Ich bin gerade dabei mich in das Thema callback in GUIs einzuarbeiten und habe mich an einem Beispiel versucht in dem ich eine Zahl in einer Tabelle mit dem Drücken eines pushbuttons um +1 erhöhen möchte.
Leider funktioniert das noch nicht und ich kommen nicht weiter damit.
Mittlerweile habe ich es so verstanden, dass ich die Variable für den Wert der in der tabelle angezeigt wird und der beim Drücken erhöht werden soll, in der guidata speichern soll weil dann alle grafischen elemente darauf zugreifen können, ist das korrekt?
Dann habe ich verstanden, dass ich noch eine callback Funktion brauche die beim Button-Drücken aufgerufen wird und welche die Variable aus der guidata ausliest, sie verändert (um eins erhöht) und dann die variable wieder in die guidata speichert. stimmt das so ca?
Weiters lese ich noch sehr häufig den Begriff 'handles' kann aber noch nicht wirklich etwas damit anfangen? Was machen diese handles? Hat jedes Grafikelement eigene handels? Kann ich darin auch etwas speichern so wie in guidata?
Ich freu mich schon auf eure Antworten und bedanke mich schonmal im Vorraus für die Hilfe
Hier ist noch der code von meinen Programm welches noch nicht funktioniert:
function pm_value_cb(pm_table, handle)
handle.value1 = 5;
% At THIS point, "handles" is just a copy of guidata for the GUI
handle.value1 = handle.value1 + 1;
% At THIS point, "handles" is different to the guidata for the GUI guidata(pm_table, handle);
% At THIS point, "handles" has been put back in as new guidata for the GUI end
Leider funktioniert das noch nicht und ich kommen nicht weiter damit.
Wann immer man im Forum "funktioniert nicht" schreibt, ist es sinnvoll, das Verhalten und das gewünschte Verhalten zu beschreiben. Ohne weitere Erklärungen kann man kaum darauf antworten.
Zitat:
Mittlerweile habe ich es so verstanden, dass ich die Variable für den Wert der in der tabelle angezeigt wird und der beim Drücken erhöht werden soll, in der guidata speichern soll weil dann alle grafischen elemente darauf zugreifen können, ist das korrekt?
guidata
ist ein Befehl. Darin kann man also nichts speichern. "handles" ist ein tückischer Begriff, denn leider wird er in vielen Beispielen als Variable verwendet, in der unter anderem auch Handles gespeichert werden. Das ist aber eher verwirrend als aussagekräftig.
Jedes Grafik-Objekt besitzt einen Handle, über das es angesprochen, also "adressiert" werden kann, z.B. für den
SET
Befehl. Wenn man ein
uicontrol
erstellt, wird der Handle zurück gegeben, damit man später einfach darauf zugreifen kann.
In jedem grafischen Element (Buttons, Menüs, AXES etc.) kann man eine Variable namens 'UserData' speichern und in nicht-historischen Matlab-Versionen eine zweite namens 'ApplicationData'. Welche man lieber mag, ist Geschmackssache. Für letztere gibt es den Befehl
guidata
, man kann aber auch direkt per
setappdata
und
getappdata
darauf zugreifen. Eine weitere Möglichkeit wäre:
Wenn man Daten zwischen Callback-Funktionen austauschen möchte, speichert man sie entweder in den Application- oder UserData der Figure oder eines Buttons (etc.), jenachdem, wo die Daten am ehesten hingehören.
Wenn man einen Callback beim Erstellen der Figure definiert:
Hier gibt es nun ein Problem: Die Variable "handles" hat beim Aufruf des Callbacks den Wert, den sie bei der Erstellung des Callbacks hatte. Hier existiert z.B. das Feld "handles.ButtonH" noch gar nicht! Darum ist das Mitführen des handles-Structs in den Inputs der Callbacks meiner Meinung nach vollkommen verwirrend und führt Anfänger immer wieder in die Irre, wenn sie mit GUIDE-produziertem Code arbeiten. Ich selbst habe den Überblick verloren, wann der "handles" Struct in GUIDE auf den aktuellen Stand gesetzt wird und wann nicht. Darum empfehle ich, das immer manuell zu tun:
function myCallback(ObjectH, EventData) % Obtain current value of "handles":
handles = guidata(ObjectH); % Liest ApplicationData automagisch aus der *Figure*
Das gleiche geht auch mit den UserData. Es ist wichtig, nach jeder Änderung des Inhalts des "handles" structs diesen auch wieder in der Figure zu speichern, sonst gehen für den nächsten Callback die Änderungen verloren. Darum könnte man es sich zur Angewohnheit machen, jeden Callback mit "handles=guidata(ObjectH)" zu beginnen und mit "guidata(ObjectH, handles)" zu beenden. Und wenn man dann noch statt "handles" einen passenden Namen wählt wie "CallbackData" oder "FigureData", wird die Verwirrung etwas kleiner.
Darf ich den Namen für die Handle-Struktur frei wählen, z.B. anstatt 'handles.FigureH', 'adresse.figure1'?
Bei der erstellung der Callback-Funktion:
Code:
function myCallback(ObjectH, EventData) % Obtain current value of "handles":
handles = guidata(ObjectH); % Liest ApplicationData automagisch aus der *Figure*
Übergebe ich an die Funktion also die Variablen 'ObjectH' und 'EventData'. Diese Variablen wurden vorher im Skript nirgends definiert - sind das also Standart-Variablen welche ich bei jeder Callback Funktion übergeben muss? Kann ich die Namen ändern von ObjectH und EventData? Bezieht sich ObjectH automatisch immer auf meine Figure in welcher ich mich aktuell befinde?
speichert mir also die Variable 'handles' mit Hilfe der 'guidata' Funktion in die 'ApplicationData' der Figure welche mit dem Handle 'handles.FigureH' adressiert wird? Hab ich das richtig verstanden? Könnte ich hier auch anstatt 'handles' eine andere Bezeichung wählen?
Die Handles in einem Struct zu speichern hat den Vorteil, dass man sie so einfach in einer Variablen an alle Unterfunktionen weiter geben kann. Das kann man aber theoretisch auch ohne Struct machen.
Zitat:
Darf ich den Namen für die Handle-Struktur frei wählen, z.B. anstatt 'handles.FigureH', 'adresse.figure1'?
Ja, der Name "handles" ist meiner Ansicht nach irreführend, denn man kann darin auch sehr gut aktuelle Nutzerdaten speichern, z.B. den zuletzt ausgewählten Ordner. Daher mein Vorschlag es "GUIData" zu nennen, was dann ja auch dem Befehl "guidata" ziemlich nahe kommt.
Zitat:
Bei der erstellung der Callback-Funktion:
Übergebe ich an die Funktion also die Variablen 'ObjectH' und 'EventData'. Diese Variablen wurden vorher im Skript nirgends definiert - sind das also Standart-Variablen welche ich bei jeder Callback Funktion übergeben muss?
Richtig. Jeder Callback bekommt automatisch als 1. Input das auslösende Object und als 2. einen Struct mit Daten, die das Event beschreiben, bei einem Maus-Click z.B. welche Taste gedrückt ist, bei einem Keyboard-Event, welcher Buchstabe, bei einem Table-Event, welche Table-Zelle ausgewählt ist etc.
Zitat:
Kann ich die Namen ändern von ObjectH und EventData?
Die Namen von Variablen sind grundsätzlich immer variable. GUIDE verwendet z.B. "hObject". Es lohnt sich, sich ein festes Names-Schema zuzulegen und es in allen Codes beizubehalten. So kann man alle Handles mit "h..." benennen, alle Anzahlen mit "n...", alle Logicals mit "is..." oder "do..." jenachdem, was ein Logical auslösen soll. Das ist aber im Endeffekt Geschmackssache, erleichtert aber die Code-Wartung sehr.
Zitat:
Bezieht sich ObjectH automatisch immer auf meine Figure in welcher ich mich aktuell befinde?
Nein. ObjectH ist (wie oben gesagt) das Objekt, welches das event ausgelöst hat. Beim Drücken eines Buttons ist es der Handle des Buttons. Wenn man ein Fenster mit die "x" im Rahmen schließt, wird der "CloseRequestFcn"-Callback aufgerufen und ObjectH ist der Handle des Fensters.
Um sicher an den Fenster-Handle zu kommen dient
ancestor(ObjectH, 'figure')
.
speichert mir also die Variable 'handles' mit Hilfe der 'guidata' Funktion in die 'ApplicationData' der Figure welche mit dem Handle 'handles.FigureH' adressiert wird? Hab ich das richtig verstanden?
Ja.
Zitat:
Könnte ich hier auch anstatt 'handles' eine andere Bezeichung wählen?
Ja. Das kannst Du übrigens ja einfach ausprobieren in Matlab.
Nein. Ersteres schreibt den Struct "handles" in die ApplicationData, zweiteres liest die ApplicationData und schreibt sie in den Struct "handles".
Fragen sind hier im Forum immer erwünscht, denn das ist ja der Sinn des Forums!
Oft ist es schneller, es einfach in Matlab auszuprobieren. Wenn man mit dem Debugger Zeile für Zeile durch den Code geht, kann man sich genau anschauen, was passiert und sich im CommandWindow oder WorkspaceBrowser die aktuellen Inhalte der Variablen anschauen.
Vielen Dank für die Hilfe! Das hat mich schon sehr viel weiter gebracht!
Ich werde mich jetzt mal damit weiter beschäftigen und versuchen das zu verinnerlichen und dann werde ich mich wieder melden wenn weitere Fragen aufkommen
so umzuschreiben, dass es in der callback funktion die guidata funktion benutzt anstatt der set/get-funktionen. Leider scheitere ich noch daran. Könnte mir villeicht jemand zeigen wie ich das bewerkstellige?
Die Lösung findest Du in meinem Post vom 05.10.2016, 12:54. Hier verwendest Du jetzt allerdings eine eingebettete Funktion, die wiederum die Variablen der Funktion verwenden kann. Das erhöht den Verwirrungsgrad noch mal. Wenn Dir das Programmieren aber sowieso schon schwer fällt, rate ich auf solche Tricks erstmal zu verzichten.
% Da "handles" nicht geändert wurde, gibt es keinen Grund das hier wieder zu speichern. % Aber der vollständigkeit halber: guidata(handles.f1, handles);
end
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.