简体   繁体   English

如何说服鼠标右键单击弹出菜单在wxPython中显示在鼠标cursor position附近?

[英]How to convince the mouse right click popup menu to show near the mouse cursor position in wxPython?

I have a wx frame that uses a SplitterWindow (the frame has also main menu, toolbar, status bar – but this is not relevant here).我有一个使用 SplitterWindow 的 wx 框架(该框架还有主菜单、工具栏、状态栏——但这在这里不相关)。 Everything works as expected, except for the mouse right click popup menu over buttons, in that the popup menu shows up at apparently random positions over the screen – and at "negative" random positions when moving the frame to the second screen (monitor).一切都按预期工作,除了按钮上的鼠标右键单击弹出菜单,因为弹出菜单显示在屏幕上明显随机的位置 - 并且在将框架移动到第二个屏幕(监视器)时出现在“负”随机位置。 By "apparently" I mean that the popup menu position seems somewhat related to the actual button (or frame) position, but multiplied with some factor – positive on main screen and negative on the second. “显然”我的意思是弹出菜单 position 似乎与实际按钮(或框架)position 有点相关,但乘以一些因素 - 主屏幕上的正数和第二个负数。

I ran the code only on Windows 10 64bit / Python 3.9.0 64bit / wx '4.1.1 msw (phoenix) wxWidgets 3.1.5'.我只在 Windows 10 64bit / Python 3.9.0 64bit / wx '4.1.1 msw (phoenix) wxWidgets 3.1.5' 上运行代码。 The first lines of the frame code were generated via wxGlade, so perhaps this could be related in the particular way the frame code was initially generated.框架代码的第一行是通过 wxGlade 生成的,因此这可能与最初生成框架代码的特定方式有关。

I created a stripped down test code, shown below, that mimics the exact situation of the real code in terms of mouse right click popup menu.我创建了一个精简的测试代码,如下所示,它在鼠标右键单击弹出菜单方面模仿真实代码的确切情况。 In this test code I placed the button in the second pane, but it behaves the same on whatever pane.在此测试代码中,我将按钮放在第二个窗格中,但它在任何窗格上的行为都相同。

I tried the same popup menu code on other simple wx example codes but without using SplitterWindow and there the popup behavior was ok.我在其他简单的 wx 示例代码上尝试了相同的弹出菜单代码,但没有使用 SplitterWindow,并且弹出行为还可以。 What should I change or improve in the test code below?我应该在下面的测试代码中更改或改进什么?

#!/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()

It's slightly convoluted but I think you are overriding the InvokingWindow 's position for wx.Menu by passing event.GetPosition() to class ButtonContext .这有点令人费解,但我认为您通过将event.GetPosition()传递给wx.Menu ButtonContext 来覆盖 wx.Menu 的InvokingWindowclass ButtonContext

In short if you drop that parameter, event.GetPosition() and just invoke it with self.PopupMenu(ButtonContext(self)) , it will default to the parent window, the button itself.简而言之,如果您删除该参数event.GetPosition()并使用self.PopupMenu(ButtonContext(self))调用它,它将默认为父 window,即按钮本身。
The result being that it will always focus on the button that you just right clicked.结果是它将始终专注于您刚刚右键单击的按钮。

在此处输入图像描述

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

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