MATLAB Language
MATLAB Gebruikersinterfaces
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 / ofset/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 dedata
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:
- 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). - Voer het script uit.
- Klik op Berekenen en kort daarna op Pauze # 1 of op Pauze # 2 .
- 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.