MATLAB Language
MATLAB Användargränssnitt
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 / ellerset/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, mendata
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:
- 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). - Kör skriptet.
- Klicka på Beräkna och kort därefter klicka på antingen Paus # 1 eller på Paus # 2 .
- 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.