Use Callback function to change string stored in it
显示 更早的评论
I'm writing a code to create an array of pushbuttons. Everytime a button is it should change it's color, based on how many times the user has already clicked the button. I thought about making one single callbackfunction for all buttons. Because I need to check what color the button is I thought about giving a number stored in the button to the callbackfunction. In the callbackfunction itself I will change the color of the button and assign another number to the corresponding button.
That's what I've got so far, but I don't know what the general structure of the callback function should look like and if this even works.
%% Create Bimaru Cells
xorigin=45;
yorigin=410;
distance=35;
for i=1:9 %% Number of columns
for j=1:9 %% Number of rows
xposcell= xorigin+(j-1)*distance;
yposcell= yorigin-(i-1)*distance;
bimarugui(i,j)= uicontrol('unit', 'pixels',... %%allocate an array of white pushbuttons
'background', 'white',...
'Style', 'pushbutton',...
'Value', [1,i,j],... %%stores the counter variable, and the location
'visible', 'on',... in the array
'position',[xposcell,yposcell,distance distance],...
'enable','on',...
'Callback',{@cell_callback,get(bimarugui(i,j),'Value')});
回答(1 个)
Your idea to controll all button colors from a single callback function is a good idea but it can be simplified.
The callback function could store the order of the colors and one of its inputs would be the handle to the button whose color will be changed. All it has to do is look up the current color of the button within the matrix of colors and then assigne the following color. It would look something like this:
function changeButtonColor(buttonHandle)
% Define all colors
buttonColors = jet(10);
% Get current button color
currColor = buttonHandle.BackgroundColor;
% Look up which row of buttonColors matches current color
currColorIdx = find(ismembertol(buttonColors, currColor, 'ByRows', true));
% If a match wasn't found or if the index is the last row, assign row 0
if isempty(currColorIdx) || isequal(currColorIdx, size(buttonColors,1))
currColorIdx = 0;
end
% Assign next color to button
buttonHandle.BackgroundColor = buttonColors(cucurrColorIdx + 1);
*Not tested
To change the color of a button, you would just pass the button's handle to that function.
changeButtonColor(handles.Button1);
15 个评论
Juri Augsburger
2020-3-24
Adam Danz
2020-3-24
The handles structure contains handles to all of your app components (when using GUIDE). All you have to do is pass the button handle to that function.
I updated my answer to demonstrate that at the end.
BTW, you can use this exact same approach in appdesigner!
Let me know if you have any questions.
Juri Augsburger
2020-3-24
编辑:Juri Augsburger
2020-3-24
"I'm not using Guide or appdesigner at the moment.",
Ah, right - I see clearly in the code in your question that you're using uicontrol. Good! This is the best approach to GUIs IMO. It's still a good idea to create a handles stucture to keep all of your GUI's handles together.
"I tried appdesigner, but I always struggled with adressing the specific pushbutton using the same callbackfunction. Could you help me with that?"
Sure. See "step 1" in this answer I provided a few days ago. It shows how to add a callback function to a button. I suggest creating a separate callback function for all of your buttons.
Then, from the code-view of appdesigner, you can add another function that will be the changeButtonColor function from my answer. One the left of the appdesigner UI you'll see "code browser", select "functions" and then press the green + button. Name the function and replace the automatically-generated "app" input with the "buttonHandle" input from my answer. Copy the rest of the code from my answer to that function.
From the button callback function, call the new function as I've demonstrated at the end of my answer.
"...the function doesn't know whch pushbutton's color to change"
Yes, it does know because that's the input: the handle to the pushbutton. This isn't a button callback function. This is an independent function that is called from anywhere within the app. A button's callback function could call this function any time it wants to change color.
Juri Augsburger
2020-3-27
Adam Danz
2020-3-27
If you're using appdesigner, the handle to the button will be stored in the app structure. There is no handles structure in appdesigner unless you created one.
The handle will look something like this: app.Button1
Juri Augsburger
2020-3-27
Guillaume
2020-3-27
In app designer, GUIDE, and many other GUI systems in other languages, a GUI callback always receive two arguments: the object that triggers the callback and some specific event argument object (eg. the state of mouse buttons for a mouse clicks). typically the source is also one of the property of the event argument object, so you get the information twice.
With app designer, this breaks up a bit since App designer's event handling eats the source argument and give you the app instance instead. Thankfully, you still get the event argument with its Source property. The Source property will contain the actual button clicked, so your callback signature (which app designer won't let you edit anyway) should be:
function ButtonsPushedCallback(app, event) %same callback called by all buttons
actualbutton = event.Source;
curcolour = actualbutton.BackgroundColor;
%... compute next colour
actualbutton.BackgrounColor = newcolour;
end
@Guillaume, the changeButtonColor function from my answer is an independent function in the GUI, not a callback function. I'm proposing that the button callback functions include a line of code that calls the changeButtonColor function. That way each button would have its own function space without the need to duplicate the color-change code.
@Juri Augsburger, will the buttons have any actions other than changing their own color? If that's the buttons' only action, then the changeButtonColor function can be changed to a callback function (which is what Guillaume was getting to).
If the buttons' only actions are to change their own color:
Change the changeButtonColor function to behave like a callback function:
function changeButtonColor(buttonHandle, ~)
% (everything else the same)
and set the callback function to
set(bimarugui(l,m),'Callback',@changeButtonColor
If the buttons' callback functions each have different actions:
Assign the buttons callback functions and within each function, call the changeButtonColor function as demonstrated in my answer.
Juri Augsburger
2020-3-27
In that case, instead of passing several button handles as separate inputs, you could combine them in a cell array and pass them as a single input.
function changeButtonColor(hObj, ~, buttonList)
% hobj is the handle to the button that evoked the callback
% buttonList is a cell array of button handles
end
set(bimarugui(l,m),'Callback',{@changeButtonColor, {bimarugui(l-1,m),bimarugui(l,m-1), . . .}})
Juri Augsburger
2020-3-27
Adam Danz
2020-3-27
Juri, instead of storing the handles in a cell array, they can be stored in a handle array which will make indexing easier. I should have suggested that from the beginning. My bad.
set(bimarugui(l,m),'Callback',{@changeButtonColor, [bimarugui(l-1,m),bimarugui(l,m-1), . . .]})
% square brackets ^ .......................................^
To get a property from a single handle stored within a handle array
get(buttonlist(1),'BackgroundColor')
% or simply
buttonlist(1).BackgroundColor; % Case sensitive
To get a n x 3 matrix of BackgroundColors from all handles,
cell2mat({buttonList.Color}')
Guillaume
2020-3-27
I'm confused now. Hasn't the GUI migrated to app designer? If so, there's no need for storing any handle. As I've explained the common callback to all the button will receive the button object that was pressed in its event.Source argument.
Adam Danz
2020-3-27
I can see why it's confusing since the dialog is jumping back and forth a bit. In this comment above, OP mentioned that they will stick with the uicontrol functions rather than appdesigner.
Also, each button is associated with surrounding buttons and when one is pressed, the color for the entire group changes. The additional input is not a handle to a single button. It's a vector of handles that are associated with the pressed button.
Depending on how the buttons are arranged, within a grid, for example, the callback function could detect which buttons are 'near' the pressed button in which case there wouldn't need to be an additional input of associated button handles.
类别
在 帮助中心 和 File Exchange 中查找有关 Interactive Control and Callbacks 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!