简体   繁体   English

在曲线上滑动点

[英]Sliding a point on a curve

I have tried the following code in Matlab 2017b: 我已经在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: 更新 :感谢VIG的评论,我能够做到这一点:

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. 谢谢。

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 . 您可以使用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'); 并删除图p=plot(xstart,ystart,'ro'); .

In slider_callback replace slider_callback替换

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. ps demo()是现有的MATLAB函数,因此最好选择另一个名称。


EDIT 2: 编辑2:

In the case that you can't use impoint , you have to add 3 listeners: 如果您不能使用impoint ,则必须添加3个侦听器:

  • WindowButtonUpFcn : detects when mouse is released. WindowButtonUpFcn :检测何时释放鼠标。
  • WindowButtonMotionFcn : detects when mouse is moved. WindowButtonMotionFcn :检测何时移动鼠标。
  • ButtonDownFcn : detects when mouse is clicked. ButtonDownFcn :检测何时单击鼠标。

The first 2 need to be attached to the figure: 前2个需要附加到该图上:

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. 由于WindowButtonUpFcnWindowButtonMotionFcn用于整个图形,因此始终会在移动或释放鼠标时调用它们。 But we only want the functions to be executed when dragging the point. 但是我们只希望在拖动点时执行功能。 To do this a variable ( dragging ) is introduced. 为此,引入了一个变量( dragging )。 In the click function this variable is set to 1 , to indicate that we're dragging. click函数中,此变量设置为1 ,以指示我们正在拖动。

Then while moving the mouse, the point, quivers and slider are updated in move . 然后,在移动鼠标时,点,颤动和滑块会在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. 释放鼠标时, dragging再次设置为0

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: 这里的pointerBehavior是一个包含3个函数的结构:

  • enterFcn : executed when mouse enters object. enterFcn :当鼠标进入对象时执行。
  • exitFcn : executed when mouse exits object. exitFcn :当鼠标退出对象时执行。
  • traverseFcn : executed when mouse enters object and when it moves in object. traverseFcn :当鼠标进入对象并在对象中移动时执行。

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 ) (有关更多信息,请参见iptSetPointerBehaviorhggroup

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM