使用wx.SplitterWindow时如何在wxPython中显示光标坐标

时间:2018-01-15 18:57:54

标签: matplotlib wxpython marker

我正在尝试执行类似于此link中所示的操作来绘制光标并在状态栏中报告数据坐标。但是,我的代码有点不同,因为我需要使用wx.SplitterWindow来分隔按钮和图。基本上,在主框架模块中,我创建状态栏,但绘图是在分离的模块中生成的。请参阅下面我当前的代码:

from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import \
    FigureCanvasWxAgg as FigCanvas, \
    NavigationToolbar2WxAgg as NavigationToolbar, \
    wxc as wxc

import pylab
import wx
from numpy import arange, sin, pi

class data:
    def __init__(self):
        self.t = []
        self.s = []

class Plot_Panel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        # create some sizers
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        checkSizer = wx.BoxSizer(wx.HORIZONTAL)

        # create figrue
        self.fig = Figure()
        self.canvas = FigCanvas(self, -1, self.fig)
        self.axes = self.fig.add_subplot(111)

        # create the widgets
        self.toggleMarker = wx.CheckBox(self, label="Show Marker")

        # layout the widgets
        mainSizer.Add(self.canvas, 1, wx.EXPAND)
        checkSizer.Add(self.toggleMarker, 0, wx.ALL, 5)
        mainSizer.Add(checkSizer)
        self.SetSizer(mainSizer)

    def draw_plot(self, data):
        # Clear the previous figure
        self.fig.clear()

        # Redraw figure
        self.axes = self.fig.add_subplot(111)

        # Define data to plot
        self.plot_data= self.axes.plot(data.t, data.s, linewidth=3, color='y',)[0]

        # Draw Cursor or not
        if self.toggleMarker.IsChecked():
            # Note that event is a MplEvent
            self.canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar)
            self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor)

        self.canvas.draw()

    def ChangeCursor(self, event):
        self.canvas.SetCursor(wxc.StockCursor(wx.CURSOR_BULLSEYE))

    def UpdateStatusBar(self, event):
        if event.inaxes:
            x, y = event.xdata, event.ydata
            # self.statusBar.SetStatusText(("x= "+str(Pos.x)+"  y="+str(Pos.y)))


class Button_Panel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        # create the widgets
        self.toggleStart = wx.Button(self, id=wx.ID_ANY, label="Plot data")


class ProportionalSplitter(wx.SplitterWindow):
    def __init__(self,parent, id = -1, proportion=0.66, size = wx.DefaultSize, **kwargs):
        wx.SplitterWindow.__init__(self,parent,id,wx.Point(0, 0),size, **kwargs)
        self.SetMinimumPaneSize(50) #the minimum size of a pane.
        self.proportion = proportion
        if not 0 < self.proportion < 1:
            raise ValueError, "proportion value for ProportionalSplitter must be between 0 and 1."
        self.ResetSash()
        self.Bind(wx.EVT_SIZE, self.OnReSize)
        self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged, id=id)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.firstpaint = True

    def SplitHorizontally(self, win1, win2):
        if self.GetParent() is None: return False
        return wx.SplitterWindow.SplitHorizontally(self, win1, win2,
            int(round(self.GetParent().GetSize().GetHeight() * self.proportion)))

    def SplitVertically(self, win1, win2):
        if self.GetParent() is None: return False
        return wx.SplitterWindow.SplitVertically(self, win1, win2,
            int(round(self.GetParent().GetSize().GetWidth() * self.proportion)))

    def GetExpectedSashPosition(self):
        if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
        else:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
        return int(round(tot * self.proportion))

    def ResetSash(self):
        self.SetSashPosition(self.GetExpectedSashPosition())

    def OnReSize(self, event):
        "Window has been resized, so we need to adjust the sash based on self.proportion."
        self.ResetSash()
        event.Skip()

    def OnSashChanged(self, event):
        "We'll change self.proportion now based on where user dragged the sash."
        pos = float(self.GetSashPosition())
        if self.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height)
        else:
            tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width)
        self.proportion = pos / tot
        event.Skip()

    def OnPaint(self, event):
        if self.firstpaint:
            if self.GetSashPosition() != self.GetExpectedSashPosition():
                self.ResetSash()
            self.firstpaint = False
        event.Skip()

class Main_Window(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title = title)

        # Create a StatusBar at the bottom of the window
        self.statusBar = wx.StatusBar(self, -1)
        self.SetStatusBar(self.statusBar)

        # Set plot panel
        self.splitter = ProportionalSplitter(self,-1, 0.85)
        self.ppanel = Plot_Panel(self.splitter)
        self.ppanel.SetBackgroundColour('#ffffff')

        # Set button panel                           
        self.bpanel = Button_Panel(self.splitter)

        # Set frame 
        self.splitter.SplitVertically(self.ppanel, self.bpanel)
        self.Show(True)
        self.Maximize(True)  

        # bind the widgets
        self.ppanel.toggleMarker.Bind(wx.EVT_CHECKBOX, self.onToggleMarker)
        self.bpanel.toggleStart.Bind(wx.EVT_BUTTON, self.onToggleStart)        

        # Set classes
        self.data = data()


    def onToggleMarker(self, event):
        self.ppanel.draw_plot(self.data)

    def onToggleStart(self, event):

        self.data.t = arange(0.0, 1.0, 0.01)
        self.data.s = sin(2*2*pi*self.data.t)

        # plot data
        self.ppanel.draw_plot(self.data)


def main():
    app = wx.App(False)
    frame = Main_Window(None, "GUI")
    frame.Show()
    app.MainLoop()


if __name__ == "__main__" :
    main()

