I'm creating a graphic interface (manually) and I would like to have a reset button which reset the default values.
I already code this
H.but(3) = uicontrol('Units','normalized', ...
'BackgroundColor',[1 0.7 1], ...
'Callback','MyFunction(''Reset'');', ...
'FontSize',12, ...
'Position',[0.04 0.54 0.1 0.05 ], ...
'String','Reset');
case 'Reset'
clear all % Is not working and I think that isn't that I expect
set(findobj(H.fig,'style','edit', '-or','style','text'),'string','') % H is a global variable. This trial don't give the default value, it just clear certain boxes
I usually prefer to create a specific reset_gui function for my GUIs that resets all the relevant control properties (like checkbox states, strings in editable text boxes, etc.) to appropriate default values, as well as setting all relevant variable values to their defaults, clearing plots, etc..
If you'd prefer a generic option for resetting all UI control properties to their initial state, here's an example of one possible solution:
function example_reset_gui
% Initialize GUI:
hFigure = figure();
uicontrol('Style', 'edit', 'Position', [20 100 100 25]);
uicontrol('Style', 'edit', 'Position', [20 65 100 25]);
uicontrol('Style', 'push', 'Position', [20 20 60 30], ...
'String', 'Reset', 'Callback', #reset_fcn);
drawnow
% Collect default states:
[defaultState{1:3}] = get_default_state(hFigure);
% Nested reset function:
function reset_fcn(~, ~)
set(defaultState{:});
end
end
% Local function:
function [hArray, propArray, valueArray] = get_default_state(hFigure)
hArray = findall(hFigure, 'Type', 'uicontrol');
propArray = fieldnames(set(hArray(1)));
valueArray = get(hArray, propArray);
end
This creates a figure with 2 editable text boxes and a reset button. You can type whatever you want into the text boxes, and when you push the reset button it will clear them (i.e. set them to the default empty string they first contained).
The local function get_default_state will find all the uicontrol objects in the figure, then get all of their set-able properties (i.e. all properties that are not read-only), then get all the initial values for those properties. The three outputs are stored in the 1-by-3 cell array defaultState, which is accessible by the nested function reset_fcn. When the reset button is pressed, all of the set-able UI control properties are set to the values they had when first created.
It should be noted that any changes made to the Position property (such as due to resizing of the figure) could be undone by this approach. Using 'normalized' units would avoid this.
If you truly want to start your GUI over from scratch the easiest way would be to just close it open it again. You can do that from your button's callback. Which I pointed at a new function restartGUI. That could be a subfunction of your main gui or its own m-file, your choice.
Your question is pretty light on details so I can't help with some of the specifics but this should give you the general idea.
IF closing and opening isn't what your want then in the restartGUI function you would have to just manually reset the state of each of your uicontrols, etc. (whatever else is in your GUI that we can't see).
H.but(3) = uicontrol('Units','normalized', ...
'BackgroundColor',[1 0.7 1], ...
'Callback',#restartGUI, ...
'FontSize',12, ...
'Position',[0.04 0.54 0.1 0.05 ], ...
'String','Reset');
% <<<< THE rest of your code >>>
function restartGUI(hObject,varargin)
global H
close(H.fig) %Assuming H.fig the main GUI window.
%Call the GUI again which will restart it.
yourGUIFunction
Edit: added the use of the global H to close.
Related
I have a uibuttongroup with radio buttons defined in it. I have uipanels defined with their corresponding properties. What I want to do is to be able to click one radio button and have one uipanel appear, and then click my other radio button to have the other uipanel appear. Here are snippets of my code:
operation_type_1 = uibuttongroup(S.Test, 'Title', 'Operation Type', 'position', [0 0.3 panel_w/2 0.15]);
uicontrol('Parent',operation_type_1, 'Style', 'radiobutton',...
'String', 'invisible',...
'position', [0 0 0 0], 'Tag', 'invisibutton');
uicontrol('Parent',operation_type_1,'Style','radiobutton',...
'String', 'Time Operation',...
'Position', 100*[0.1 flooring(3.5, 'tp') 1.2 0.15], 'Tag', 'timeop1');
uicontrol('Parent',operation_type_1,'Style','radiobutton',...
'String', 'Volume Operation',...
'Position', 100*[0.1 flooring(2.5, 'tp') 1.2 0.15], 'Tag', 'volumeop1');
This defines my button group and the two radio buttons.
Then I have code which creates a volume panel:
As well as a Time Panel:
These are in the same position. What I want is to be able to click on the "Time Operation" radio button and have the time panel be visible, and when I click on the "Volume Operation" radio button, the volume panel is visible.
I've tried doing switch case statements. I don't get errors, but I don't get results either. For example, my case statements for the time and volume panels are:
switch str
case 'timeop1'
if U.Value; S.result_panel_time1.Visible = 'On';
else S.result_panel_time1.Visible = 'Off';
end
case 'volumeop1'
if U.Value; S.result_panel_volume1.Visible = 'On';
else S.result_panel_volume1.Visible = 'Off';
end
How do I get this to work? I'm not using GUIDE, just coding a MATLAB GUI.
UPDATE
I've tried implementing the callback suggested below, but I get a "Function definition is misplaced or improperly nested." error. I use the following function:
function button_callback(U, varargin{2})
switch get(get(operation_type_1, 'SelectedObject'), 'Tag')
case 'timeop1'
if U.Value; S.result_panel_time1.Visible = 'On';
else S.result_panel_time1.Visible = 'Off';
end
case 'volumeop1'
if U.Value; S.result_panel_volume1.Visible = 'On';
else S.result_panel_volume1.Visible = 'Off';
end
end
end
And I've added the callbacks "...'callback', {#pb_call, S}" to my timeop1 and volumeop1. (Because all of the other function I have are in a .m file called pb_call.m). The function appears to be nested fine but the error points at the exact one.
It seems to me you did not define callback for your RadioButton. For example, set callback for volumeop1:
uicontrol('Parent',operation_type_1,'Style','radiobutton',...
'String', 'Volume Operation',...
'Position', 100*[0.1 0.3 1.2 0.15], 'Tag', 'volumeop1', ...
'Callback', #switchPanel);
Then in function switchPanel, you will set corresponding panel visible, while set others invisible.
This is trying to answer your questions, but it seems to me what you want is uitab.
My partner ended up fixing it:
The callback was {callback, S} and S, U, and str were:
S = varargin{3}; %main figure handle
U = varargin{1}; %current uicontrol
str = char(U.String);
The problem occurred in the radiobutton creation, since the result panels were being created after the radiobuttons could be triggered, thus nothing was made invisible/visible and an error would occur.
However, it would be highly convenient if callbacks could affect all GUI parts, not just previously defined ones. I've tried using guidata in the past, but I had to use other, less straighforward methods to accomplish my goals. I'll try using working samples and building upon those in the future, but currently I am working on another part of the project and will get back to that later.
But using either guidata/setappdata or something related would work here as well as my own solution, which is making sure that the objects you are trying to change are already defined before the button triggering the callback.
(He also posted this answer to where I asked this same question in MATLAB Answers.)
Im trying to create a calendar using MATLAB GUI.
I have two Edit Text objects - edittext1 and edittext2.
I want to do this one:
I put cursor at edittext1 then select date at calendar and it pits into text field of edittext1.
And the same for edittext2: if I put cursor into edittext2 and select date it puts into edittext2 Edit Text.
I know I can use callback for calendar this way.
Question:
How can I put into Callback function handler to ACTIVE edit text object?
How to get handle to object where cursor is now?
About the focus question, there is no active text box when you click a date on the java calendar, because the active component at this time is the java calendar.
To know which text box was active last, you simply need to keep track of it. One way is to add a callback to the edit box, which will update a variable (stored in the appdata) with the handle of the latest active text box.
Armed with that, the callback of the calendar will just retrieve the date, then place it in the last active text box.
Note: The ButtonDownFcn event of the text box will only fire on left and right click if the text box 'enable' property is 'off' or 'inactive'. (if it is 'on', then only the right click is detected). That is why I declared the text boxes as inactive. That does not prevent you to update the text programmatically so I didn't think it was a problem.
Code for testcalendar.m:
function testcalendar
handles.f = figure;
commonEditProperties = {'Style', 'edit', 'String', '', ...
'Units', 'Normalized', ...
'Enable','inactive' , ...
'callback',#EditBoxFcn , ...
'ButtonDownFcn',#EditBoxFcn } ;
handles.ledit = uicontrol( commonEditProperties{:}, 'Position', [0.1 0.1 0.3 0.1], 'Tag','ledit' );
handles.redit = uicontrol( commonEditProperties{:}, 'Position', [0.5 0.1 0.3 0.1], 'Tag','redit' );
% preallocate a variable to hold the active text box handle
setappdata(handles.f,'activeTextBox',[]) ;
com.mathworks.mwswing.MJUtilities.initJIDE;
% Put calendar to my figure
handles.jPanel = com.jidesoft.combobox.DateChooserPanel;
[handles.hPanel,handles.hContainer] = javacomponent(handles.jPanel,[100,100,200,200], handles.f);
juiFunHandle = handle(handles.jPanel, 'CallbackProperties');
set(juiFunHandle, 'MousePressedCallback', ...
#(src, evnt)CellSelectionCallback(src, evnt, handles));
set(juiFunHandle, 'KeyPressedCallback', ...
#(src, evnt)CellSelectionCallback(src, evnt, handles));
% store gui handles in application data
guidata(handles.f , handles)
end
function EditBoxFcn(hobj,~)
handles = guidata(hobj) ;
ActiveTextBox = get(hobj,'Tag') ;
setappdata( handles.f , 'activeTextBox', handles.(ActiveTextBox) ) ;
end
function CellSelectionCallback(~, ~, handles)
% retrieve the handle of the active text box
ActiveTextBox = getappdata(handles.f,'activeTextBox') ;
% assign a default active text box if none was selected before
if isempty(ActiveTextBox) ; ActiveTextBox = handles.ledit ; end
numRetry = 10 ;
for k=1:numRetry
pause(0.1)
dateString = char( javaMethodEDT('getSelectedDate', handles.jPanel) ) ;
if ~isempty(dateString) ; break ; end
end
set(ActiveTextBox , 'String' , dateString ) ;
end
See it in action:
Edit
There is no pure Matlab way to have your Matlab edit box fully editable an reacting (firing an event) to a single click of any mouse button.
You can get this functionality by using the text box underlying java object. This java object exposes a lot of events and you can just pick the one you need.
The catch:
To get the handle of the underlying java object, you need to use the almighty findjobj utility by Yair Altman. You can download the latest version from the file exchange here: findjobj
Once you have that saved in your Matlab path, just replace the few first line of code defining the edit boxes given in the example above by:
commonEditProperties = {'Style', 'edit', 'String', '', 'Units', 'Normalized', 'Enable','on' } ;
handles.ledit = uicontrol( commonEditProperties{:}, 'Position', [0.1 0.1 0.3 0.1] );
handles.redit = uicontrol( commonEditProperties{:}, 'Position', [0.5 0.1 0.3 0.1] );
% preallocate a variable to hold the active text box handle
setappdata(handles.f,'activeTextBox',[]) ;
% Find the java underlying object for the text boxes
ledit = findjobj(handles.ledit) ;
redit = findjobj(handles.redit) ;
% assign a callback to the java object (which CAN detect single click)
set(ledit,'MouseClickedCallback',#(h,e) setappdata( handles.f , 'activeTextBox', handles.ledit ) ) ;
set(redit,'MouseClickedCallback',#(h,e) setappdata( handles.f , 'activeTextBox', handles.redit ) ) ;
And you can completely comment or remove the sub-function EditBoxFcn as the callback action is done directly.
So for a self project I'm creating a gui minesweeper like game in matlab and want to create an adjustable pushbutton grid however I'm not sure on how to do so. this is what I have got so far.
function createField()
xAmount = str2double(inputdlg('enter row length'));
yAmount = str2double(inputdlg('enter column length'));
for i = 1:xAmount
for j = 1:yAmount
%create buttons
end
end
end
One solution might be:
function create_field(hparent, nx, ny, width, padding)
% Test arguments
if ~test_parent_handle(hparent)
error('Parent must be a single valid graphic handle.');
elseif ~test_positive_integer(nx)
error('Number of buttons on X direction must be a scalar positive integer.');
elseif ~test_positive_integer(ny)
error('Number of buttons on Y direction must be a scalar positive integer.');
elseif ~test_positive_integer(width) ...
|| (width >= 100)
error('Button width must be a scalar positive integer smaller than 100.');
elseif ~test_positive_integer(padding) ...
|| (padding >= 20)
error('Button padding must be a scalar positive integer smaller than 20.');
end;
% Resize the parent to fit the button grid
set(hparent, 'Units', 'pixels');
ppos = get(hparent, 'Position');
ppos(3) = nx*width + (nx-1)*padding;
ppos(4) = ny*width + (ny-1)*padding;
set(hparent, 'Position', ppos);
% Create button grid
for p = 1:nx
for q = 1:ny
bpos = [ % Button spec:
(p-1)*(width+padding) % - X
(q-1)*(width+padding) % - Y
width % - W
width % - H
];
uicontrol( ...
'Units', 'pixels', ...
'Tag', sprintf('X%dY%d',p,q), ...
'Style', 'pushbutton', ...
'Parent', hparent, ...
'Position', bpos ...
);
end;
end;
% ----- NESTED FUNCTIONS -----
function tf = test_parent_handle(value)
tf = isscalar(value) ...
&& ishandle(value);
end
function tf = test_positive_integer(value)
tf = isscalar(value) ...
&& isreal(value) ...
&& isfinite(value) ...
&& (value > 0) ...
&& (fix(value) == value);
end
end
For a figure with 15 x 10 square buttons, each having the side 25 pixels with a padding of 3 pixels between the buttons, call:
create_field(figure(), 15, 10, 20, 3);
As with most problems there are many different approaches, having written something similar I'll give you the same prompts that I used when writing my helper function.
Your code is going to act based on what button is pressed so each button will need its own unique ID and properties. Depending on the MATLAB version used, each of your graphics elements will have a handle. Starting in R2014b, graphics objects can be addressed directly as objects rather than needing to utilize a numeric ID as a pointer.
Start with the figure window and check out the figure properties:
h.mainfig = figure; % Arbitrary figure window
get(h.mainfig); % Dump properties to command window
Right now we're probably most interested in the Units and Position properties of the main figure window, which you can use in a helper function to figure out how to size and space the buttons as you create them.
If we create a pushbutton graphics object with uicontrol() we're going to get mostly the same properties.
h.randombutton = uicontrol('Parent', h.mainfig, 'Style', 'pushbutton');
get(h.randombutton);
Again, we're interested in the Units and Position properties. We're also going to be interested in the Callback property, which is the function that executes when we interact with the button. Another good one is the Tag property, which can be used to set a unique string tag for each button for use with later logic.
You've probably noticed I'm using a structure array to store my graphics handles. This is similar to how MATLAB generates its object data when creating a GUI with GUIDE and has the huge advantage of a tidy data package to pass around our function. A great thing about structure arrays is that you can nest data structures, allowing us to easily generate and address graphics objects without needing to get clever with dynamic field references or eval() (yuck). Instead of having to do something like button_1, button_2, etc, we can do:
h.button(1) = uicontrol('Parent', h.mainfig, 'Style', 'pushbutton');
h.button(2) = uicontrol('Parent', h.mainfig, 'Style', 'pushbutton');
...
h.button(n) = uicontrol('Parent', h.mainfig, 'Style', 'pushbutton');
Now we know how to generate an arbitrary number of buttons programmatically and easily address them later on.
Other than the button generation we have another key function that I mentioned earlier, the button callback. Callback functions follow a slightly different syntax in that they natively pass along two arguments, the handle of the object whose callback is executing and the event data structure (see the documentation for more info). Because the function knows what UI object invoked it, we can make a pretty generic function.
Hopefully this helps!
Have you considered creating the ui in Java - undocumented matlab has some examples. Java would provide you nice LayoutManagers that will take care about resizing and more.
I wrote a code like this in Matlab:
function[] = gui_function()
window.value1 = uicontrol('style', 'edit', ...
'string', '5', ...
'callback', #is_number);
window.computeButton = uicontrol('style', 'push', ...
'callback', {#test_script, str2double(get(window.value1, 'string'))});
end
function[] = test_script(varargin)
value1 = varargin{3};
end
I want to pass the text from Edit uicontrol to Button's callback. When I do it as following, the value that is passed is an old value that is set when declaring the uicontrol.
So ie. I run the GUI and have a value of 5 in the edit. I overwrite it to be 20, but after pushing the button, the value that is being passed is still 5
What is wrong in this approach? How can it be done differently?
Thank you in advance!
In my opinion, the best option when working with GUIs is to use the handles structure of the GUI, in which every uicontrols are stored along with their associated properties, in addition to (that's the cool part) whatever you want to store in it, like variables for instance.
So I modified you code a bit to make use of the handles structure. I'm not entirely clear as to what you want, but in my example the pushbutton is used to update the content of a second edit box with the content of the 1st edit box. That's very basic, but it should help you get a feel of handles and the handles structure. If something is unclear please let me know!
function gui_function()
ScreenSize = get(0,'ScreenSize');
handles.figure = figure('Position',[ScreenSize(3)/2,ScreenSize(4)/2,400,285]);
handles.Edit1 = uicontrol('style', 'edit','Position',[100 150 75 50], ...
'string', '5');
handles.Edit2 = uicontrol('style', 'edit','Position',[100 80 75 50], ...
'string', 'Update me');
handles.computeButton = uicontrol('style', 'push','Position',[200 100 75 75],'String','PushMe', ...
'callback', #PushButtonCallback);
guidata(handles.figure, handles); %// Save handles to guidata. Then it's accessible form everywhere in the GUI.
function PushButtonCallback(handles,~)
handles=guidata(gcf); %// Retrieve handles associated with figure.
TextInBox1 = get(handles.Edit1,'String');
set(handles.Edit2,'String',TextInBox1); %// Update 2nd edit box with content of the first.
%// Do whatever you want...
guidata(handles.figure, handles); %// DON'T forget to update the handles structure
You could customize this GUI by adding your function callback (test_script) in the same way I implemented the PushButtonCallback. Hope I understood what you wanted :)
I have some sliders on figure 1, and I have some images on figure 2. I want to do the callbacks for the sliders in a way that, when I change the sliders in figure 1 , the threshold changes and images update automatically in figure 2.
I'm using addlistener to send values for callback function. The problem is when you move slider the active figure is figure 1, and you want to do changes on figure 2.
adding some code for clarification:
M.rgbImage = imread('euhedral-mag-on-po-edge-pseudo-sub-ophitic-rl-fov-4-8mm.jpg');
[rows, columns, numberOfColorBands] = size(M.rgbImage);
F.f = figure; % This is the figure which has the axes to be controlled.
% Now create the other GUI
S.fh = figure('units','pixels',...
'position',[400 400 500 100],...
'menubar','none',...
'name','Image control',...
'numbertitle','off',...
'resize','off');
S.sl = uicontrol('style','slide',...
'unit','pix',...
'position',[60 10 270 20],...
'min',0,'max',255,'val',100,...
'callback',{#sl_call2,S},'deletefcn',{#delete,F.f});
....
lis = addlistener(S.sl,'Value','PostSet',#(e,h) sl_call3(S,F,M));
function sl_call3(S,F,M)
v = get(S.sl,'value');
figure(F.f), subplot(4, 4, 13);
M.redMask = (M.redPlane > v);
imshow(M.redObjectsMask, []);
set(S.ed(2),'string',v);
Create reference to both your figures:
f1=figure(1);
f2=figure(2);
And then when doing the callback pass f2 as a parameter.
In the callback, you'll have get the handle to the second figure.
There's various ways to do that.
You can specify the handle to the second figure at the time of callback-definition:
figure2 = ...;
addlistener(hSlider, ..., #(a,b) changeStuffOn(figure2));
Or during the callback:
function callbackFunction(hObject, evt)
% get the handle to the second figure, e.g. by a tag, or its name
fig2 = findobj(0, 'type', 'figure', 'tag', 'figure2'); %
% do whatever you want with fig2
end
The latter might be somewhat worse in performance, but e.g. has the benefit of working reliably even if figure2 was deleted and recreated and some point.
To avoid the change of focus you'll have to get rid of this line your callback:
figure(F.f)
This explicitly moves the focus to the second figure.
You'll have to use e.g. the imshow(axes_handle, ...) syntax, in order to show the image not in the "current axes".