Sök…


Skicka data runt användargränssnittet

De flesta avancerade användargränssnitt kräver att användaren kan skicka information mellan de olika funktionerna som utgör ett användargränssnitt. MATLAB har ett antal olika metoder för att göra det.


guidata

MATLAB: s egen GUI-utvecklingsmiljö (GUIDE) föredrar att använda en struct namngivna handles att skicka data mellan återuppringningar. Denna struct innehåller alla grafikhandtag till olika UI-komponenter samt användarspecificerad data. Om du inte använder en GUIDE-skapad återuppringning som automatiskt passerar handles kan du hämta det aktuella värdet med hjälp av guidata

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

Om du vill ändra ett värde som är lagrat i denna datastruktur kan du ändra men sedan måste du lagra det inom hObject för att ändringarna ska kunna synas av andra återuppringningar. Du kan lagra det genom att ange ett andra inmatningsargument till guidata .

% Update the value
handles.myValue = 2;

% Save changes
guidata(hObject, handles)

Värdet på hObject spelar ingen roll så länge det är en UI-komponent i samma figure eftersom data till slut lagras i den siffra som innehåller hObject .

Bäst för:

  • Lagra handles , där du kan lagra alla handtagen till dina GUI-komponenter.
  • Lagring av "små" andra variabler som måste nås av de flesta återuppringningar.

Rekommenderas inte för :

  • Lagring av stora variabler som inte behöver nås av alla återuppringningar och underfunktioner (använd setappdata / getappdata för dessa).

setappdata / getappdata

I likhet med guidata tillvägagångssättet kan du använda setappdata och getappdata att lagra och hämta värden från ett grafikhandtag. Fördelen med att använda dessa metoder är att du bara kan hämta det värde du vill snarare än en hel struct innehåller all lagrad data. Det liknar en nyckel- / värdeförråd.

För att lagra data i ett grafikobjekt

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

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

Och att hämta samma värde från en annan återuppringning

value = getappdata(hObject, 'mykey');

Obs! Om inget värde lagrats innan getappdata returnerar det en tom matris ( [] ).

I likhet med guidata lagras data i figuren som innehåller hObject .

Bäst för:

  • Lagring av stora variabler som inte behöver nås av alla återuppringningar och underfunktioner.

UserData

Varje grafikhandtag har en speciell egenskap, UserData som kan innehålla all UserData du önskar. Det kan innehålla en celluppsättning, en struct eller till och med en skalar. Du kan dra nytta av den här egenskapen och lagra all information du vill kopplas till ett visst grafikhandtag i det här fältet. Du kan spara och hämta värdet med standardmetoderna för get / set för grafikobjekt eller punktnotation om du använder R2014b eller nyare.

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

Sedan från en annan återuppringning kan du hämta dessa data:

their_data = get(hObject, 'UserData');

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

Bäst för:

  • Lagring av variabler med ett begränsat omfång (variabler som troligen endast kommer att användas av objektet där de är lagrade, eller objekt som har ett direkt samband med det).

Kapslade funktioner

I MATLAB kan en kapslad funktion läsa och ändra alla variabler som definieras i moderfunktionen. På det här sättet, om du anger en återuppringning som en kapslad funktion, kan den hämta och ändra all data som är lagrad i huvudfunktionen.

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

Bäst för:

  • Små, enkla gränssnitt. (för snabb prototypning, för att inte behöva implementera guidata och / eller set/getappdata metoder).

Rekommenderas inte för :

  • Medium, stora eller komplexa gränssnitt.

  • GUI skapat med GUIDE .


Explicit input argument

Om du behöver skicka data till en återuppringningsfunktion och inte behöver ändra data inom återuppringningen kan du alltid överväga att skicka data till återuppringningen med hjälp av en noggrant utformad återuppringningsdefinition.

Du kan använda en anonym funktion som lägger till ingångar

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

Eller så kan du använda cellmatrissyntaxen för att ange ett återuppringning och igen specificera ytterligare ingångar.

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

Bäst för:

  • När återuppringning behöver data att utföra vissa operationer, men data variabeln inte behöver ändras och sparas i en ny stat.

Skapa en knapp i ditt användargränssnitt som pausar körning av återuppringning

Ibland vill vi pausa körning av kod för att kontrollera applikationens status (se felsökning ). När du kör kod genom MATLAB-redigeraren kan detta göras med knappen "Paus" i UI eller genom att trycka på Ctrl + c (på Windows). Men när en beräkning initierades från ett GUI (via återuppringning av någon uicontrol ) uicontrol här metoden inte längre, och återuppringningen bör avbrytas via en annan återuppringning. Nedan visas en demonstration av denna princip:

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

För att se till att du förstår detta exempel gör du följande:

  1. Klistra in ovanstående kod i en ny fil som heter och spara den som interruptibleUI.m , så att koden startar på den allra första raden i filen (detta är viktigt för att den första metoden ska fungera).
  2. Kör skriptet.
  3. Klicka på Beräkna och kort därefter klicka på antingen Paus # 1 eller på Paus # 2 .
  4. Se till att du kan hitta värdet på superSecretVar .

Vidarebefordra data med hjälp av strukturen "handtag"

Detta är ett exempel på en grundläggande GUI med två knappar som ändrar ett värde som lagras i GUI: s 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);

För att testa exemplet, spara det i en fil som heter gui_passing_data.m och starta det med F5. Observera att i ett så enkelt fall skulle du inte ens behöva lagra värdet i handtagsstrukturen eftersom du direkt kan komma åt det från redigeringsrutans String .

Prestandaproblem när du skickar data runt användargränssnittet

Två huvudtekniker gör det möjligt att skicka data mellan GUI-funktioner och återuppringningar: setappdata / getappdata och guidata ( läs mer om det ). Den förstnämnda bör användas för större variabler eftersom det är mer tidseffektivt. Följande exempel testar de två metodernas effektivitet.

En GUI med en enkel knapp skapas och en stor variabel (10000x10000 dubbel) lagras både med guidata och med setappdata. Knappen laddar om och lagrar tillbaka variabeln med de två metoderna när de körs. Rörelsetid och procentuell förbättring med setappdata visas i kommandofönstret.

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

På min Xeon [email protected] GHz får jag Difference: 0.00018957 ms / 73 % , så med getappdata / setappdata får jag en prestandaförbättring på 73%! Observera att resultatet inte ändras om en dubbelvariabel 10x10 används, men resultatet kommer dock att ändras om handles innehåller många fält med stora data.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow