如何多次显示 wx.TipWindow?

How can I show a wx.TipWindow multiple times?

我试图在滚轮更改 RadioBox 项目时在鼠标位置显示 wx.TipWindow(我希望新选择的项目显示在鼠标处)。

这就是我所拥有的:

wx.TipWindow(self, self.rdb.GetString(nxt)) <- Works perfectly. Self is an instance of wx.Frame

但是,如果上面的行被调用不止一次(即,我滚动不止一次~5 次),它会不断地在彼此之上生成新的 windows。最终,程序因以下错误而崩溃:

Traceback (most recent call last):
  File "C:\Users\Seth\anaconda3\envs\DLC-GPU\lib\site-packages\matplotlib\backends\backend_wx.py", line 989, in _onMouseWheel
    x = evt.GetX()
AttributeError: 'MouseEvent' object has no attribute 'GetX'

我不能让它工作吗?我尝试在显示下一个之前关闭并销毁 TipWindow,但出现同样的错误。

我曾想过“为什么不自己做”,但真烦人哈哈。

显示 wx.TipWindow 的代码块:

    def MouseWheel(self, event):
        assert isinstance(event, wx.MouseEvent)
        whlRot = event.GetWheelRotation()

        if whlRot < 0:
            nxt = self.rdb.GetSelection() + 1
            if nxt < self.rdb.GetCount():
                self.rdb.SetSelection(nxt) # Sets the next object in the RadioBox
                wx.TipWindow(self, self.rdb.GetString(nxt))

        if whlRot > 0:
            prv = self.rdb.GetSelection() - 1
            if prv >= 0:
                self.rdb.SetSelection(prv) # Sets the previous object in the RadioBox
                wx.TipWindow(self, self.rdb.GetString(prv))

正如您所说的“...滚轮更改 RadioBox 项目...”但这不是单选框的本机功能,它是您通过我们看不到的代码设计的。

我假设它看起来像这样:

import wx

class RadioBoxFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, 'Radio Box Frame', size=(400, 400))
        
        panel = wx.Panel(self, -1, pos=(10,10), size=(300,300), style=wx.BORDER_RAISED)
        sampleList = ['Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine']
        self.option=wx.RadioBox(panel, -1, "Select an option", pos=(10, 10), size=wx.DefaultSize, choices=sampleList, majorDimension=3, style=wx.RA_SPECIFY_COLS)
        self.Bind(wx.EVT_RADIOBOX, self.getOption)
        panel.Bind(wx.EVT_MOUSEWHEEL, self.getWheelOption)

        for i in range(len(sampleList)):
            self.option.SetItemToolTip(i, "Option "+sampleList[i]) 
        
        self.CreateStatusBar()
        self.SetStatusText("Status area")
        self.Show()
        
    def getWheelOption(self, event):
        assert isinstance(event, wx.MouseEvent)
        whlRot = event.GetWheelRotation()

        if whlRot < 0:
            nxt = self.option.GetSelection() + 1
        else:
            nxt = self.option.GetSelection() - 1
        if nxt > self.option.GetCount() - 1:
            nxt = 0
        if nxt < 0:
            nxt = self.option.GetCount() - 1
        self.option.SetSelection(nxt) # Sets the next object in the RadioBox
        txt = "Option " + self.option.GetString(nxt) + " Selected"
        tw = wx.TipWindow(self, txt)
        tw.SetBoundingRect(wx.Rect(1,1,1,1)) #restrict action required to cancel tipwindow
        self.SetStatusText(txt)
        
    def getOption(self, event):
        state1 = self.option.GetSelection()
        txt = self.option.GetString(state1)
        self.SetStatusText(txt+" is Selected")

if __name__ == '__main__':
    app = wx.App()
    RadioBoxFrame()
    app.MainLoop()

产生以下内容:

稍微玩一下这段代码,你会发现你仍然遇到同样的错误,因为在 Linux 上使用 wxPython 4.1.1,上面的代码不会给出错误。如果上述代码失败,您可能需要查看您的环境。

终于找到了不需要更新 wxPython 的答案(因为这破坏了代码中不属于我的东西)。

这是我最后做的:

 if self.popUp is None:
     self.popUp = wx.TipWindow(self, wht, maxLength=1000000)
 else:
     try: # Try is needed for if the TipWindow is closed by clicking elsewhere
        self.popUp.Show(show=False) # This was the key line. For some reason, hiding the window was required before destroying
        self.popUp.Destroy()
     except:
        pass
    self.popUp = wx.TipWindow(self, wht, maxLength=1000000)

这非常有效,是我想要的结果。

我注意到 wxPython 4.1.0 和 4.1.1 之间 Windows 上的不同 TipWindow 行为。在 4.1.1 版本中,TipWIndow 在移出 BoundingRect 时不会被销毁。与上述类似的问题,但不同之处在于我仅在升级到 4.1.1 时遇到此问题。请参阅下面的片段以重现此行为 + 4.1.1 中的效果图片。有没有人有类似的经历,知道解决办法是什么?

import wx


class RadioBoxFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1)
        panel = wx.Panel(self, -1, pos=(10, 10))
        sampleList = ['Zero', 'One', 'Two']
        self.option = wx.RadioBox(panel, -1, "Select an option", pos=(10, 10),
                                  size=wx.DefaultSize, choices=sampleList,
                                  majorDimension=3)
        self.Bind(wx.EVT_RADIOBOX, self.getOption)
        panel.Bind(wx.EVT_MOUSEWHEEL, self.getWheelOption)

        self.Show()

    def getWheelOption(self, event):
        whlRot = event.GetWheelRotation()
        if whlRot < 0:
            nxt = self.option.GetSelection() + 1
        else:
            nxt = self.option.GetSelection() - 1

        if nxt > self.option.GetCount() - 1:
            nxt = 0
        if nxt < 0:
            nxt = self.option.GetCount() - 1

        self.option.SetSelection(nxt)
        txt = "Option " + self.option.GetString(nxt) + " Selected"
        tw = wx.TipWindow(self, txt)
        tw.SetBoundingRect(wx.Rect(1, 1, 1, 1))

    def getOption(self, event):
        state1 = self.option.GetSelection()


if __name__ == '__main__':
    app = wx.App()
    RadioBoxFrame()
    app.MainLoop()