Zoeken…


Gegevens doorgeven aan de gebruikersinterface

De meeste geavanceerde gebruikersinterfaces vereisen dat de gebruiker informatie kan doorgeven tussen de verschillende functies waaruit een gebruikersinterface bestaat. MATLAB heeft een aantal verschillende methoden om dit te doen.


guidata

MATLAB's eigen GUI Development Environment (GUIDE) geeft er de voorkeur aan om een struct genaamd handles te gebruiken om data tussen callbacks door te geven. Deze struct bevat alle grafische handvatten voor de verschillende UI-componenten, evenals door de gebruiker opgegeven gegevens. Als u geen door GUIDE gemaakte callback gebruikt die automatisch handles doorgeeft, kunt u de huidige waarde ophalen met behulp van guidata

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

Als u een waarde wilt wijzigen die is opgeslagen in deze gegevensstructuur, kunt u deze wijzigen, maar dan moet u deze opnieuw opslaan in het hObject om de wijzigingen zichtbaar te maken voor andere callbacks. U kunt het opslaan door een tweede guidata voor guidata te guidata .

% Update the value
handles.myValue = 2;

% Save changes
guidata(hObject, handles)

De waarde van hObject doet er niet toe, zolang het een UI-component binnen hetzelfde figure omdat de gegevens uiteindelijk worden opgeslagen in de figuur die hObject .

Best voor:

  • De handles opslaan, waarin u alle handvatten van uw GUI-componenten kunt opslaan.
  • "Kleine" andere variabelen opslaan waartoe de meeste callbacks toegang moeten hebben.

Niet aanbevolen voor :

  • Grote variabelen opslaan die niet door alle callbacks en subfuncties moeten worden benaderd (gebruik hiervoor setappdata / getappdata ).

setappdata / getappdata

Net als bij de guidata benadering, kunt u setappdata en getappdata gebruiken om waarden op te slaan en op te halen vanuit een grafische handle. Het voordeel van het gebruik van deze methoden is dat u alleen de gewenste waarde kunt ophalen in plaats van een volledige struct met alle opgeslagen gegevens. Het is vergelijkbaar met een sleutel / waardeopslag.

Gegevens opslaan in een grafisch object

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

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

En om dezelfde waarde op te halen vanuit een andere callback

value = getappdata(hObject, 'mykey');

Opmerking: als er geen waarde is opgeslagen voordat getappdata wordt getappdata , retourneert deze een lege array ( [] ).

Net als guidata worden de gegevens opgeslagen in de figuur die hObject bevat.

Best voor:

  • Grote variabelen opslaan die niet voor alle callbacks en subfuncties toegankelijk zijn.

UserData

Elke grafische handle heeft een speciale eigenschap, UserData die elke gewenste data kan bevatten. Het kan een celarray, een struct of zelfs een scalair bevatten. U kunt profiteren van deze eigenschap en alle gegevens opslaan die u aan een bepaalde grafische handle in dit veld wilt koppelen. U kunt de waarde opslaan en ophalen met de standaard get / set methoden voor grafische objecten of puntnotatie als u R2014b of nieuwer gebruikt.

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

Vervolgens kunt u vanuit een andere callback deze gegevens ophalen:

their_data = get(hObject, 'UserData');

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

Best voor:

  • Variabelen opslaan met een beperkt bereik (variabelen die waarschijnlijk alleen worden gebruikt door het object waarin ze zijn opgeslagen, of objecten die er een directe relatie mee hebben).

Geneste functies

In MATLAB kan een geneste functie elke variabele in de bovenliggende functie lezen en wijzigen. Op deze manier, als u een callback opgeeft als een geneste functie, kan deze alle gegevens ophalen en wijzigen die zijn opgeslagen in de hoofdfunctie.

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

Best voor:

  • Kleine, eenvoudige GUI's. (voor snelle prototyping, om de guidata en / of set/getappdata methoden niet te hoeven implementeren).

