Is it possible to "bind" the value of a uieditfield to a variable?

In the language I am most familiar with (Visual Foxpro) it is possible to have a textbox with a ControlSource property set to a variable (e.g. MyVar). The textbox displays the value of myVar. Changing the value in the textbox changes the value of MyVar, and vice versa.
Is it possible to do something similar with a uieditfield? If not, I will have to manually set the value of the uieditfield whenever the value of my variable changes.
Might it be possible for the uieditfield to take its value from a function and be dynamically updated in that way? Any other suggestions?
Thank you.

3 Comments

"Is it possible to "bind" the value of a uieditfield to a variable?"
The short answer is no: MATLAB is pass-by-value**, not pass-by-reference, so once that value is stored in two different places then they are quite independent from one another.
"I will have to manually set the value of the uieditfield whenever the value of my variable changes"
What does "manually" mean? You could just write two little functons, for each possible change. Not complex.
"Any other suggestions?"
Why duplicate the value? Perhaps you could simply use the UIEDITFIELD value directly.
** well, actually something more like copy-on-write, but that's not so important right now.
Thank you Stephen. I wil comment fully in the next few minutes.
This is in part prompted ny Stephen's contribution but will I hope clarify things for everybody.
I am plotting two graphs of pH values against volume of base for two different acids. The values to be plotted are dependent on four different variables for each acid. There are a total of 6 uieditfields (and two dropdowns) for the user to enter the different parameters. So before the calculation can take place, the values in the uieditfields must be assigned to the variables (it would be too ugly and cumbersome to use the uieditfield values directly, especially since the calculations require the use of fsolve).
I was originally intending to carry out the calculations (and plotting) when the user clicked on a "Do it" button. I then decided it would be nice to recalculate and plot after any changes to the parameters in the uieditfields. I therefore decided to make use of ValueChangedFcn. An example is here:
efCa1 = uieditfield(gl,'numeric','Value',Ca1,'ValueChangedFcn',@(efCa1,event) valueChange(efCa1,"Ca1"));
The same valueChange function is used for each of the controls. The first parameter (in this case efCa1) tells valueChange which control was changed and the second parameter (in this case "Ca1") tells valueChange which variable efCa1 is associated with.
valueChange sets the value of the variable (Ca1) to the value of the uieditfield (efCa1.Value) and then calls a function (makePlot) which performs the calculations and plots the results. This is now working very nicely.
My apologies for staing earlier "I will have to manually set the value of the uieditfield whenever the value of my variable changes". That was totally misleading.
My thanks to everybody for their contributions. My only problem now is in deciding which answer to accept!

Sign in to comment.

 Accepted Answer

I think the easiest way to do something like this would be to make your variable a class with a value and a handle. If you create a set function in that class you can use it to set the String property of the handle object.
Edit:
I have attached an example implementation that only really needs good documentation and input validation. It hides the internal structure by overloading disp.
h=text(0.5,0.5,'txt');
A=BoundVariable(0,h);
A.value=2; % as you can see, it even works for text objects

24 Comments

