Linking two push buttons in Matlab GUI
Show older comments
Hi every one.I have a question about push buttons in Gui.
I have imported an image of a car in GUI and on this image exist different push buttons which are responsible for different information of this car.
every time that the operator click on any push buttons the various information will be showned in a tabe.
Now i want to define a new push button as 'shift push button'.And this button is responsible to change the position of any push button that i click on it.
How can i do it?
How can i define a function for each buttons that they change their position and set a new position on this image
5 Comments
It's not clear what kind of repositioning you're looking for. If you want to be able to drag-n-drop a button to a new position, there's no easy way of doing that. If you want to cycle through a bunch of positions as if you're scrambling the orange buttons, that would be fairly simple.
You'll need to change the "position" property of the button object. Are you doing this with app designer, guide, or did you construct the gui bottom-up?
Mahdi Ghourchian
on 14 Aug 2019
Edited: Mahdi Ghourchian
on 14 Aug 2019
Rik
on 14 Aug 2019
As Adam said, drag and drop is impossible (hacks may exist). Changing the position property of your buttons is easy:
set(handle.PushButton1,'Position',ShiftedPositionVector)
Adam
on 14 Aug 2019
You can implement drag and drop in some way or other using the WindowButtonMotionFcn I'm sure, though how you would trigger it and what kind of cursor you could put on screen while doing it I don't know. The actual moving in a way that replicates drag and drop does not seem to present too many challenges though.
Mahdi Ghourchian
on 14 Aug 2019
Answers (1)
Here is a complete demo you can run that allows you to drag-and-drop any GUI object that is assigned a KeyPress and KeyRelease function. Just copy the code to an m file and run it.
Instructions at the top describe how to avoid invoking a button's callback function when it is selected to be repositioned. In short, once the object is active (most recently selected), position the mouse over the object, hold down 'd' (or whatever other activation key you want to assign) and the object's position will be yoked with the mouse cursor until the activation key is relased. To undo the most recent repositioning, select the figure background and press escape.
See comments within the code for more detail.
% DEMO: how to create drag-and-drop placement of objects within a GUI
% after the GUI is created.
%
% SOURCE: https://www.mathworks.com/matlabcentral/answers/475811-linking-two-push-buttons-in-matlab-gui
%
% First a GUI is created with two simple objects.
% Each object is assigned a KeyPress and KeyRelease function. When the
% object is the active object and the activation key is presed, the
% object goes into drag mode and its position follows the mouse until
% the activation button is released. In order for an object to be
% active you must first select it with your mouse. In order to not
% invoke a buttonDown callback function during drag-and-drop, you must
% follow this order:
% 1) select the object by clicking on it and holding down the mouse
% button. Note: if the object is already active, you don't need
% to click on it but the mouse must be on top of the object.
% 2) press and hold the activation key ('d' in this demo; it's easy
% to change).
% 3) Drag the object while continuing to hold the mouse button (if
% need) and the actvation key ('d').
% 4) First release the mouse button (if held), then release the activation
% key. If done in the reverse order, the callback function will be invoked.
% For objects that do not have callback functions invoked by selecting them,
% just click on the object with the mouse and drag while holding the activation
% key.
%
% To undo the previous drag-n-drop, select the figure background and press escape.
%
% Details
% A "WindowButtonMotionFcn" function is assigned to the figure. This function
% continually looks for an object handle stored as "yokedObject" within the figure's
% application data. When "yokedObject" is empty, nothing happens. When "yokedObject"
% contains an object handles, the position of that object is yoked with the mouse
% position (drag mode). The KeyPress functions merely assign the selected object
% to the "yokedObject" field and the KeyRelease function merely removes that object
% so it will no longer be yoked. If the drag duration lasts fewer than 0.2 seconds,
% the object is returned to its original position. This is to avoid accidental
% activations.
%% Create the simple GUI
% Contains 1 button and 1 popup menu
h.fig = figure();
h.but1 = uicontrol(h.fig,'Style','PushButton','Units','Normalize','Position',[.1,.8,.2,.1],'String','Go');
h.popup1 = uicontrol(h.fig, 'Style', 'ListBox', 'Units','Normalize', 'Position', [.5, .6, .2, .2], 'String', {'apples','oranges','pears'});
% assign callback functions
h.fig.WindowButtonMotionFcn = @mouseMotionFcn; % Captures mouse movement within figure
h.but1.Callback = @button1CallbackFcn; % callback function for button
h.but1.KeyPressFcn = @dragAndDropKeyPressFcn; % function: start dragging button
h.but1.KeyReleaseFcn = @dragAndDropKeyReleaseFcn; % function : stop dragging button
h.popup1.KeyPressFcn = @dragAndDropKeyPressFcn; % function : start dragging popup menu
h.popup1.KeyReleaseFcn = @dragAndDropKeyReleaseFcn; % function : stop dragging popup menu
h.fig.KeyPressFcn = @undoDragAndDropFcn; % undo previous drag-and-drop
% Assign handles to gui figure
guidata(h.fig, h)
%% Callback functions
function button1CallbackFcn(hObj,~,~)
% Activated when button is pressed. If the callback function was invoked during
% the drag-and-drop, execution is terminated. Otherwise, this displays a
% message box.
h = guidata(hObj.Parent); % assumes object's parent is figure
if isfield(h,'yokedObject') && isequal(hObj, h.yokedObject)
return % Object is being yoked, do not invoke callback function
end
% display message box
msgbox('Hello world!', mfilename, 'replace')
end
function dragAndDropKeyPressFcn(hObj, event)
% Activated when the object is selected and a key is pressed. If the key is not the
% activation key (assigned below), execution is terminated.
% Hold down the activation key to drag and drop a GUI object to a different location in
% the GUI figure. If key was not the designated activation key, of if object is already
% being yoked, do nothing.
h = guidata(hObj.Parent); %assumes the object's parent is the main figure
if ~strcmpi(event.Key, 'd') || (isfield(h,'yokedObject') && ~isempty(h.yokedObject))
return
else
% store initial button position & units, initial mouse position, and start timer
h.initMousePos = h.currMousePos;
h.tic = tic();
h.originalObjUnits = hObj.Units;
% Set object units equal to figure units (will be reset later)
hObj.Units = hObj.Parent.Units; %assumes the figure is parent to the object
h.initObjPosOnClick = hObj.Position; % in figure units
% Yoke object to mouse position
h.yokedObject = hObj;
guidata(hObj.Parent, h);
end
end
function dragAndDropKeyReleaseFcn(hObj, event)
% Activated when the object is selected and a pressed key is released. If the released
% key is not the activation key (assigned below), execution is terminated.
% If key was not the designated activation key, do nothing.
if ~strcmpi(event.Key, 'd')
return
else
% If activation key was not held long enough, return to orginal position
h = guidata(hObj.Parent); %assumes the object's parent is the main figure
if toc(h.tic) < 0.2
yokedObj = h.yokedObject;
h.previousYokedObject = h.yokedObject;
h.yokedObject = [];
guidata(hObj.Parent, h) %stop drag right away
% Return object to original position and units
yokedObj.Position = h.initObjPosOnClick;
yokedObj.Units = h.originalObjUnits;
else
% drop object at final location
h.previousYokedObject = h.yokedObject;
h.yokedObject = [];
guidata(hObj.Parent, h) %stop drag
hObj.Units = h.originalObjUnits; % return original units
end
end
end
function undoDragAndDropFcn(hObj,event)
% Activated when the figure background is selected and the activation key
% (assigned below) is pressed. The most recent object that was drag-and-dropped
% will be reset back to its original position.
% If key was not the designated activation key or if there isn't a yoked object, do nothing.
h = guidata(hObj);
if ~strcmpi(event.Key, 'escape') || ~isfield(h,'previousYokedObject') || isempty(h.previousYokedObject)
return
else
% Return object to original position
h.previousYokedObject.Units = hObj.Units;
h.previousYokedObject.Position = h.initObjPosOnClick;
h.previousYokedObject.Units = h.originalObjUnits;
% Just in case something went wrong with releasing the yoke
h.yokedObject = [];
end
end
function mouseMotionFcn(hObj, ~)
% Activated when the mouse enters the figure area.
% Stores current mouse position within figure and when an object
% is stored in the "yokedObject" field of the figure's application
% data, the object will move with the mouse.
h = guidata(hObj);
h.currMousePos = get(hObj, 'CurrentPoint');
guidata(hObj,h)
% Yoke the object with the mouse position
if isfield(h,'yokedObject') && ~isempty(h.yokedObject)
% if current mouse position is not within object, stop.
if ~(h.initMousePos(1) >= h.initObjPosOnClick(1) && ... % is to the right of object's left edge
h.initMousePos(1) <= sum(h.initObjPosOnClick([1,3])) && ... % is to the left of object's right edge
h.initMousePos(2) >= h.initObjPosOnClick(2) && ... % is above object's bottom edge
h.initMousePos(2) <= sum(h.initObjPosOnClick([2,4]))) % is under the object's top edge
h.yokedObject = [];
guidata(hObj,h)
return
end
% Compute initial mouse position (in figure units) relative to object position within figure
% Earlier sections of code ensured that the object and figure have the same units.
h.yokedObject.Position(1:2) = h.currMousePos - (h.initMousePos - h.initObjPosOnClick(1:2));
end
end
7 Comments
Mahdi Ghourchian
on 14 Aug 2019
A .fig file just stores a figure and its objects. You can also generate that with code (which is a better idea in general). You are using GUIDE, which comes with its own downsides. You can copy and paste the code Adam gave you in its own m-file and run it to see the effect. You can use the tips below to learn how to make GUIs without being forced to store both an m-file and a fig file.
My small guide to avoid GUIDE:
- Make a figure (with f=figure;) and look into the doc for figure which properties you want to turn off (you probably want to set Menu and Toolbar to 'none')
- Create buttons and axes and everything you need with functions like uicontrol and axes. Save the handles to each element to fields of a struct (like handles.mybutton=uicontrol(___);)
- When you've finished loading all data (and saving it to fields of your handles struct), and creating all the buttons, save your handles struct to the guidata of your figure like this guidata(handles.f,handles);. (You can also use getappdata and setappdata)
- You can set the Callback property of many objects. If you do, use a function name with an @ in front, or a char array that can be evaluated to valid code. (like @MyFunction or 'disp(''you pushed the button'')')
- Callback functions will be called with two arguments: the first is a handle to the callback object, the second is eventdata that may contain special information. To get access to your data, just use handles=guidata(gcbo);. You can replace the gcbo function with the name of the first input to your callback function if you prefer.
- More information about callbacks can be found in multiple places in the doc, for example here.
@Adam: you can directly use h=guidata(hObj); instead of h=guidata(hObj.Parent);.
@Mahdi Ghourchian, the callback functions in my demo are also available in GUIDE GUIs so I believe you could transfer this to a GUIDE GUI and most of the sections would just be copy-paste. However, there is a lot of communication between these functions so you have to take time to understand what's going on and how this works in order to test it and work out any kinks that might occur during the transfer.
As I mentioned from the very beginning (my first comment under your question), if you know the new positions of the buttons ahead of time, it's probably easiest just to directly assign the new position to the button handles rather than drag-n-drop them. For example, if you're just trying to scramble the positions of buttons 1 to 12 between their current positions, there's a MUCH EASIER solution.
Mahdi Ghourchian
on 20 Aug 2019
Adam Danz
on 20 Aug 2019
Glad I could help. Did you get it working in your GUIDE GUI?
Mahdi Ghourchian
on 21 Aug 2019
Edited: Mahdi Ghourchian
on 21 Aug 2019
Adam Danz
on 21 Aug 2019
"yeah....i did it.Instead of defining a new push buttons i used drag and drop method and found the code for it in google."
Mind sharing it or at least a link to what you found?
"these push buttons have kindda lost ther actions."
It sounds like the drag-and-drop method you're using is interfering with the button-down function or callback function of the button. I was careful to avoid that problem in my solution.
"I want to define a new push button and i want to define a function in its call back to reset the other push buttons functionality"
This sounds like a mess, non-intuitive, and not user friendly. It sounds like a bad idea that is designed to fix previous bad ideas. I have a feeling that the entire approach could be replaced my something much cleaner and intuitive. But I still don't know the purpose of the buttons or why they have to move. If you explain that I might be able to suggest better user designs.
Categories
Find more on Migrate GUIDE Apps 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!