I am currently creating a GUI(Graphical User Interface) for my Matlab programs and in one of the programs, one of the arguments is a percentage from a whole.
What I want to do is, create some form of object that presents numbers from 0-100 and the user increases the number by 1 or decrease by -1 with every press of the arrow buttons.
Is there such an object that will help me do that? And how do I create it?
Is this what you are looking for:
function test_perc
figh = figure();
% create a text control that will display the 0 - 100 text
texth = uicontrol('Style', 'text', 'Units', 'normalized', ...
'Position', [0.1, 0.1, 0.8, 0.8], 'FontSize', 56, ...
'String', '0');
% set a function that handles key presses (uses handle to the text object)
set(figh, 'WindowKeyPressFcn', #(hobj, ev) percfun(ev, texth));
function percfun(ev, texth)
% check if leftarrow or rightarrow has been
% pressed and modify text accordingly
if strcmp(ev.Key, 'leftarrow')
val = max(0, str2num(get(texth, 'String')) - 1);
set(texth, 'String', num2str(val));
elseif strcmp(ev.Key, 'rightarrow')
val = min(100, str2num(get(texth, 'String')) + 1);
set(texth, 'String', num2str(val));
end
The code above creates a figure and a uicontrol of style 'text'. The figure is then set to respond to keypresses (WindowKeyPressFcn) with a specific function (percfun) that responds to arrows by setting the text of the uicontrol.
If you have any questions - ask, I will elucidate.
Related
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.
I have an edit text in a MATLAB GUI. I want the user to be able to write only numerals and whenever they write a text character, this last character is immediately deleted. Moreover, I don't know in which kind of function to put this code(callback, keypress, etc.).
This is impossible without resorting to Java. That is because MATLAB has no way to access a uicontrol's typed string; you can only access its current string (i.e., after pressing Enter or changing focus).
Below is an imperfect workaround. It uses two identical edit boxes, one on top of the other, but the topmost box is initially hidden. The KeyPressFcn of the visible edit box:
filters the keypresses on numeric-only
accumulates valid keypresses in a string with global storage
sets that string to the current string of the invisible edit box
Makes that invisible edit box visible, so that it occludes the one you're typing in
Its CallBack function then
Takes the string of the normally-invisible box
Sets the always-visible box' string equal to that string
Hides the normally-invisible box again
Here's the implementation (liberally borrowed from here):
function GUI_tst
% Create new GUI
G.fh = figure('menubar' , 'none',...
'units' , 'normalized', ...
'position', [.4 .4 .2 .2]);
% The actual edit box
G.eh1 = uicontrol('style' , 'edit',...
'units' , 'normalized', ...
'position' , [.1 .4 .8 .2],...
'string' , '',...
'KeyPressFcn', #kpr,...
'Callback' , #cll);
% The "fake" edit box
G.eh2 = copyobj(G.eh1, G.fh);
set(G.eh2, 'Visible', 'off');
% Its string (global)
G.eh_str = '';
guidata(G.fh, G);
end
% "Real" edit box' KeyPressFcn()
function kpr(~, evt)
if isempty(evt.Character)
return; end
G = guidata(gcbf);
% Occlude the "real" editbox with the "fake" one
set(G.eh2, 'visible', 'on');
% Accumulate global string if keys are numeric
if strcmp(evt.Key,'backspace')
G.eh_str = G.eh_str(1:end-1);
elseif isempty(evt.Modifier) && ...
any(evt.Character == char((0:9)+'0') )
G.eh_str = [G.eh_str evt.Character];
end
% Set & save new string
set(G.eh2, 'string', G.eh_str);
guidata(gcbf,G);
end
% "Real" edit box' CallBack()
function cll(~,~)
G = guidata(gcbf);
% Set the "real" box' string equal to the "fake" one's,
% and make the "fake" one invisible again
set(G.eh1, 'String', get(G.eh2, 'String'));
set(G.eh2, 'visible', 'off');
end
This works reasonably well, but it has some drawbacks:
because you're typing somewhere you can't see, the cursor is hidden
selecting text and pressing backspace/delete does not work
it's not very resource efficient
Although it is possible using Java (see this post by MATLAB-god Yair Altman), the simpler and more common way to do it is to just accept that the user is typing invalid input, and only check/correct it in the Callback function (i.e., after pressing Enter).
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 :)