Ricerca…


Passaggio dei dati intorno all'interfaccia utente

Le interfacce utente più avanzate richiedono all'utente di essere in grado di passare informazioni tra le varie funzioni che costituiscono un'interfaccia utente. MATLAB ha un numero di metodi diversi per farlo.


guidata

L' ambiente di sviluppo GUI della MATLAB preferisce utilizzare una struct denominata handles per passare i dati tra i callback. Questa struct contiene tutti gli handle grafici per i vari componenti dell'interfaccia utente, nonché i dati specificati dall'utente. Se non si utilizza un callback creato da GUIDE che passa automaticamente gli handles , è possibile recuperare il valore corrente utilizzando guidata

% hObject is a graphics handle to any UI component in your GUI
handles = guidata(hObject);

Se si desidera modificare un valore archiviato in questa struttura dati, è possibile modificarlo, ma è necessario memorizzarlo nuovamente all'interno di hObject affinché le modifiche siano visibili da altri callback. È possibile memorizzarlo specificando un secondo argomento di input per guidata .

% Update the value
handles.myValue = 2;

% Save changes
guidata(hObject, handles)

Il valore di hObject non ha importanza fintanto che si tratta di un componente dell'interfaccia utente all'interno della stessa figure poiché, in definitiva, i dati vengono archiviati nella figura che contiene hObject .

Meglio per:

  • Memorizzazione della struttura delle handles , in cui è possibile memorizzare tutti gli handle dei componenti della GUI.
  • Memorizzazione di "piccole" altre variabili a cui è necessario accedere tramite la maggior parte delle richiamate.

Non consigliato per :

  • Memorizzazione di variabili di grandi dimensioni a cui non è necessario accedere con tutte le richiamate e le setappdata (utilizzare setappdata / getappdata per queste).

setappdata / getappdata

Simile al guidata approccio, è possibile utilizzare setappdata e getappdata per memorizzare e recuperare i valori all'interno di gestire una grafica. Il vantaggio dell'utilizzo di questi metodi è che è possibile recuperare solo il valore desiderato anziché un'intera struct contenente tutti i dati memorizzati. È simile a un archivio di chiavi / valori.

Per memorizzare i dati all'interno di un oggetto grafico

% Create some data you would like to store
myvalue = 2

% Store it using the key 'mykey'
setappdata(hObject, 'mykey', myvalue)

E per recuperare lo stesso valore da un callback differente

value = getappdata(hObject, 'mykey');

Nota: se non è stato memorizzato alcun valore prima di chiamare getappdata , verrà restituito un array vuoto ( [] ).

Simile a guidata , i dati sono memorizzati nella figura che contiene hObject .

Meglio per:

  • Memorizzazione di variabili di grandi dimensioni a cui non è necessario accedere con tutte le richiamate e le sottofunzioni.

UserData

Ogni handle grafico ha una proprietà speciale, UserData che può contenere tutti i dati che desideri. Potrebbe contenere un array di celle, una struct o anche uno scalare. È possibile usufruire di questa proprietà e memorizzare in questo campo tutti i dati che si desidera associare a un determinato elemento grafico. È possibile salvare e recuperare il valore utilizzando i metodi get / set standard per gli oggetti grafici o la notazione dei punti se si utilizza R2014b o più recente.

% 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;

Quindi dall'interno di un altro callback, è possibile recuperare questi dati:

their_data = get(hObject, 'UserData');

% Or if you're using R2014b or newer:
% their_data = hObject.UserData;

Meglio per:

  • Memorizzazione di variabili con un ambito limitato (variabili che possono essere utilizzate solo dall'oggetto in cui sono memorizzate o oggetti che hanno una relazione diretta con esso).

Funzioni annidate

In MATLAB, una funzione nidificata può leggere e modificare qualsiasi variabile definita nella funzione genitore. In questo modo, se si specifica una richiamata come funzione nidificata, è possibile recuperare e modificare qualsiasi dato memorizzato nella funzione principale.

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

Meglio per:

  • GUI piccole e semplici. (per la prototipazione rapida, per non dover implementare i metodi guidata e / o set/getappdata ).

Non consigliato per :

  • GUI di media, grande o complessa.

  • GUI creata con GUIDE .


Argomenti di input espliciti

Se è necessario inviare dati a una funzione di callback e non è necessario modificare i dati all'interno del callback, è sempre possibile considerare di trasferire i dati al callback utilizzando una definizione callback accuratamente predisposta.

Potresti usare una funzione anonima che aggiunge input

% 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))

In alternativa, è possibile utilizzare la sintassi dell'array di celle per specificare un callback, specificando nuovamente input aggiuntivi.

set(hObject, 'Callback', {@mycallback, data})

Meglio per:

  • Quando il callback necessita di data per eseguire alcune operazioni, la variabile di data non deve essere modificata e salvata in un nuovo stato.

Creazione di un pulsante nell'interfaccia utente che sospende l'esecuzione di callback

A volte vorremmo mettere in pausa l'esecuzione del codice per ispezionare lo stato dell'applicazione (vedere Debug ). Quando si esegue il codice tramite l'editor MATLAB, è possibile farlo utilizzando il pulsante "Pausa" nell'interfaccia utente o premendo Ctrl + c (su Windows). Tuttavia, quando un calcolo è stato avviato da una GUI (tramite il callback di alcuni uicontrol ), questo metodo non funziona più e il callback deve essere interrotto tramite un altro callback. Di seguito è una dimostrazione di questo principio:

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

Per assicurarti di aver compreso questo esempio, procedi nel seguente modo:

  1. Incolla il codice sopra in un nuovo file chiamato e salvalo come interruptibleUI.m , in modo tale che il codice inizi sulla prima riga del file (questo è importante perché il 1 ° metodo funzioni).
  2. Esegui lo script.
  3. Fai clic su Calcola e, poco dopo, fai clic su Pausa n. 1 o Pausa n . 2 .
  4. Assicurati di poter trovare il valore di superSecretVar .

Trasmettere dati in giro usando la struttura "maniglie"

Questo è un esempio di una GUI di base con due pulsanti che modificano un valore memorizzato nella struttura degli handles della GUI.

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);

Per testare l'esempio, salvarlo in un file chiamato gui_passing_data.m e lanciarlo con F5. Si noti che in un caso così semplice, non è nemmeno necessario memorizzare il valore nella struttura degli handle perché è possibile accedervi direttamente dalla proprietà String della casella di modifica.

Problemi di prestazioni quando si passano dati intorno all'interfaccia utente

Due tecniche principali consentono il passaggio dei dati tra le funzioni della GUI e le callback: setappdata / getappdata e guidata ( leggi di più a riguardo ). Il primo dovrebbe essere usato per variabili più grandi in quanto è più efficiente nel tempo. L'esempio seguente verifica l'efficienza dei due metodi.

Viene creata una GUI con un semplice pulsante e una grande variabile (10000x10000 double) viene memorizzata sia con guidata che con setappdata. Il pulsante ricarica e memorizza la variabile utilizzando i due metodi durante il tempo della loro esecuzione. Il tempo di esecuzione e il miglioramento percentuale usando setappdata vengono visualizzati nella finestra di comando.

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);

Sulla mia Xeon W3530@2,80 GHz ho Difference: 0.00018957 ms / 73 % , quindi usando getappdata / setappdata ottengo un miglioramento delle prestazioni del 73%! Si noti che il risultato non cambia se viene utilizzata una variabile doppia 10x10, tuttavia, il risultato cambierà se gli handles contengono molti campi con dati di grandi dimensioni.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow