How to loop through pushbuttons (=tiles in a maze) with a single callback?

1 view (last 30 days)
I am building a 5 by 5 maze in Matlab, made of pushbuttons (each pushbutton is a tile in the maze). The beginning tile is green; the end tile is yellow. Open tiles are white and blocked tiles (the walls) are blue. Colors are preallocated through a 5 by 5 matrix (A), being white=0, blue=1, yellow=2 and green=3. My main function sets up a 5 by 5 matrix A and then calls a function "create_maze":
A = [0 3 0 1 0 ; 0 0 0 0 1 ; 1 0 0 0 1; 1 1 0 0 1; 1 0 2 0 0];
create_maze(A)
The function also makes only some tiles visible, the ones around the green tile.
So far so good. Now I would like to click on a white tile and have the adjacent tiles appearing. I would like to build a callback function that loops through all the pushbutton/tiles (so I'll need to write only one function). I have put all the pushbuttons in a matrix L and managed to set a callback function to it. The program does run without error (so the callback is kind of working) but... nothing happens! I don't understand why. If you could have a look I would really appreciate it!
This is my function create_maze:
function create_maze(A, varargin)
I set the screen:
scr = get(0, 'screensize');
f1 = figure(1);
set(f1, 'menubar', 'none');
set(f1, 'position', [scr(1) scr(2) scr(3) scr(4)]);
create 25 pushbuttons (sorry...)
h1 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'String', '',...
'Position', [200 200 100 100]);
h2 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [300 200 100 100]);
h3 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [400 200 100 100]);
h4 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [500 200 100 100]);
h5 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [600 200 100 100]);
h6 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [200 300 100 100]);
h7 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [300 300 100 100]);
h8 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [400 300 100 100]);
h9 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [500 300 100 100]);
h10 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [600 300 100 100]);
h11 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [200 400 100 100]);
h12 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [300 400 100 100]);
h13 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [400 400 100 100]);
h14 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [500 400 100 100]);
h15 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [600 400 100 100]);
h16 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [200 500 100 100]);
h17 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [300 500 100 100]);
h18 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [400 500 100 100]);
h19 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [500 500 100 100]);
h20 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [600 500 100 100]);
h21 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [200 600 100 100]);
h22 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [300 600 100 100]);
h23 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [400 600 100 100]);
h24 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [500 600 100 100]);
h25 = uicontrol('Style', 'pushbutton',...
'BackgroundColor', [0.91 0.91 0.91],...
'Position', [600 600 100 100]);
put the pushbuttons in a matrix L
L = [h1 h2 h3 h4 h5; h6 h7 h8 h9 h10;h11 h12 h13 h14 h15;...
h16 h17 h18 h19 h20; h21 h22 h23 h24 h25];
set the colors of the pushbuttons and...
for i = 1: size(A,1) % rows
for j = 1: size(A,2) % columns
if A(i,j) == 0
set(L(i,j),'BackgroundColor', 'w')
set(L(i,j), 'visible', 'off')
elseif A(i,j) == 1
set(L(i,j),'BackgroundColor','b')
set(L(i,j), 'visible', 'off')
elseif A(i,j) == 2
set(L(i,j),'BackgroundColor','y')
set(L(i,j),'String','GOAL')
set(L(i,j), 'visible', 'on')
elseif A(i,j) == 3
set(L(i,j),'BackgroundColor','g')
end
end
...make only some pushbuttons (the ones around the green one) visible
for i = 1: size(A,1) % rows
for j = 1: size(A,2) % columns
if (1 < i) && A(i-1,j) == 3 ||...
(1 < j) && A(i,j-1) == 3
set(L(i,j), 'visible', 'on')
elseif (i < length(A)) && A(i+1,j) == 3 ||...
(j < length(A)) && A(i,j+1) == 3
set(L(i,j), 'visible', 'on')
end
end
end
end
set the callback to the matrix L
set(L(i,j),'callback',{@my_funct,L,A});
set up the callback function
function [] = my_funct(source, callbackdata,L,A)
The following is the complete loop that should make the tiles adjacent to the tile I clicked on visible, but nothing happens (I don't get any error either).
for i = 1: size(A,1) % rows
for j = 1: size(A,2) % columns
if (1 < i) && A(i,j) == 0 ||...
(1 < j) && A(i,j) == 0
set(L(i,j-1), 'visible', 'on')
elseif (1 < i) && A(i,j) == 0 ||...
(1 < j) && A(i,j) == 0
set(L(i-1,j), 'visible', 'on')
elseif (i < length(A)) && A(i,j) == 0 ||...
(j < length(A)) && A(i,j) == 0
set(L(i+1,j), 'visible', 'on')
elseif (i < length(A)) && A(i,j) == 0 ||...
(j < length(A)) && A(i,j) == 0
set(L(i,j+1), 'visible', 'on')
end
end
end
end
end

Accepted Answer

Geoff Hayes
Geoff Hayes on 6 Dec 2015
Serena - I think that you are missing an end at the end of your first double for loop block that sets the colours of the pushbuttons, and that missing end has been put at the end of the next double for loop block to make some of the pushbuttons visible. This causes two problems since both sets of double for loops use the same indexing variables i and j (as an aside, you may want to consider renaming these to something more meaningful since MATLAB also uses these to represent the imaginary number). This most likely causes a problem with the line
set(L(i,j),'callback',{@my_funct,L,A});
only being assigned to the (5,5) pushbutton control since it occurs outside of the previous double for loop. I suggest that you include this in the first block and end it appropriately as
for r = 1: size(A,1) % rows
for c = 1: size(A,2) % columns
set(L(r,c),'callback',{@my_funct});
if A(r,c) == 0
set(L(r,c),'BackgroundColor', 'w')
set(L(r,c), 'visible', 'off')
elseif A(r,c) == 1
set(L(r,c),'BackgroundColor','b')
set(L(r,c), 'visible', 'off')
elseif A(r,c) == 2
set(L(r,c),'BackgroundColor','y')
set(L(r,c),'String','GOAL')
set(L(r,c), 'visible', 'on')
elseif A(r,c) == 3
set(L(r,c),'BackgroundColor','g')
end
end
end
So now every pushbutton will be assigned the callback. Since the above outer for loop as been terminated with the end then you will have to remove the redundant end from the second block of code.
Note the change to your callback
set(L(r,c),'callback',{@my_funct});
Since the callback is a nested function within create_maze, you do not need to pass in parameters that are declared or are local to create_maze. The callback will have access to these elements since it is nested. This will require you to change the callback signature to
function [] = my_funct(source, callbackdata)
So that should get the callback to fire. The next step will be to revisit your callback logic - you probably only want "do" anything if the user is pressing a white pushbutton. You can use the source input along with the property BackgroundColor to retrieve the colour as
bgColor = get(source,'BackgroundColor');
if all(bgColor)
% pushbutton is white
% do something
end
Since the bgColor is a 1x3 array indicating the RGB color, if it is all ones then the button background is white.
Now you presumably need to determine the neighbours of this white pushbutton only. How can you do that since all you have is the source (which is the handle to the pushbutton)? Since the handles are of a floating precision (double) data type, you don't want to be looking through each element of L and comparing each to this handle. So how else can you determine where in L (and so A) this handle is? Hint - look back at how you assign the callback to the pushbutton and consider using the r and c as the unique identifier into L and A.
  6 Comments
Serena De Stefani
Serena De Stefani on 7 Dec 2015
Edited: Geoff Hayes on 7 Dec 2015
Hi Geoff,
Again, thanks a lot for your feedback. I have just another question about the final loop in the callback function.
So I have built the function:
function [] = my_funct(source, callbackdata, rIdx,cIdx)
L = [h1 h2 h3 h4 h5; h6 h7 h8 h9 h10;h11 h12 h13 h14 h15;...
h16 h17 h18 h19 h20; h21 h22 h23 h24 h25];
% disp(rIdx) correctly displayed
% disp(cIdx) correctly displayed
% disp(A) correctly displayed
bgColor = get(source,'BackgroundColor');
if all(bgColor)
bgColor = [1 1 1];
% disp(cIdx) correctly displayed
if (1 < cIdx)
set(L(rIdx,cIdx-1), 'visible', 'on')
elseif (1 < rIdx)
set(L(rIdx-1,cIdx), 'visible', 'on')
elseif (rIdx < length(A))
set(L(rIdx+1,cIdx), 'visible', 'on')
elseif (cIdx < length(A))
set(L(rIdx,cIdx+1), 'visible', 'on')
end
end
end
Strangely, it only works for the pushbutton in the position L(6,1) (that becomes visible when I click on the pushbutton L(1,1), but not for the other ones.
Geoff Hayes
Geoff Hayes on 7 Dec 2015
Serena - you will need more code as the above will only set the visibility for at most one neighbouring push button. As there can be at most eight (depending upon where the current button is located), then you will have to iterate over each one (if I correctly understand what happens when the user presses a push button) and set as visible if needed.

Sign in to comment.

More Answers (0)

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!