How to capture key press in Matlab uipanel - matlab

How can one capture keyboard entry inside a uipanel, i.e. when anything in the panel has focus? I've found that uipanel does not have the KeyPressFcn property. I've read this post from Undocumented Matlab about Java callbacks, but I also can't get KeyPressedCallback to work. For example, if I try to this:
set(h_panel, 'KeyPressFcn', #(src, event)key_press(obj, src, event));
I get this error:
The name 'KeyPressFcn' is not an accessible property for an instance of class 'uicontrol'.
The same thing occurs if I try KeyPressedCallback. I'm afraid I'll have to resort to some sort of hack involving the parent figure, which I would like to avoid if possible.

KeyPressedCallback is a property of the underlying Java object, not the original Matlab uicontrol object. To access the underlying Java control of a Matlab uicontrol, you need to use the findjobj utility, as I believe that I explained in my blog post that you referenced (you probably missed that crucial step):
jPanel = findjobj(hPanel);
jPanel.KeyPressedCallback = #myMatlabCallbackFunc;
Note that Matlab panels only became Java-based objects in HG2 (R2014b, see here). So on R2014a and earlier Matlab releases you will not be able to use this technique, only on one of the newer releases.

I don't see any callback properties that you can use or events to which you can attach a listener.
>> events(h_panel)
Events for class matlab.ui.container.Panel:
ObjectBeingDestroyed
LocationChanged
SizeChanged
ButtonDown
Reset
PropertyAdded
PropertyRemoved
Just the mouse event (ButtonDown) and the ButtonDownFcn callback. Perhaps there are other tricks. Ask Yair Altman!

Ultimately, I have found there are two reasonable solutions to this problem, both involving what I originally described as "some sort of hack involving the parent figure". Both of them require some sort of concept of an "active" panel or object within the figure in question.
Solution 1
Rely on the last-clicked object to direct keyboard input in the figure to that object. Use ButtonDownFcn for every object in the figure that needs keyboard input. In the callback, store the handle of the object in the appdata of the figure as the "active" object. (Something like setappdata(h_fig, 'active_obj', h_obj.) Then set KeyPressFcn in the figure to a function that will get that handle out of the appdata and branch accordingly.
Solution 2
Use some sort of keypress scheme to decide which object to direct further input to. This works well if you have a number of similar objects that merely need disambiguation. For example, set the KeyPressFcn of the figure to a function that uses keys 1-9 to indicate the correspondingly numbered object. Direct further keyboard input to that object or a related function.
Neither method is perfect, and I wish there was a way to avoid going through the figure, but in practice these aren't very complicated to implement. I'm actually using both simultaneously.

Related

Passing information back and forth between multiple figures in GUIDE GUI, Matlab

I have created several figures in Matlab (using GUIDE) which act as a config-GUI for a model. The idea is that changes made in figure F1 should affect what choices can be made in figure F2, F3, .... However, there are 5 figures, all holding different information, and it is possible to navigate arbitrarily between the figures (push buttons on each figure, to every other figure).
A large issue is that I want only one figure to be open at any point in time. That is, when F1 has started FX, I want F1 to close. Hence, I think it is unsuitable to use global variables. (?)
My issue is that I am simply not capable of holding all the data up to date. Maybe this could be achieved using appdata or guidata, but I cannot wrap my head around it.
Examples:
Since the handles of F1 and F2 differs, passing F1.handles to F2 works (F1.handles shows up in varargin{1} in F2), but I cannot concatenate F1.handles with F2.handles. Hence, I have no apt way of sending F1.handles and F2.handles to F3 (or any other figure). (If this can be achieved in a more simple way, I might be okay with dropping the "arbitrarily navigation feature", but so far I have not been able to make it work.)
Using .mat-files (i.e., write FX.handles to a file and load each file in each Figure) seems such bad practice that I haven't even given it a serious go.
So far, I have not found it necessary to change the data in FN±X from FN, hence I guess the .mat-file approach could work, but my latest idea is using Matlab OOP and pass around a class instead of the handles. I found an old post on the topic (Global (shared) variables in Matlab GUI code behind. Is there better way to do it then using handles structure?) but it links merely to a File Exchange and I am unable to understand how to make it applicable for my use case.
Edit 1: I found this Using GUIDE with object-oriented MATLAB?, and will give it a try, but I am still having a hard time understanding exactly how to use it, since it seems to require using handles anyway.
U can try using global variables to retrieve handles for all the figures created by assigning handles values to a global variable in a structure format. Global variable persists in memory until you close the figures.

MATLAB GUI - How do I remove the CreateFcn callback in my code?

I'm currently learning MATLAB's GUIDE gui programming. I notice that when I place some objects in a figure, a corresponding 'CreateFcn' callback function is creating in the associated .m file. MATLAB's comments state that this function is executed when the object is created (I would consider this a constructor for the object).
However, I've noticed that not all objects seem to have this 'CreateFcn' constructor. Static text objects do not appear to have this callback function. And as of currently, it seems like this function just makes the code more difficult to read. Thus I'm curious if I can delete.
By deleting it, I tend to get an error in my code stating that the function can't be found. So my question: is it possible to delete the 'CreateFcn' method to declutter my code?
Thanks,
Surely it is possible.
Double-click the object to open up the inspector window, locate the "CreateFcn" property and set its value to an empty string. Then go to the .m file and remove the code of CreateFcn. This way MATLAB wouldn't complain about the missing CreateFcn anymore.
CreateFcn is not really a constructor per se, since it happens after all properties of the object are already set. It is more like an optional post-constructor event that gives user an opportunity to further customize the object's initial behavior dynamically. For example, you can customize the object's color at creation depending on the background color on which the object appears. For most control objects, the default behavior is probably already good enough for you. So you can safely remove those CreateFcns until you find a good excuse to use one.
1) Goto the View --> Property Inspector
2) expand the Creation and deletion control, remove the text from CreateFcn and DeleteFcn 3) close the property inspector save the respective GUI (Don't forget to save)
4) remove the callbacks in m-script.