I wouldn't know how to go about that without considerable guidance ... all I have to go on is a numeric variable Ka and a uieditfield named efKa. I wouldn't know how to make the varaible a class with a value and handle and I'm not sure what a handle is or how it would be used. My experience with Matlab is very limited.
I'm away from the computer now, so it's harder to write an example for you.
Luckily I don't have to: the Matlab documentation is very good and contains many examples. You need two properties: one named value and one named object. The second one can be used to store the output from the uicontrol function.
A handle is a reference to something. In this case that would be your uicontrol graphics object, but it will also work with a text object, and many other things. The difference between a handle object and a normal variable is that if you make a copy to another variable (e.g. with b=a), the second variable will still refer to the same object, so any change made to one will also apply to the other. You should think of them as containing an address to something, instead of containing that thing itself.
Thank you. I'll start looking for some examples, but if you could write an example when you are back at your computer and can spare a few minutes, I'd be very grateful.
Thank you, Rik.
It looks as if this might be very useful but it will take me a little while to see how I can implement it for my project.
I hadn't seen text() before ...
Since a uieditfield also should have a String property, you can use the output from that function. I just used text to show any object with a String property will work.
I have written a very simple piece of code to see how BoundVariable would work with uieditfields. I needed to modify BoundVariable.m to set Value instead of String.. The test code is here
fig = uifigure("Name","Fig 1");
fig.Name = "Bound variable test";
gl = uigridlayout(fig,[1 1]);
x = uieditfield(gl);
y = uieditfield(gl);
x.Value = "Test";
A=BoundVariable("Test2",x);
y.Value = "Y";
y is only there for somewhere to go after changing the text in x. This is working BUT if I then enter "Test3" in the x uieditfield, the value of A remains unchanged (or, at least, appears to remain unchanged)
It maybe that this was your intention (for changing A to modify x.Value), in which case I apologise for not being clearer. I need a change of x.Value to change the value of the bound variable.
In practice my uieditfields are numeric, so I would a version of BoundVariable to deal with that (should be trivial) or have a way of BoundVariable to intelligenly decide whether it is dealing with a text or numeric property.
Ah, you want it the other way around as well?
That is easy to implement, as I already implemented a get function. Instead of doing v=obj.value; you need v=str2double(obj.handle.String);. That way the getter will load the text from the object, attempt to convert to a number, and return the result.
You will have to check whether the disp method works as expected or should be altered in a similar way.
Thank you, Rik. I am in the middle of something else right now but will look at it again in the light of your last post and see if I can get it working. I will let you know the outcome or if I need further help. I hope that's OK.
Well, I have copied BoundVariable.m to BoundVariable2.m and then tried to modify it to do what I want, but without success. I am not concerned with strings at all, I'm only dealing with numerics. BoundVariable2 needs to work in such a way that the following code works as expected
fig = uifigure("Name","Fig 1");
fig.Name = "Bound variable test";
gl = uigridlayout(fig,[1 1]);
efX = uieditfield(gl,'numeric');
efY = uieditfield(gl,'numeric');
efX.Value = 1;
efY.Value = 0;
%A=BoundVariable2(?,efX);
%A=BoundVariable2(efX)
A % Should be 1
efX.Value = 2;
A % Should be 2
I am not sure what we need where the commented lines are, but I suspect BoundVariable 2 only needs one parameter (the object that A gets it value from). I apologise for not pointing out earlier that I am dealing with numerics ...
The main point is that my code grabs the String property (which is a char vector) and converts it to a numeric scalar. The setter does the opposite: it takes a numeric scalar, converts it to a char vector and sets it as the String property.
Since you want to use the Value property instead, you can omit the conversions back and forth and replace String with Value in the code I gave you.
You didn't attach the edited code, so I cannot point out where you made a mistake.
P.S. The value of A should also change when efX is changed interactively ...
I think I have done as you suggest but still cannot get it to work in such a way that changing the uieditfield value changes the value of A. Revised BoundVaraible2.m attached.
Rik, I think we may be trying too hard ... from what Stephen and Walter have said, I don't think it can be done. In any event see my reply to Stephen (not yet written) in which I will clarify things and explain what I believe to be the best solution. Thanks again for all your efforts.
If by chance you do think you have a way of doing this, by all means let us all know.
If the requirements were that interactive use of the control resulted in change to the variable then ValueChangedCallback (or for some controls, ValueChangingCallback might be preferred)
However, those callbacks are not fired if the value is changed by direct assignment
To catch a change by direct assignments then you would need a listener set on the property. In order to set a listener then the SetObservable attribute needs to be on the property of the object. But I am not at all clear that you would be able to set the Value property as observable as opposed to the stored uieditfield object.
Thank you Walter.
Regarding your first paragraph, I think my use of ValueChangedFcn (see my previous post) is what you have in mind. I do not need to deal with direct assignments to the various controls, however I will bear in mind the comments in your third paragraph for the future.
I will check your code later today. I am convinced that the example code snippet you posted can work as described by its comments.
I finally got round to do the edits for you.
Unfortunately, the online editor cannot use uifigures, so I can't show the results, but on my local machine they match the behavior you put in the comments.
A = BoundVariable2(efX);
A % Shows 1
efX.Value = 2;
A % Shows 2
I will attach the edited function to my answer.
I also implemented an optional second parameter in case you change your mind. With the second parameter you can choose which property to read/write to.
I have does some testing with BoundVariable2 and it appears to be working beautifully. The value of the variable A changes when the value of the uieditfield is changed programatically (i.e. efX.Value = <NewValue> AND/OR when it is changed interactively.
Great piece of work - well done and many thanks.
In the light of other posters effectively saying this could not be done, I wonder if you should bring this to a wider audience? I am sure some people might find it very useful.
There is a nuance here.
What Walter pointed out that isn't possible is actually binding the variables so they are the same (even if not observed).
What my code does is retrieve the value whenever something is trying to read the value. As you noticed, that is in fact possible.
My code might miss some edge cases where the getter is not called before extracting the value. It might be the case that calling struct on the object will not refresh the value before the conversion (I did not test this and there may be more edge cases, e.g. when saving this variable to a mat file). Such edge cases are the only practical difference between what Walter explained is impossible (true binding), and my code (effective binding). Both can be true at the same time (and I trust Walter if he says it is not possible; he is seldom mistaken about these things).
A = BoundVariable2(efX);
class(A)
isnumeric(A)
isa(A, 'double')
A+1 %does this work?
double(A) %does this work?
I doubt there is a way to overload all functions automatically to return the value, so if you want to do it like this exactly, no, this doesn't work. But if you do class(A.Value) etc it should. So I don't really see the issue.
We could imagine that Mathworks could potentially have implemented something along the lines of
A = 42;
linkVariable(A, app.UIedit7.Value)
such that A remains a numeric variable that can be used in calculations like sind(A*2) and that plain assignment to A
A = 30;
affected the output of the edit field and that changing the edit field changed the current value of A (assuming that it exists in a live workspace or as a persistent variable.) That would, after all, be similar to what debuggers can do, with the variable browser giving a "live" view to a variable.
We can imagine that they could have done that, but it is not technically possible at the MATLAB level at this time, as assigning to an unindexed variable currently breaks any existing links except that persistent and global variables stay accessible by name. We know that internal debugging facilities must exist but we do not appear to have any way to access the facilities.
We could imagine creating a new class that derived from double and so could be used in arithmetic, but might perhaps not pass isa('double'). And we could imagine tying it to a control such that certain kinds of value changes got reflected in the control. Not full assignment to the entire variable, but indexed assignments perhaps, A(1)=30 or a set() method, something like that. Could making a change to the control alter the variable? Well the variable would not generally be in scope of the control, not unless your creation routine did something like evalin('caller', 'global NAME'). Maybe you could hack something along those lines, but normally value classes are not "remotely" accessible and changing all references could get messy. Unless, that is, you make the class a handle class.
But is it possible to derive both from double() and handle() such that changes in the control propagate immediately, but arithmetic routines can still transparently use the value? I don't know for sure, but I rather suspect not.
So that gets us to the remaining possibility, of creating a class that provides a "friendly" interface to talk about the value of a control but requires special functions to assign to or get the value and which cannot be used transparently in arithmetic statements.
In this last case, the linked variable becomes similar to an alias.
A = BoundVariable2(app.CONTROL)
A.value %to get at value for arithmetic taking into account changes to the control
A.value = 30 %to set the value including changing the control
standing in for
app.CONTROL.value
app.CONTROL.value = 30
is it worth it? I have my doubts.
I had no idea when I posted this question that it would prompt such lengthy and interesting contributions. I thank you both, Rik and Walter.
For now, what Rik has come up with fits my needs perfectly.

Sign in to comment.

More Answers (1)

If the requirement was that the bound variable would be a plain numeric value that could satisfy isnumeric and isdouble (to be passed as a parameter for example) then the answer would be that there is no provision for that in MATLAB.
It is especially the case that using a plain unindexed assignment will completely overwrite the target variable, removing any special attribute or ties it might have.
You would therefore need to encapsulate the behavior within a class, or you could encapsulate behaviors within functions.

Categories

Find more on Creating, Deleting, and Querying Graphics Objects in Help Center and File Exchange

Products

Release

R2022b

Asked:

on 21 Dec 2022

Commented:

on 29 Dec 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!