按下“绘图数据”按钮时会显示图表。我想要做的是在选中“显示标记”复选框时显示状态栏中的x和y位置(以与在链接中发布的代码中完成的方式类似的方式),并在它是时停止选中。但是由于状态栏的定义和不同模块中的绘图,我不确定是否可以在我的代码中执行此操作。任何提示都会受到欢迎。

1 个答案:

答案 0 :(得分:2)

通过这个问题获得完整的,有效的示例程序真是太高兴了 您只需将基本模块作为参数传递给self.ppanel = Plot_Panel(self.splitter, self)
即。

base

然后在更新状态栏时参考,请参阅下面的from matplotlib.figure import Figure from matplotlib.backends.backend_wxagg import \ FigureCanvasWxAgg as FigCanvas, \ NavigationToolbar2WxAgg as NavigationToolbar, \ wxc as wxc import pylab import wx from numpy import arange, sin, pi class data: def __init__(self): self.t = [] self.s = [] class Plot_Panel(wx.Panel): def __init__(self, parent, base): wx.Panel.__init__(self, parent) self.base = base # create some sizers mainSizer = wx.BoxSizer(wx.VERTICAL) checkSizer = wx.BoxSizer(wx.HORIZONTAL) # create figrue self.fig = Figure() self.canvas = FigCanvas(self, -1, self.fig) self.axes = self.fig.add_subplot(111) # create the widgets self.toggleMarker = wx.CheckBox(self, label="Show Marker") # layout the widgets mainSizer.Add(self.canvas, 1, wx.EXPAND) checkSizer.Add(self.toggleMarker, 0, wx.ALL, 5) mainSizer.Add(checkSizer) self.SetSizer(mainSizer) def draw_plot(self, data): # Clear the previous figure self.fig.clear() # Redraw figure self.axes = self.fig.add_subplot(111) # Define data to plot self.plot_data= self.axes.plot(data.t, data.s, linewidth=3, color='y',)[0] # Draw Cursor or not if self.toggleMarker.IsChecked(): # Note that event is a MplEvent self.canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar) self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) self.canvas.draw() def ChangeCursor(self, event): self.canvas.SetCursor(wxc.StockCursor(wx.CURSOR_BULLSEYE)) def UpdateStatusBar(self, event): if event.inaxes: x, y = event.xdata, event.ydata self.base.statusBar.SetStatusText(("x= "+str(x)+" y="+str(y))) class Button_Panel(wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) # create the widgets self.toggleStart = wx.Button(self, id=wx.ID_ANY, label="Plot data") class ProportionalSplitter(wx.SplitterWindow): def __init__(self,parent, id = -1, proportion=0.66, size = wx.DefaultSize, **kwargs): wx.SplitterWindow.__init__(self,parent,id,wx.Point(0, 0),size, **kwargs) self.SetMinimumPaneSize(50) #the minimum size of a pane. self.proportion = proportion if not 0 < self.proportion < 1: raise ValueError, "proportion value for ProportionalSplitter must be between 0 and 1." self.ResetSash() self.Bind(wx.EVT_SIZE, self.OnReSize) self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged, id=id) self.Bind(wx.EVT_PAINT, self.OnPaint) self.firstpaint = True def SplitHorizontally(self, win1, win2): if self.GetParent() is None: return False return wx.SplitterWindow.SplitHorizontally(self, win1, win2, int(round(self.GetParent().GetSize().GetHeight() * self.proportion))) def SplitVertically(self, win1, win2): if self.GetParent() is None: return False return wx.SplitterWindow.SplitVertically(self, win1, win2, int(round(self.GetParent().GetSize().GetWidth() * self.proportion))) def GetExpectedSashPosition(self): if self.GetSplitMode() == wx.SPLIT_HORIZONTAL: tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height) else: tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width) return int(round(tot * self.proportion)) def ResetSash(self): self.SetSashPosition(self.GetExpectedSashPosition()) def OnReSize(self, event): "Window has been resized, so we need to adjust the sash based on self.proportion." self.ResetSash() event.Skip() def OnSashChanged(self, event): "We'll change self.proportion now based on where user dragged the sash." pos = float(self.GetSashPosition()) if self.GetSplitMode() == wx.SPLIT_HORIZONTAL: tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().height) else: tot = max(self.GetMinimumPaneSize(),self.GetParent().GetClientSize().width) self.proportion = pos / tot event.Skip() def OnPaint(self, event): if self.firstpaint: if self.GetSashPosition() != self.GetExpectedSashPosition(): self.ResetSash() self.firstpaint = False event.Skip() class Main_Window(wx.Frame): def __init__(self, parent, title): wx.Frame.__init__(self, parent, title = title) # Create a StatusBar at the bottom of the window self.statusBar = wx.StatusBar(self, -1) self.SetStatusBar(self.statusBar) # Set plot panel self.splitter = ProportionalSplitter(self,-1, 0.85) self.ppanel = Plot_Panel(self.splitter, self) self.ppanel.SetBackgroundColour('#ffffff') # Set button panel self.bpanel = Button_Panel(self.splitter) # Set frame self.splitter.SplitVertically(self.ppanel, self.bpanel) self.Show(True) self.Maximize(True) # bind the widgets self.ppanel.toggleMarker.Bind(wx.EVT_CHECKBOX, self.onToggleMarker) self.bpanel.toggleStart.Bind(wx.EVT_BUTTON, self.onToggleStart) # Set classes self.data = data() def onToggleMarker(self, event): self.ppanel.draw_plot(self.data) def onToggleStart(self, event): self.data.t = arange(0.0, 1.0, 0.01) self.data.s = sin(2*2*pi*self.data.t) # plot data self.ppanel.draw_plot(self.data) def main(): app = wx.App(False) frame = Main_Window(None, "GUI") frame.Show() app.MainLoop() if __name__ == "__main__" : main()

参考
yarn add lodash

enter image description here