MATLAB GUI to set Object Constructor

I'm currently designing a GUI to open a MAT file(s) to store the time-series variables in it as properties in a class, and do things to the data within the class. The Class is pretty well defined, however, it is the I/O portion of it that I need guidance on.
The constructor of the class currently is written to set the properties to empty if there are no inputs. However, I have a method that has a UIOPEN to get the file and set the properties of the class.
I have created a GUIDE GUI, where I pass the empty object of the class to the handles of the GUI and store it using guidata. The GUI has a button (along with other elements) called "Get File" that will call the property setter method when clicked to populate the properties and a listbox with those properties.
The uncertainty is in the whole architecture of what I have done. I'd like to know if there is a better way to accomplish this. It seems like it's kind of a mickey mouse way of doing it. Thanks!
I can point out a few things:
GUIDE is old, weird and it is generally better to create GUIs programmatically
once you have gotten rid of GUIDE you can have the object govern the GUI behavior easily - the object could have methods to spawn and refresh the gui, hold handles to gui elements in private properties etc.
Creating object-manged guis can also save you some problems with syncing workspace with the gui without using global, assignin or evalin. Since the object holds the data and it also governs the gui - the problem is no longer present.
Mathworks disencourages using guidata for things other than handles to graphical objects, and advices the user to use appdata

How to pre-set cursor or selection for default answer in input dialog

If one creates an inputdialog with inputdlg and a default answer, it looks like that:
Which callback command do I need to make it look like that?
The documentation is missing a lot here. It's a kind of "luxury service" for the customer ;)
But I think it would be nice, if it's easy to implement.
This question is actually solved, as I found out that there are convenient functions like uigetfile and uiputfile for my particular case. But the general case of my questions remains unsolved or at least I haven't tested the java approach.
I'm afraid using the builtin inputdlg without changes this is not possible.
At least there's not 'hidden' feature allowing for this.
You'd need access to the underlying java TextField object for that purpose.
You could copy inputdlg to some new place and make your own version of it.
In combination with the findjobj utility the desired functionality in principle exists.
http://www.mathworks.com/matlabcentral/fileexchange/14317-findjobj-find-java-handles-of-matlab-graphic-objects
Things could look like this then:
% create the edit-field:
h = uicontrol('style', 'edit',...);
% get the underlying java object
% this should be a javahandle to a JTextField
jtextfield = findjobj(h);
% set start/end of the selection as desired:
jtextfield.setSelectionStart(startPos);
jtextfield.setSelectionEnd(endPos);

Limiting string length in a Edit Box on Matlab user interfaces

I inserted an Edit box in a Matlab user interface and I would like to limit the number of characters that an user can type. There is no obvious property on the Edit box (such as "max characters"). I tried to use the callback function, verifying if the current string size on the edit box was bigger than a limit I set and truncating the first characters, however the callback only acted when I clicked outside the edit box and then inside again.
Do you have any idea of how to do this?
Thanks in advance.
EDITED
As suggested by Amro, I tried placing a verification code inside the KeyPressFcn callback of the edit box. I typed the following code:
function prefix_edit_KeyPressFcn(hObject, eventdata, handles)
text = get(hObject, 'String');
if length(text) > 15
set(hObject, 'String', text(1:15));
end
The problem is that the edit box string is only changed when I type something, press Enter and then try to type something again. It seems that the KeyPressFcn is only called after pressing Enter (as mentioned in the forum post that Amro suggested).
The solution proposed in the forum seems too complicated, for such a simple task. Surely there has to be a more elegant way...
Instead of using KeyPressFcn, implement the aforementioned callback function on the KeyTypedCallback property of the underlying Java component, which can be found using the findjobj utility.
Note: do NOT use the underlying Java component's document's lineLimit attribute, since this is a blind alley - a remnant of old Java versions that are not used by Matlab.
You could set your own Document object, but the callback way is simpler I think.
Try to put your logic inside the KeyPressFcn callback function. There is an old newsgroup thread discussing a similar solution.