I am creating a MATLAB GUI that needs to listen to key press information and then update the screen accordingly. This would not be a problem if the callback function for a key press actually had access to the handles object, but it does not. Is there a way to give this callback access to the handles object?
This is how I start my key listener.
set(hObject,'KeyPressFcn',#keyDownListener)
Then I try to handle this in a the defined function
function keyDownListener(src,event)
% need access to handles
end
I have to imagine it is simple, but I can not seem to find a good answer for this. Thanks in advance.
I think you can do the following:
set(hObject,'KeyPressFcn',{#keyDownListener,handles})
and then define the function as:
function keyDownListener(src,event,handles)
You just have to add addtional parameters to your keyDownListener-fcn. There is a special syntax to do this, as explained here:
matlab-callback-function-only-sees-one-parameter-passed-to-it
Related
I am currently coding a new library with several models in it (I am used to Matlab, but not to Simulink). I am able to create a model with block parameters, let's say parameter 'p', and a callback function (initfct) which uses this parameter to compute specific values used inside my model (let say a simple gain K=K(p)).
My problem is that my parameter 'p' and 'K' are available directly on the workspace, what I don't want to. Moreover, if I use twice or more this model in a system, the two models share always the same 'K', which also I don't want to.
So how I can make these variables 'p' and 'K' independent when I use my custom model several time, and to prevent these variables to be viewed in the workspace ?
Should I use "Reference models", but I am not familiar with this feature ... ?
Thanks for you answer,
Michael
Within a callback, gcb returns the path to the block which currently executes the callback. Having the path, you can use get_param to access the parameters.
Just for demonstation purposes, insert the following to the MoveFcn of a delay block:
set_param(gcb,'DelayLength',num2str(randi(10)))
It will randomly change the delay whenever the block is moved.
I am not sure if my answer explains everything you need. It might be that you also need a Mask. If you think this answer is incomplete, please update your question and include a small example model demonstrating your problem.
Thanks, with your help I was able to solve the problem.
To be more specific if someone else has the same problem : you need in your mask to declare also internal variables used by the callback function. Unchecked the relevant options so that they not appear as standard input parameters of your model.
My problem was also to use num2str instead of mat2str (when the gain was a matrix acting on multiple inputs).
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.
I am now using Matlab GUI and have problem during accessing return values from a function which is set by set().
Situation:
I set the windowMotionFcn as below:
set(gcf,'WindowButtonMotionFcn',#test);
Function 'test' can return 2 variables (named as var1 and var2).But I dont know how to store them...
I have searched in the Internet and could not find any way.
How should I write?
Thank you for your help and kind attention.
I think that what you want to do is to return a value from the callback function. And regarding returning a value from a callback I am not sure that is possible. I found an old article from matlab newsreader. I think your problem could be similar.
However, if you have a matlab GUIDE GUI, there is a way to return a value from a gui. It is described in a matlab tutorial in matlab central: advanced-getting-an-output-from-a-guide-gui. What you must do is to modify your CloseRequestFcn and your OutputFcn.
Another way, which should work is using global variables. A global varable exist in the global workspace. That means that it can be seen and accessed by every function in matlab. Global variables are in most cases not recommended, but if no other solution exists they may be necessary. Just make sure to document them, so that the next person to take over your code knows that they are there. Also make sure to select a good name for the globals, like gblMyVar so there can be no confusion that the variable is global.
I have designed a MATLAB GUI by GUIDE for image analysis. I need to share data between functions so I used the guidata function and stored it in the handles-object as it is documented (http://www.mathworks.de/de/help/matlab/ref/guidata.html).
For the auto generated callback functions (which receive handles automatically) this works well, however I also want to modify the data in self-written functions and self-written callback functions (like click on image events). I tried manually passing the handles object which gives me read access to the data but no way to store it. I tried passing the object handle too, to use guidata(hObject, handles) but the object handle does not work then.
In short: I need a way to read&write data from all functions in the file. I'm looking for a more elegant way than making everything global. That would be my last resort.
Do you have any ideas?
In GUIs, you can use the function setappdata / getappdata in order to store and share data structure between functions (link to docs).
You can use the figure as the handle. For example:
appData = struct;
appData.image = someImage;
appData.title = "someTitle";
setappdata(handles.figure1,'data',appData);
Later, you pass handles to your functions, and you can retrieve your data:
function showTitle(handles)
appData = getappdata(handles.figure1,'data');
title = appData.title;
newTitle = "someNewTitle";
appData.title = newTitle;
setappdata(handles.figure1,'data',appData);
EDIT: Just found this link, which specifies multiple strategies to share data among callbacks.
Thank you a lot! I found the error while trying to produce a reproducebable example. In my case I was using the image handle instead of the figure handle in one function because it was an image click callback and inside that function the image was redrawn so the handle wasn't valid any more.
I use gcf now to obtain the figure handle and it works fine.
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.