Niet aanbevolen voor :

  • Middelgrote, grote of complexe GUI's.

  • GUI gemaakt met GUIDE .


Expliciete invoerargumenten

Als u gegevens naar een terugbelfunctie moet verzenden en de gegevens binnen de terugbelaanvraag niet hoeft te wijzigen, kunt u altijd overwegen om de gegevens aan de terugbelverzoek door te geven met behulp van een zorgvuldig gemaakte terugbeldefinitie.

U kunt een anonieme functie gebruiken die invoer toevoegt

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

Of u kunt de syntaxis van de celarray gebruiken om een callback op te geven, waarbij u opnieuw extra invoer opgeeft.

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

Best voor:

  • Wanneer de callback data nodig heeft om bepaalde bewerkingen uit te voeren, maar de data niet hoeft te worden gewijzigd en in een nieuwe status te worden opgeslagen.

Een knop maken in uw gebruikersinterface waarmee de uitvoering van terugbellen wordt onderbroken

Soms willen we de uitvoering van de code onderbreken om de status van de toepassing te inspecteren (zie Foutopsporing ). Wanneer u code uitvoert via de MATLAB-editor, kunt u dit doen met de knop "Pauzeren" in de gebruikersinterface of door op Ctrl + c te drukken (in Windows). Toen echter een berekening werd gestart vanuit een GUI (via de terugbelactie van een of andere uicontrol ), werkt deze methode niet meer en moet de terugbelverzoek worden onderbroken via een andere terugbelverzoek. Hieronder is een demonstratie van dit principe:

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

Om ervoor te zorgen dat u dit voorbeeld begrijpt, doet u het volgende:

  1. Plak de bovenstaande code in een nieuw bestand met de naam en sla het op als interruptibleUI.m , zodat de code begint op de allereerste regel van het bestand (dit is belangrijk voor de eerste methode om te werken).
  2. Voer het script uit.
  3. Klik op Berekenen en kort daarna op Pauze # 1 of op Pauze # 2 .
  4. Zorg ervoor dat u de waarde van superSecretVar kunt vinden.

Gegevens doorgeven met behulp van de structuur 'grepen'

Dit is een voorbeeld van een basis-GUI met twee knoppen die een waarde wijzigen die is opgeslagen in de structuur van de GUI- handles .

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

Om het voorbeeld te testen, slaat u het op in een bestand met de naam gui_passing_data.m en start u het met F5. Houd er rekening mee dat u in zo'n eenvoudig geval de waarde niet eens hoeft op te slaan in de structuur van de handgrepen, omdat u deze rechtstreeks kunt openen vanuit de eigenschap String van het bewerkingsvak.

Prestatieproblemen bij het doorgeven van gegevens aan de gebruikersinterface

Twee hoofdtechnieken maken het mogelijk gegevens door te geven tussen GUI-functies en Callbacks: setappdata / getappdata en guidata ( lees er meer over ). De eerste moet worden gebruikt voor grotere variabelen, omdat deze efficiënter is in de tijd. In het volgende voorbeeld wordt de efficiëntie van de twee methoden getest.

Er wordt een GUI met een eenvoudige knop gemaakt en een grote variabele (10000x10000 dubbel) wordt zowel met guidata als met setappdata opgeslagen. De knop herlaadt en slaat de variabele op met behulp van de twee methoden terwijl de uitvoering ervan wordt getimed. De looptijd en het percentage verbetering met behulp van setappdata worden weergegeven in het opdrachtvenster.

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

Op mijn Xeon [email protected] GHz krijg ik Difference: 0.00018957 ms / 73 % , dus met getappdata / setappdata krijg ik een prestatieverbetering van 73%! Merk op dat het resultaat niet verandert als een dubbele variabele van 10x10 wordt gebruikt. Het resultaat zal echter veranderen als de handles veel velden met grote gegevens bevat.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow