如何说服鼠标右键单击弹出菜单显示在 wxPython 中鼠标光标位置附近?
How to convince the mouse right click popup menu to show near the mouse cursor position in wxPython?
我有一个使用 SplitterWindow 的 wx 框架(该框架还有主菜单、工具栏、状态栏——但这与此处无关)。一切都按预期工作,除了鼠标右键单击按钮上的弹出菜单,因为弹出菜单明显显示在屏幕上的 运行dom 位置 - 移动时显示在“负”运行dom 位置框架到第二个屏幕(显示器)。 “显然”我的意思是弹出菜单的位置似乎与实际按钮(或框架)位置有些相关,但乘以一些因素 - 在主屏幕上为正,在第二个屏幕上为负。
I 运行 代码仅适用于 Windows 10 64 位/Python 3.9.0 64 位/wx '4.1.1 msw (phoenix) wxWidgets 3.1.5'。框架代码的第一行是通过wxGlade生成的,所以这可能与框架代码最初生成的特定方式有关。
我创建了一个精简的测试代码,如下所示,它模拟了真实代码在鼠标右键单击弹出菜单方面的确切情况。在此测试代码中,我将按钮放在第二个窗格中,但它在任何窗格中的行为都相同。
我在其他简单的 wx 示例代码上尝试了相同的弹出菜单代码,但没有使用 SplitterWindow,并且弹出行为正常。我应该在下面的测试代码中更改或改进什么?
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.SetSize((400, 300))
self.SetTitle("test frame")
sizer_0 = wx.BoxSizer(wx.HORIZONTAL)
self.window_1 = wx.SplitterWindow(self, wx.ID_ANY)
self.window_1.SetMinimumPaneSize(20)
sizer_0.Add(self.window_1, 1, wx.EXPAND, 0)
self.pane_1 = wx.Panel(self.window_1, wx.ID_ANY)
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
self.pane_2 = wx.Panel(self.window_1, wx.ID_ANY)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
self.button = wx.Button(self.pane_2, wx.ID_ANY, "test button")
sizer_2.Add(self.button, 0, 0, 0)
self.pane_1.SetSizer(sizer_1)
self.pane_2.SetSizer(sizer_2)
self.window_1.SplitVertically(self.pane_1, self.pane_2)
self.SetSizer(sizer_0)
self.Layout()
self.Bind(wx.EVT_CONTEXT_MENU, self.OnButtonContextMenu, self.button)
def OnButtonContextMenu(self, event):
self.PopupMenu(ButtonContext(self), event.GetPosition())
##
class ButtonContext(wx.Menu):
def __init__(self, parent):
super(ButtonContext, self).__init__()
self.parent = parent
button_popup = wx.MenuItem(self, wx.ID_ANY, 'test popup')
self.Append(button_popup)
self.Bind(wx.EVT_MENU, self.button_action, button_popup)
def button_action(self, event):
event.Skip()
##
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, wx.ID_ANY, "")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
##
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()
它有点令人费解,但我认为您通过将 event.GetPosition()
传递给 class ButtonContext
来覆盖 InvokingWindow
对 wx.Menu
的位置。
简而言之,如果您删除该参数 event.GetPosition()
并仅使用 self.PopupMenu(ButtonContext(self))
调用它,它将默认为父 window,即按钮本身。
结果是它将始终关注您刚刚右键单击的按钮。
我有一个使用 SplitterWindow 的 wx 框架(该框架还有主菜单、工具栏、状态栏——但这与此处无关)。一切都按预期工作,除了鼠标右键单击按钮上的弹出菜单,因为弹出菜单明显显示在屏幕上的 运行dom 位置 - 移动时显示在“负”运行dom 位置框架到第二个屏幕(显示器)。 “显然”我的意思是弹出菜单的位置似乎与实际按钮(或框架)位置有些相关,但乘以一些因素 - 在主屏幕上为正,在第二个屏幕上为负。
I 运行 代码仅适用于 Windows 10 64 位/Python 3.9.0 64 位/wx '4.1.1 msw (phoenix) wxWidgets 3.1.5'。框架代码的第一行是通过wxGlade生成的,所以这可能与框架代码最初生成的特定方式有关。
我创建了一个精简的测试代码,如下所示,它模拟了真实代码在鼠标右键单击弹出菜单方面的确切情况。在此测试代码中,我将按钮放在第二个窗格中,但它在任何窗格中的行为都相同。
我在其他简单的 wx 示例代码上尝试了相同的弹出菜单代码,但没有使用 SplitterWindow,并且弹出行为正常。我应该在下面的测试代码中更改或改进什么?
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import wx
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.SetSize((400, 300))
self.SetTitle("test frame")
sizer_0 = wx.BoxSizer(wx.HORIZONTAL)
self.window_1 = wx.SplitterWindow(self, wx.ID_ANY)
self.window_1.SetMinimumPaneSize(20)
sizer_0.Add(self.window_1, 1, wx.EXPAND, 0)
self.pane_1 = wx.Panel(self.window_1, wx.ID_ANY)
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
self.pane_2 = wx.Panel(self.window_1, wx.ID_ANY)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
self.button = wx.Button(self.pane_2, wx.ID_ANY, "test button")
sizer_2.Add(self.button, 0, 0, 0)
self.pane_1.SetSizer(sizer_1)
self.pane_2.SetSizer(sizer_2)
self.window_1.SplitVertically(self.pane_1, self.pane_2)
self.SetSizer(sizer_0)
self.Layout()
self.Bind(wx.EVT_CONTEXT_MENU, self.OnButtonContextMenu, self.button)
def OnButtonContextMenu(self, event):
self.PopupMenu(ButtonContext(self), event.GetPosition())
##
class ButtonContext(wx.Menu):
def __init__(self, parent):
super(ButtonContext, self).__init__()
self.parent = parent
button_popup = wx.MenuItem(self, wx.ID_ANY, 'test popup')
self.Append(button_popup)
self.Bind(wx.EVT_MENU, self.button_action, button_popup)
def button_action(self, event):
event.Skip()
##
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, wx.ID_ANY, "")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
##
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()
它有点令人费解,但我认为您通过将 event.GetPosition()
传递给 class ButtonContext
来覆盖 InvokingWindow
对 wx.Menu
的位置。
简而言之,如果您删除该参数 event.GetPosition()
并仅使用 self.PopupMenu(ButtonContext(self))
调用它,它将默认为父 window,即按钮本身。
结果是它将始终关注您刚刚右键单击的按钮。