WICHTIG: Der Betrieb von goMatlab.de wird privat finanziert fortgesetzt. - Mehr Infos...

Mein MATLAB Forum - goMatlab.de

Mein MATLAB Forum

 
Gast > Registrieren       Autologin?   

Partner:




Forum
      Option
[Erweitert]
  • Diese Seite per Mail weiterempfehlen
     


Gehe zu:  
Neues Thema eröffnen Neue Antwort erstellen

Verständnis guidata/callback/handles; +1 Button in GUI

 

thedom
Forum-Anfänger

Forum-Anfänger


Beiträge: 15
Anmeldedatum: 03.03.16
Wohnort: ---
Version: R2018b
     Beitrag Verfasst am: 30.09.2016, 15:20     Titel: Verständnis guidata/callback/handles; +1 Button in GUI
  Antworten mit Zitat      
Liebe Matlab-Gemeinde,

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:
Code:

function myui2
f1 = figure;

set(f1,'Name','Test-Handle-Callback');
set(f1,'units','normalized','outerposition',[0 0 1 1]);

    main_window = uipanel('Title','Test','Position',[.06 .06 .8 .8],'BackgroundColor','white','FontSize',12);
       
        pm_panel = uipanel('Parent',main_window,'Title','Plus/Minus-Calculation','Position',[.02 .02 .96 .45]);
           
            bg = uibuttongroup(pm_panel,'Position',[0.5 0.1 0.2 0.2]);
       
                p_button = uicontrol(bg,'String','plus 1','Style','pushbutton','Position',[10 20 60 20],'Callback',@plus_cb);
           
                m_button = uicontrol(bg,'String','minus 1','Style','pushbutton','Position',[100 20 60 20],'Callback',@minus_cb);
               
                    f1.pm_value = 3;
                   
                    pm_data = {'Value ' f1.pm_value};

                    pm = uitable('Parent',pm_panel,...
                    'Data',pm_data,...
                    'Position',[10 10 400 200],...
                    'CellEditCallback',@pm_value_cb);
               
               
                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
           
end
 
Private Nachricht senden Benutzer-Profile anzeigen


thedom
Themenstarter

Forum-Anfänger

Forum-Anfänger


Beiträge: 15
Anmeldedatum: 03.03.16
Wohnort: ---
Version: R2018b
     Beitrag Verfasst am: 04.10.2016, 10:21     Titel:
  Antworten mit Zitat      
Hallo liebe Leute,
Es wäre wirklich sehr hilfreich für mich wenn mir etwas zu meiner Fragestellung sagen könnte.

Liebe Grüße, Dom
Private Nachricht senden Benutzer-Profile anzeigen
 
Harald
Forum-Meister

Forum-Meister


Beiträge: 24.495
Anmeldedatum: 26.03.09
Wohnort: Nähe München
Version: ab 2017b
     Beitrag Verfasst am: 04.10.2016, 13:12     Titel:
  Antworten mit Zitat      
Hallo,

ich habe das mal so angepasst, dass der Plus-Button funktioniert.

Wenn man auf diesen klickt, soll ja der Eintrag im Table erhöht werden?
Code:
function myui2
handles.f1 = figure;

set(handles.f1,'Name','Test-Handle-Callback');
set(handles.f1,'units','normalized','outerposition',[0 0 1 1]);

handles.main_window = uipanel('Title','Test','Position',[.06 .06 .8 .8],'BackgroundColor','white','FontSize',12);

handles.pm_panel = uipanel('Parent',handles.main_window,'Title','Plus/Minus-Calculation','Position',[.02 .02 .96 .45]);

handles.bg = uibuttongroup(handles.pm_panel,'Position',[0.5 0.1 0.2 0.2]);
handles.pm_value = 3;

handles.pm_data = {'Value ' handles.pm_value};

handles.pm = uitable('Parent',handles.pm_panel,...
    'Data',handles.pm_data,...
    'Position',[10 10 400 200],...
    'CellEditCallback',@pm_value_cb);

handles.p_button = uicontrol(handles.bg,'String','plus 1','Style','pushbutton','Position',[10 20 60 20],'Callback',{@plus_cb, handles});

handles.m_button = uicontrol(handles.bg,'String','minus 1','Style','pushbutton','Position',[100 20 60 20],'Callback',@minus_cb);




    function plus_cb(plus_button, ~, handles)

        Data = get(handles.pm, 'Data');
        Data{1,2} = Data{1,2} + 1;
        set(handles.pm, 'Data', Data);
   end

end


Für den Anfang dürfte GUIDE leichter sein als die GUI mit uicontrol-Befehlen aufzubauen.

Grüße,
Harald
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 05.10.2016, 11:54     Titel: Re: Verständnis guidata/callback/handles; +1 Button in GUI
  Antworten mit Zitat      
Hallo thedom,

Zitat:
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:
Code:
FigureH = figure;
AppData = get(FigureH, 'ApplicationData')
% Oder:
AppData = FigureH.ApplicationData;  % In modernen Matlab-Versionen
% Oder:
AppData = guidata(FigureH);


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:
Code:
handles.FigureH = figure;
handles.ButtonH = uicontrol('Callback', {@myCallback, handles})

wird der Callback automatisch mit zwei zusätzlichen Inputs aufgerufen:
Code:
function myCallback(ObjectH, EventData, handles)

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:
Code:
handles.FigureH = figure;
handles.ButtonH = uicontrol('Callback', @myCallback);
guidata(handles.FigureH, handles);
% Oder:
setappdata(handles.FigureH, handles);

