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 dazu setappdata / 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 / oder set/getappdata nicht implementieren zu set/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 die data 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:

  1. 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).
  2. Führen Sie das Skript aus.
  3. Klicken Sie auf Berechnen und kurz darauf entweder auf Pause 1 oder auf Pause 2 .
  4. superSecretVar Sie sicher, dass Sie den Wert von superSecretVar .

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.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow