Reputation: 1021
I have tried the following code in Matlab 2017b:
function demo()
clc,close all
fig=figure();
ax=axes(fig,...
'Units','Normalized',...
'Position',[0.2,0.2,0.6,0.6],...
'XGrid','on',...
'YGrid','on')
slider=uicontrol(...
'Parent',fig,...
'Style','slider',...
'Units','normalized',...
'Position',[0.2,0.9,0.6,0.05],...
'Tag','slider1',...
'Min',0,...
'Max',10,...
'Value',1,...
'Callback',@slider_callback);
x=linspace(0,10);
y=1/3*x.^2;
plot(x,y,'b-')
grid on
xlabel('x-axis')
ylabel('y-axis')
hold on
p=plot(1,1/3,'ro')
hold off
function slider_callback(hObject,eventdata)
x=hObject.Value;
p.XData=x;
p.YData=1/3*x.^2;
drawnow
end
end
Currently, I move the slider and it is only when I release the mouse button that the point is updated. What changes can I make so that I see the point move as I drag the slider?
Thanks.
UPDATE: Thanks to VIG's comment, I was able to do this:
function demo()
clc,close all
fig=figure();
% initialize some parameters
xstart=4;
ystart=1/3*4^2;
ax=axes(fig,...
'Units','Normalized',...
'Position',[0.2,0.2,0.6,0.6],...
'XGrid','on',...
'YGrid','on');
slider=uicontrol(...
'Parent',fig,...
'Style','slider',...
'Units','normalized',...
'Position',[0.2,0.9,0.6,0.05],...
'Tag','slider1',...
'Min',0,...
'Max',10,...
'Value',xstart);
addlistener(slider,'Value',...
'PostSet',@(hObject, event) slider_callback(slider, event));
x=linspace(0,10);
y=1/3*x.^2;
plot(x,y,'b-')
grid on
xlabel('x-axis')
ylabel('y-axis')
hold on
plot([-5,10],[0,0],'k-');
plot([0,0],[-5,35],'k-');
p=plot(xstart,ystart,'ro');
a1=quiver(0,0,xstart,ystart,0,...
'LineWidth',1,...
'Color','red');
a2=quiver(0,0,0,xstart,0,...
'LineWidth',1,...
'Color','red');
a3=quiver(0,0,xstart,0,0,...
'LineWidth',1,...
'Color','red');
d=plot([0,xstart,xstart],[ystart,ystart,0],'k--');
hold off
function slider_callback(hObject,eventdata)
x=hObject.Value;
p.XData=x;
p.YData=1/3*x.^2;
a1.UData=x;
a1.VData=1/3*x.^2;
a2.VData=1/3*x.^2;
a3.UData=x;
d.XData=[0,x,x];
d.YData=[1/3*x.^2,1/3*x.^2,0];
drawnow
end
end
Which produces this image:
I'd love to hear any further suggestions.
Thanks.
Upvotes: 0
Views: 137
Reputation: 1868
You need to add a listener, and then you might omit the callback when creating the slider:
slider=uicontrol(...
'Parent',fig,...
'Style','slider',...
'Units','normalized',...
'Position',[0.2,0.9,0.6,0.05],...
'Tag','slider1',...
'Min',0,...
'Max',10,...
'Value',1);
addlistener(slider,'Value','PostSet',@(hObject, event) slider_callback(slider, event));
EDIT:
You can use impoint
. Then add:
....
addlistener(slider,'Value',...
'PostSet',@(hObject, event) slider_callback(slider, event));
h = impoint(gca,xstart,ystart);
setColor(h,'r')
point = h;
addNewPositionCallback(h,@(h) make_constraint(h));
x=linspace(0,10);
...
and delete the plot p=plot(xstart,ystart,'ro');
.
In slider_callback
replace
p.XData=x;
p.YData=1/3*x.^2;
with
setPosition(point, [x 1/3*x^2])
and add
function make_constraint(h)
fcn = makeConstrainToRectFcn('impoint',[0 10],[1/3*h(1).^2 1/3*h(1).^2]);
% Enforce boundary constraint function using setPositionConstraintFcn
setPositionConstraintFcn(point,fcn);
a1.UData=h(1);
a1.VData=1/3*h(1).^2;
a2.VData=1/3*h(1).^2;
a3.UData=h(1);
d.XData=[0,h(1),h(1)];
d.YData=[1/3*h(1).^2,1/3*h(1).^2,0];
set(slider, 'Value', h(1))
drawnow
end
So total code:
function stackover()
clc,close all
fig=figure();
% initialize some parameters
xstart=4;
ystart=1/3*4^2;
ax=axes(fig,...
'Units','Normalized',...
'Position',[0.2,0.2,0.6,0.6],...
'XGrid','on',...
'YGrid','on');
slider=uicontrol(...
'Parent',fig,...
'Style','slider',...
'Units','normalized',...
'Position',[0.2,0.9,0.6,0.05],...
'Tag','slider1',...
'Min',0,...
'Max',10,...
'Value',xstart);
addlistener(slider,'Value',...
'PostSet',@(hObject, event) slider_callback(slider, event));
h = impoint(gca,xstart,ystart);
setColor(h,'r')
point = h;
addNewPositionCallback(h,@(h) make_constraint(h));
x=linspace(0,10);
y=1/3*x.^2;
plot(x,y,'b-')
grid on
xlabel('x-axis')
ylabel('y-axis')
hold on
plot([-5,10],[0,0],'k-');
plot([0,0],[-5,35],'k-');
a1=quiver(0,0,xstart,ystart,0,...
'LineWidth',1,...
'Color','red');
a2=quiver(0,0,0,xstart,0,...
'LineWidth',1,...
'Color','red');
a3=quiver(0,0,xstart,0,0,...
'LineWidth',1,...
'Color','red');
d=plot([0,xstart,xstart],[ystart,ystart,0],'k--');
hold off
function slider_callback(hObject,eventdata)
x=hObject.Value;
setPosition(point, [x 1/3*x^2])
a1.UData=x;
a1.VData=1/3*x.^2;
a2.VData=1/3*x.^2;
a3.UData=x;
d.XData=[0,x,x];
d.YData=[1/3*x.^2,1/3*x.^2,0];
drawnow
end
function make_constraint(h)
fcn = makeConstrainToRectFcn('impoint',[0 10],[1/3*h(1).^2 1/3*h(1).^2]);
% Enforce boundary constraint function using setPositionConstraintFcn
setPositionConstraintFcn(point,fcn);
a1.UData=h(1);
a1.VData=1/3*h(1).^2;
a2.VData=1/3*h(1).^2;
a3.UData=h(1);
d.XData=[0,h(1),h(1)];
d.YData=[1/3*h(1).^2,1/3*h(1).^2,0];
set(slider, 'Value', h(1))
drawnow
end
end
ps demo()
is an existing MATLAB function, so it's best that you choose another name.
EDIT 2:
In the case that you can't use impoint
, you have to add 3 listeners:
WindowButtonUpFcn
: detects when mouse is released.WindowButtonMotionFcn
: detects when mouse is moved.ButtonDownFcn
: detects when mouse is clicked.The first 2 need to be attached to the figure:
fig=figure('WindowButtonUpFcn',@drop,'WindowButtonMotionFcn',@move);
The last one can be attached to the plot only:
p=plot(xstart,ystart,'ro','ButtonDownFcn',@click);
Since WindowButtonUpFcn
and WindowButtonMotionFcn
are for the whole figure, these will always be called on motion or release of the mouse. But we only want the functions to be executed when dragging the point. To do this a variable (dragging
) is introduced. In the click
function this variable is set to 1
, to indicate that we're dragging.
Then while moving the mouse, the point, quivers and slider are updated in move
. Here a control unit is added to make sure you don't drag the point out of the boundaries of the slider.
When the mouse is released, dragging
is set to 0
again.
Of course it would be nice to know when you are hovering above the point, so that you know that if you click now, you can drag the point. To do this we can set the pointerbehaviour with
iptSetPointerBehavior(p, pointerBehavior);
Here pointerBehavior
is a struct containing 3 functions:
enterFcn
: executed when mouse enters object.exitFcn
: executed when mouse exits object.traverseFcn
: executed when mouse enters object and when it moves in object.We don't need the last one. When entering the mousepointer is set to be a cross with arrows on the edges, when leaving the point is transformed to the (regular) arrow. (for more info see iptSetPointerBehavior and hggroup)
The total code is then:
function stackover()
clc,close all
fig=figure('WindowButtonUpFcn',@drop,'WindowButtonMotionFcn',@move);
% initialize some parameters
xstart=4;
ystart=1/3*4^2;
dragging = 0;
ax=axes('Units','Normalized',...
'Position',[0.2,0.2,0.6,0.6],...
'XGrid','on',...
'YGrid','on');
slider=uicontrol(...
'Parent',fig,...
'Style','slider',...
'Units','normalized',...
'Position',[0.2,0.9,0.6,0.05],...
'Tag','slider1',...
'Min',0,...
'Max',10,...
'Value',xstart);
addlistener(slider,'Value',...
'PostSet',@(hObject, event) slider_callback(slider, event));
pointerBehavior.enterFcn = @(figHandle, currentPoint) set(figHandle, 'Pointer', 'fleur');
pointerBehavior.exitFcn = @(figHandle, currentPoint) set(figHandle, 'Pointer', 'arrow');
pointerBehavior.traverseFcn = [];
x=linspace(0,10);
y=1/3*x.^2;
plot(x,y,'b-')
grid on
xlabel('x-axis')
ylabel('y-axis')
hold on
plot([-5,10],[0,0],'k-');
plot([0,0],[-5,35],'k-');
p=plot(xstart,ystart,'ro','ButtonDownFcn',@click);
iptSetPointerBehavior(p, pointerBehavior); % set behaviour of pointer when over p
iptPointerManager(gcf); % let figure know what you're doing
a1=quiver(0,0,xstart,ystart,0,...
'LineWidth',1,...
'Color','red');
a2=quiver(0,0,0,xstart,0,...
'LineWidth',1,...
'Color','red');
a3=quiver(0,0,xstart,0,0,...
'LineWidth',1,...
'Color','red');
d=plot([0,xstart,xstart],[ystart,ystart,0],'k--');
hold off
function slider_callback(hObject,eventdata)
x=hObject.Value;
p.XData=x;
p.YData=1/3*x.^2;
a1.UData=x;
a1.VData=1/3*x.^2;
a2.VData=1/3*x.^2;
a3.UData=x;
d.XData=[0,x,x];
d.YData=[1/3*x.^2,1/3*x.^2,0];
drawnow
end
function click(hObject,eventdata)
dragging = 1;
end
function drop(hObject,eventdata)
dragging = 0;
end
function move(hObject,eventdata)
if dragging
mouse = ax.CurrentPoint;
x = mouse(1,1);
if x >= slider.Max
x = slider.Max;
elseif x <= slider.Min
x = slider.Min;
end
p.XData=x;
p.YData=1/3*x.^2;
a1.UData=x;
a1.VData=1/3*x.^2;
a2.VData=1/3*x.^2;
a3.UData=x;
d.XData=[0,x,x];
d.YData=[1/3*x.^2,1/3*x.^2,0];
slider.Value = x;
drawnow
end
end
end
Upvotes: 2