MATLAB Language
MATLAB-Benutzeroberflächen
Suche…
Weitergabe von Daten an die Benutzeroberfläche
Die meisten fortgeschrittenen Benutzeroberflächen erfordern, dass der Benutzer Informationen zwischen den verschiedenen Funktionen, die eine Benutzeroberfläche bilden, weiterleiten kann. MATLAB verfügt über verschiedene Methoden, um dies zu tun.
guidata
MATLABs eigene GUI Development Environment (GUIDE) bevorzugt die Verwendung einer struct
namens handles
, um Daten zwischen Callbacks zu übergeben. Diese struct
enthält alle Grafik-Handles für die verschiedenen UI-Komponenten sowie vom Benutzer angegebene Daten. Wenn Sie keinen von GUIDE erstellten Rückruf verwenden, der handles
automatisch übergibt, können Sie den aktuellen Wert mithilfe von guidata
% hObject is a graphics handle to any UI component in your GUI
handles = guidata(hObject);
Wenn Sie einen Wert ändern möchten, der in dieser Datenstruktur gespeichert ist, können Sie ihn ändern. Sie müssen ihn jedoch wieder im hObject
speichern, damit die Änderungen für andere Rückrufe sichtbar sind. Sie können es speichern, indem Sie ein zweites Eingabeargument für guidata
.
% Update the value
handles.myValue = 2;
% Save changes
guidata(hObject, handles)
Der Wert von hObject
spielt keine Rolle, solange es sich um eine UI-Komponente innerhalb derselben figure
da die Daten letztendlich in der Figur gespeichert werden, die hObject
.
Beste für:
- Speichern der
handles
Struktur, in der Sie alle Handles Ihrer GUI-Komponenten speichern können. - Speichern "kleiner" anderer Variablen, auf die die meisten Callbacks zugreifen müssen.
Nicht empfohlen für :
- Speichern großer Variablen, auf die nicht alle Callbacks und Unterfunktionen
setappdata
müssen (verwenden Sie dazusetappdata
/getappdata
).
setappdata
/ getappdata
Ähnlich wie beim guidata
Ansatz können Sie setappdata
und getappdata
, um Werte innerhalb eines Grafik- getappdata
zu speichern und abzurufen. Der Vorteil der Verwendung dieser Methoden besteht darin, dass Sie nur den gewünschten Wert abrufen können, anstatt eine ganze struct
mit allen gespeicherten Daten. Es ähnelt einem Schlüssel- / Wertspeicher.
Um Daten innerhalb eines Grafikobjekts zu speichern
% Create some data you would like to store
myvalue = 2
% Store it using the key 'mykey'
setappdata(hObject, 'mykey', myvalue)
Und denselben Wert aus einem anderen Rückruf abrufen
value = getappdata(hObject, 'mykey');
Hinweis: Wenn vor dem Aufruf von getappdata
kein Wert gespeichert wurde, wird ein leeres Array ( []
) zurückgegeben.
Ähnlich wie bei guidata
werden die Daten in der Figur gespeichert, die hObject
enthält.
Beste für:
- Speichern großer Variablen, auf die nicht alle Callbacks und Unterfunktionen zugreifen müssen.
UserData
Jedes Grafik-Handle hat eine spezielle Eigenschaft, UserData
die beliebige Daten enthalten kann. Es könnte ein Zellenfeld, eine struct
oder sogar einen Skalar enthalten. Sie können diese Eigenschaft nutzen und in diesem Feld alle Daten speichern, die Sie einem bestimmten Grafik-Handle zuordnen möchten. Sie können den Wert speichern und abrufen, indem Sie die Standardmethode get
/ set
für Grafikobjekte oder Punktnotation verwenden, wenn Sie R2014b oder neuer verwenden.
% Create some data to store
mydata = {1, 2, 3};
% Store it within the UserData property
set(hObject, 'UserData', mydata)
% Of if you're using R2014b or newer:
% hObject.UserData = mydata;
Dann können Sie aus einem anderen Rückruf diese Daten abrufen:
their_data = get(hObject, 'UserData');
% Or if you're using R2014b or newer:
% their_data = hObject.UserData;
Beste für:
- Speichern von Variablen mit begrenztem Umfang (Variablen, die wahrscheinlich nur von dem Objekt verwendet werden, in dem sie gespeichert sind, oder Objekten, die eine direkte Beziehung dazu haben).
Verschachtelte Funktionen
In MATLAB kann eine verschachtelte Funktion jede in der übergeordneten Funktion definierte Variable lesen und ändern. Wenn Sie einen Rückruf als verschachtelte Funktion angeben, können auf diese Weise alle in der Hauptfunktion gespeicherten Daten abgerufen und geändert werden.
function mygui()
hButton = uicontrol('String', 'Click Me', 'Callback', @callback);
% Create a counter to keep track of the number of times the button is clicked
nClicks = 0;
% Callback function is nested and can therefore read and modify nClicks
function callback(source, event)
% Increment the number of clicks
nClicks = nClicks + 1;
% Print the number of clicks so far
fprintf('Number of clicks: %d\n', nClicks);
end
end
Beste für:
- Kleine, einfache GUIs. (für schnelles Prototyping, um die Methoden
guidata
und / oderset/getappdata
nicht implementieren zuset/getappdata
).
Nicht empfohlen für :
Mittlere, große oder komplexe GUIs.
GUI erstellt mit
GUIDE
.
Explizite Eingabeargumente
Wenn Sie Daten an eine Rückruffunktion senden und die Daten innerhalb des Rückrufs nicht ändern müssen, können Sie die Daten immer mit einer sorgfältig erstellten Rückrufdefinition an den Rückruf übergeben.
Sie können eine anonyme Funktion verwenden, die Eingaben hinzufügt
% Create some data to send to mycallback
data = [1, 2, 3];
% Pass data as a third input to mycallback
set(hObject, 'Callback', @(source, event)mycallback(source, event, data))
Oder Sie können die Zellenarray-Syntax verwenden, um einen Rückruf anzugeben, wobei wiederum weitere Eingaben angegeben werden.
set(hObject, 'Callback', {@mycallback, data})
Beste für:
- Wenn der Rückruf benötigt
data
, einige Operationen durchführen , aber diedata
braucht nicht in einem neuen Zustand geändert und gespeichert werden.
Erstellen einer Schaltfläche in Ihrer Benutzeroberfläche, die die Ausführung des Rückrufs anhält
Manchmal möchten wir die Codeausführung anhalten, um den Status der Anwendung zu überprüfen (siehe Debugging ). Wenn Sie Code über den MATLAB-Editor ausführen, können Sie dies über die Schaltfläche "Pause" in der Benutzeroberfläche oder durch Drücken von Strg + c (unter Windows) tun. Wenn jedoch eine Berechnung über eine GUI initiiert wurde (über den Rückruf eines bestimmten uicontrol
), funktioniert diese Methode nicht mehr, und der Rückruf sollte durch einen anderen Rückruf unterbrochen werden. Im Folgenden wird dieses Prinzip demonstriert:
function interruptibleUI
dbclear in interruptibleUI % reset breakpoints in this file
figure('Position',[400,500,329,160]);
uicontrol('Style', 'pushbutton',...
'String', 'Compute',...
'Position', [24 55 131 63],...
'Callback', @longComputation,...
'Interruptible','on'); % 'on' by default anyway
uicontrol('Style', 'pushbutton',...
'String', 'Pause #1',...
'Position', [180 87 131 63],...
'Callback', @interrupt1);
uicontrol('Style', 'pushbutton',...
'String', 'Pause #2',...
'Position', [180 12 131 63],...
'Callback', @interrupt2);
end
function longComputation(src,event)
superSecretVar = rand(1);
pause(15);
print('done!'); % we'll use this to determine if code kept running "in the background".
end
function interrupt1(src,event) % depending on where you want to stop
dbstop in interruptibleUI at 27 % will stop after print('done!');
dbstop in interruptibleUI at 32 % will stop after **this** line.
end
function interrupt2(src,event) % method 2
keyboard;
dbup; % this will need to be executed manually once the code stops on the previous line.
end
Um sicherzustellen, dass Sie dieses Beispiel verstehen, gehen Sie folgendermaßen vor:
- Fügen Sie den obigen Code in eine neue Datei ein und speichern Sie sie als
interruptibleUI.m
, sodass der Code in der ersten Zeile der Datei beginnt (dies ist für die erste Methode wichtig). - Führen Sie das Skript aus.
- Klicken Sie auf Berechnen und kurz darauf entweder auf Pause 1 oder auf Pause 2 .
-
superSecretVar
Sie sicher, dass Sie den Wert vonsuperSecretVar
.
Weitergeben von Daten mithilfe der Struktur "Handles"
Dies ist ein Beispiel eines grundlegenden GUI mit zwei Tasten , die einen Wert in der GUI gespeichert ändern handles
Struktur.
function gui_passing_data()
% A basic GUI with two buttons to show a simple use of the 'handles'
% structure in GUI building
% Create a new figure.
f = figure();
% Retrieve the handles structure
handles = guidata(f);
% Store the figure handle
handles.figure = f;
% Create an edit box and two buttons (plus and minus),
% and store their handles for future use
handles.hedit = uicontrol('Style','edit','Position',[10,200,60,20] , 'Enable', 'Inactive');
handles.hbutton_plus = uicontrol('Style','pushbutton','String','+',...
'Position',[80,200,60,20] , 'Callback' , @ButtonPress);
handles.hbutton_minus = uicontrol('Style','pushbutton','String','-',...
'Position',[150,200,60,20] , 'Callback' , @ButtonPress);
% Define an initial value, store it in the handles structure and show
% it in the Edit box
handles.value = 1;
set(handles.hedit , 'String' , num2str(handles.value))
% Store handles
guidata(f, handles);
function ButtonPress(hObject, eventdata)
% A button was pressed
% Retrieve the handles
handles = guidata(hObject);
% Determine which button was pressed; hObject is the calling object
switch(get(hObject , 'String'))
case '+'
% Add 1 to the value
handles.value = handles.value + 1;
set(handles.hedit , 'String', num2str(handles.value))
case '-'
% Substract 1 from the value
handles.value = handles.value - 1;
end
% Display the new value
set(handles.hedit , 'String', num2str(handles.value))
% Store handles
guidata(hObject, handles);
Um das Beispiel zu testen, speichern Sie es in einer Datei namens gui_passing_data.m
und starten Sie es mit F5. Beachten Sie, dass Sie in einem solchen einfachen Fall den Wert nicht einmal in der Handles-Struktur speichern müssen, da Sie über die String
Eigenschaft des Bearbeitungsfelds direkt darauf zugreifen können.
Leistungsprobleme beim Übergeben von Daten an der Benutzeroberfläche
Zwei Haupttechniken ermöglichen die Übergabe von Daten zwischen GUI-Funktionen und Callbacks: setappdata / getappdata und guidata ( lesen Sie mehr darüber ). Ersteres sollte für größere Variablen verwendet werden, da es zeitsparender ist. Im folgenden Beispiel wird die Effizienz der beiden Methoden getestet.
Eine GUI mit einer einfachen Schaltfläche wird erstellt und eine große Variable (10000x10000 double) wird sowohl mit guidata als auch mit setappdata gespeichert. Die Schaltfläche lädt die Variable mit den beiden Methoden neu und speichert sie zurück, während ihre Ausführung zeitlich gesteuert wird. Die Laufzeit und die prozentuale Verbesserung mit setappdata werden im Befehlsfenster angezeigt.
function gui_passing_data_performance()
% A basic GUI with a button to show performance difference between
% guidata and setappdata
% Create a new figure.
f = figure('Units' , 'normalized');
% Retrieve the handles structure
handles = guidata(f);
% Store the figure handle
handles.figure = f;
handles.hbutton = uicontrol('Style','pushbutton','String','Calculate','units','normalized',...
'Position',[0.4 , 0.45 , 0.2 , 0.1] , 'Callback' , @ButtonPress);
% Create an uninteresting large array
data = zeros(10000);
% Store it in appdata
setappdata(handles.figure , 'data' , data);
% Store it in handles
handles.data = data;
% Save handles
guidata(f, handles);
function ButtonPress(hObject, eventdata)
% Calculate the time difference when using guidata and appdata
t_handles = timeit(@use_handles);
t_appdata = timeit(@use_appdata);
% Absolute and percentage difference
t_diff = t_handles - t_appdata;
t_perc = round(t_diff / t_handles * 100);
disp(['Difference: ' num2str(t_diff) ' ms / ' num2str(t_perc) ' %'])
function use_appdata()
% Retrieve the data from appdata
data = getappdata(gcf , 'data');
% Do something with data %
% Store the value again
setappdata(gcf , 'data' , data);
function use_handles()
% Retrieve the data from handles
handles = guidata(gcf);
data = handles.data;
% Do something with data %
% Store it back in the handles
handles.data = data;
guidata(gcf, handles);
Auf meinem Xeon [email protected] GHz erhalte ich Difference: 0.00018957 ms / 73 %
, daher bekomme ich mit getappdata / setappdata eine Leistungsverbesserung von 73%! Beachten Sie, dass sich das Ergebnis nicht ändert, wenn eine 10x10-Doppelvariable verwendet wird. Das Ergebnis ändert sich jedoch, wenn handles
viele Felder mit großen Daten enthalten.