function myCallback(ObjectH, EventData)
% Obtain current value of "handles":
handles = guidata(ObjectH);  % Liest ApplicationData automagisch aus der *Figure*

% Oder:
FigureH = ancestor(ObjectH, 'figure');
handles = getappdata(FigureH);

handles.neuerWert = rand;
guidata(handles.FigureH, handles);  % Oder identisch: guidata(ObjectH, handles)

% Oder:
setappdata(FigureH, handles)


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.

Guß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
thedom
Themenstarter

Forum-Anfänger

Forum-Anfänger


Beiträge: 15
Anmeldedatum: 03.03.16
Wohnort: ---
Version: R2018b
     Beitrag Verfasst am: 07.10.2016, 08:16     Titel:
  Antworten mit Zitat      
Vielen Dank schonmal für eure Hilfe!! Es bringt schon viel Licht in die Sache für mich.

Dabei tun sich noch ein paar Fragen auf:

Code:
handles.FigureH = figure;
handles.ButtonH = uicontrol('Callback', @myCallback);


Warum brauche ich eigentlich eine 'handles' Struktur und wieso reicht nicht ein einfaches Handle aus:
Code:
?

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?

Zur guidata Funktion:

Code:
guidata(handles.FigureH, handles);
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?

Ist
Code:
guidata(handles.FigureH, handles);
gleichbedeutend mit
Code:
handles = guidata(handles.FigureH)
?

Es sind leider sehr viele Fragen ^^ aber ich würde es wirklich gerne genau verstehen und würde mich über jede Hilfe freuen

LG
Dom[/code]
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 07.10.2016, 10:37     Titel:
  Antworten mit Zitat      
Hallo thedom,

Zitat:
Warum brauche ich eigentlich eine 'handles' Struktur und wieso reicht nicht ein einfaches Handle aus:
Code:
?

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') .

Zitat:
Code:
guidata(handles.FigureH, handles);
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.

Zitat:
Ist
Code:
guidata(handles.FigureH, handles);
gleichbedeutend mit
Code:
handles = guidata(handles.FigureH)
?

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! Smile

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.

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
thedom
Themenstarter

Forum-Anfänger

Forum-Anfänger


Beiträge: 15
Anmeldedatum: 03.03.16
Wohnort: ---
Version: R2018b
     Beitrag Verfasst am: 10.10.2016, 13:09     Titel:
  Antworten mit Zitat      
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 Smile

LG,
Dom
Private Nachricht senden Benutzer-Profile anzeigen
 
thedom
Themenstarter

Forum-Anfänger

Forum-Anfänger


Beiträge: 15
Anmeldedatum: 03.03.16
Wohnort: ---
Version: R2018b
     Beitrag Verfasst am: 11.10.2016, 14:37     Titel:
  Antworten mit Zitat      
Hallo liebe Matlab-Kollegen,

Ich habe heute versucht das Program aus dem 2. Post:
Code:
function myui2
handles.f1 = figure;

set(handles.f1,'Name','Test-Handle-Callback');
set(handles.f1,'units','normalized','outerposition',[0 0 1 1]);

handles.main_window = uipanel('Title','Test','Position',[.06 .06 .8 .8],'BackgroundColor','white','FontSize',12);

handles.pm_panel = uipanel('Parent',handles.main_window,'Title','Plus/Minus-Calculation','Position',[.02 .02 .96 .45]);

handles.bg = uibuttongroup(handles.pm_panel,'Position',[0.5 0.1 0.2 0.2]);
handles.pm_value = 3;

handles.pm_data = {'Value ' handles.pm_value};

handles.pm = uitable('Parent',handles.pm_panel,...
    'Data',handles.pm_data,...
    'Position',[10 10 400 200],...
    'CellEditCallback',@pm_value_cb);

handles.p_button = uicontrol(handles.bg,'String','plus 1','Style','pushbutton','Position',[10 20 60 20],'Callback',{@plus_cb, handles});

handles.m_button = uicontrol(handles.bg,'String','minus 1','Style','pushbutton','Position',[100 20 60 20],'Callback',@minus_cb);




    function plus_cb(plus_button, ~, handles)

        Data = get(handles.pm, 'Data');
        Data{1,2} = Data{1,2} + 1;
        set(handles.pm, 'Data', Data);
   end

end


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?

LG,Dom
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 12.10.2016, 13:16     Titel:
  Antworten mit Zitat      
Hallo thedom,

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.

Code:
function myui2
handles.f1 = figure;
...
handles.p_button = uicontrol(handles.bg,'String','plus 1', 'Style','pushbutton', ...
              'Position',[10 20 60 20],'Callback', @plus_cb);
...
guidata(handles.f1, handles);  % handles speichern
end

function plus_cb(plus_button, ~)
handles = guidata(plus_button);  % handles auslesen

Data = get(handles.pm, 'Data');
Data{1,2} = Data{1,2} + 1;
set(handles.pm, 'Data', Data);

% 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

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
Neues Thema eröffnen Neue Antwort erstellen



Einstellungen und Berechtigungen
Beiträge der letzten Zeit anzeigen:

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
.





 Impressum  | Nutzungsbedingungen  | Datenschutz | FAQ | goMatlab RSS Button RSS

Hosted by:


Copyright © 2007 - 2024 goMatlab.de | Dies ist keine offizielle Website der Firma The Mathworks

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.