【问题标题】:How to use "ButtonDownFcn" in a populated GUI axes?如何在填充的 GUI 轴中使用“ButtonDownFcn”?
【发布时间】:2018-12-16 17:49:48
【问题描述】:

我有一个非常简单的 GUI,其中我有一个由按钮启动的绘图功能,该按钮在轴上绘制散点图(称为 Method1axes1):

handles.plot = scatter(X,Y, 'parent', handles.Method1axes1);

现在我希望用户能够单击轴(绘图)以获取更大的新图形。如果我不先在轴上绘图,我尝试了下面的代码。一旦我运行绘图函数,散点图就会出现在 Method1axes1 中,但我无法再单击该图。

% --- Executes on mouse press over axes background.
function Method1axes1_ButtonDownFcn(hObject, eventdata, handles)
figure
scatter(X,Y);

我做错了什么?

【问题讨论】:

    标签: matlab matlab-guide matlab-gui


    【解决方案1】:

    这是 MATLAB 的一种特殊情况,并且没有很好的文档记录。

    您需要考虑两件事:

    • 1) 最明显的部分。当您在axes 中绘制某些内容时,该情节位于前景中。因此,当您单击 axes 时,顶部的情节会拦截该点击并尝试处理它。您需要从axes 中的绘图/散点图/图像对象中禁用鼠标单击捕获。为此,您必须将分散对象的HitTest 属性设置为'off'。 (最近的 MATLAB 版本更改了该属性的名称,现在称为PickableParts)。

    • 2) 不太明显和记录在案。它曾经在 axes ButtonDownFcn 回调的文档中,但不再解释(尽管行为仍然存在)。这是我在旧论坛上可以找到的:

    调用 PLOT 时,如果坐标区 NextPlot 属性设置为 'replace' (默认情况下)axes 的大部分属性(包括 ButtonDownFcn) 被重置为其默认值。

    axes NextPlot 属性更改为'replacechildren' 以避免这种情况, 或者在调用PLOT之后设置ButtonDownFcn,或者使用低级LINE 函数而不是更高级别的 PLOT 函数。

    这也在这里讨论和解释:Why does the ButtonDownFcn callback of my axes object stop working after plotting something?


    对于您的情况,我尝试了set(axe_handle,'NextPlot','replacechildren'),它可以让鼠标点击到达ButtonDownFcn,但不幸的是它对axes 限制和LimitModes 造成了严重破坏......所以我选择了第二种解决方案,即在axes中的每一个情节之后重新定义ButtonDownFcn的回调。


    总而言之,pushbutton1_Callback 的代码应该是:

    function pushbutton1_Callback(hObject, eventdata, handles)
        % Whatever stuff you do before plotting
        % ...
        % Plot your data
        handles.plot = scatter(X,Y, 'parent', handles.Method1axes1);
        % Disable mouse click events for the "scatterplot" object
        set(handles.plot,'HitTest','off') ;
        % re-set the "ButtonDownFcn" callback
        set(handles.Method1axes1,'ButtonDownFcn',@(s,e) Method1axes1_ButtonDownFcn(s,e,handles) )
    

    而对于你的axes鼠标点击事件,你不妨保留新生成对象的句柄:

    function Method1axes1_ButtonDownFcn(hObject, eventdata, handles)
        handles.newfig    = figure ;
        handles.axes1copy = copyobj( handles.Method1axes1 , handles.newfig ) ;
    

    请注意,我只是使用copyobj 函数而不是绘制新集合,这在您需要重现绘图时非常方便。


    插图:

    【讨论】:

    • 很好的答案!我认为您所做的一项关键更改是设置回调 after 调用 scatter。据我了解,OP首先设置回调,然后绘图,如果我没记错的话,它将重置回调。
    • @CrisLuengo,没错。似乎如果axesNextPlot 属性是默认的replace,则高级绘图函数(plot/scatter/plot3 ... etc)会重置大部分axes 回调。调用像line 这样的较低级别的对象不会这样做,但我不知道scatter 的等效低级别。这也是为什么为轴声明 hold all 似乎可以解决我在网上找到的许多答案的问题(因为它将 NextPlot 设置为 'add'),但在这个例子中并不实用。
    • 其实已经有人解释了一部分:stackoverflow.com/questions/5273481/…
    • 现在scatter 有自己的对象类型,但在过去它只是一个或多个line 对象。对于简单的scatter(x,y),您会得到与plot(x,y,'o') 相同的结果,因此您可以使用低级别的line 创建该图。但是,是的,hold on 也解决了这个问题(与cla 结合可以删除以前的绘图而不重置坐标轴属性)。
    • @Hoki,非常感谢您提供的非常出色和有用的答案。
    【解决方案2】:

    如果你想设置图形/图形在鼠标上放大和缩小 滚动/单击,然后只需将所需轴的缩放属性设置为 OpeningFcn 在 m 文件中。

    例如在 GUI 的 m 文件中的 OpeningFcn 中,放入以下代码。请确保将以下代码放入 OpeningFcn 函数中。

    h1 = zoom(handles.Method1axes1);
    h1.Enable = 'on';
    

    现在,在每次鼠标滚动/单击时,您都可以放大/缩小图表。

    下面给出了名为 ZoomAxesDemo 的 GUI 的 openingFcn 示例屏幕截图。

    【讨论】:

    • 嗨,安詹。您的代码运行良好,但问题是我有一个 16 个小轴的 GUI。因此,当用户单击它时,我需要“图形/图形”更大。
    • 你想在所有 16 个小轴上放大图形吗,在每个轴上单独单击?我不明白您要准确传达的要求。
    • 我只想把点击的图放大。
    • 请不要发布代码图片,对于看不到图片的人,您的回答会失去很多用处。此外,复制粘贴代码应该比制作和上传屏幕截图更容易!
    • 我认为@CrisLuengo 试图提出的观点是,您可以(应该)将代码本身作为格式化代码发布,而不是发布代码的屏幕截图。代码的屏幕截图在 SO 上并不是特别有用。屏幕截图的适当用途是显示运行代码产生的图形,但任何代码的 sn-p 都应作为代码发布,而不是作为屏幕截图。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-27
    • 2015-06-10
    • 2018-10-08
    • 1970-01-01
    相关资源
    最近更新 更多