使用wxPython为单独的程序提供右键单击上下文菜单

时间:2019-03-01 15:29:05

标签: python event-handling wxpython wxpython-phoenix

我在格式化此问题的标题时遇到了麻烦,因为我不确定我是否会以正确的方式进行操作,所以让我解释一下。

我想尝试在一个我没有源代码的现有程序中添加一个右键单击上下文菜单。 wxPython通常是我选择的框架。我发现有几种方法可以做到这一点:

1)创建一个透明的wx.Frame,该框架与现有程序绑定并位于其上方,以拦截鼠标事件。如果这样做,则不确定是否可以将鼠标事件传递到基础窗口。我喜欢这个选项,因为它可以在叠加层中添加更多有用的信息。

2)创建一个无头程序,该程序全局拦截右键单击事件,并在满足某些条件时在指针位置生成上下文菜单。根据我到目前为止所做的研究,如果不连续轮询鼠标位置,这似乎是不可能的。

我想念什么?有没有更优雅的解决方案呢?使用Python甚至可能吗?

编辑:我有部分概念验证工作,如下所示:

import wx
import win32gui
import win32api
import win32con

class POC_Frame(wx.Frame):

    def __init__(self, parent):
        wx.Frame.__init__(self, parent, id=wx.ID_ANY, title='POC', pos=(0,0), size=wx.Size(500, 500), style=wx.DEFAULT_FRAME_STYLE)
        self.ToggleWindowStyle(wx.STAY_ON_TOP)

        extendedStyleSettings = win32gui.GetWindowLong(self.GetHandle(), win32con.GWL_EXSTYLE)
        win32gui.SetWindowLong(self.GetHandle(), win32con.GWL_EXSTYLE,
                               extendedStyleSettings | win32con.WS_EX_LAYERED | win32con.WS_EX_TRANSPARENT)
        win32gui.SetLayeredWindowAttributes(self.GetHandle(), win32api.RGB(0,0,0), 100, win32con.LWA_ALPHA)

        self.Bind(wx.EVT_RIGHT_DOWN, self.onRightDown)
        self.Bind(wx.EVT_RIGHT_UP, self.onRightUp)

        self.CaptureMouse()

    def onRightDown(self, event):
        print(event)

    def onRightUp(self, event):
        print(event)

app = wx.App(False)
MainFrame = POC_Frame(None)
MainFrame.Show()
app.MainLoop()

这似乎行得通,因为它将右键单击事件传递到了基础窗口,同时仍可以识别它们,但是只执行了一次。一旦失去焦点,它就会停止工作,而我尝试使焦点恢复正常的一切似乎都没有效果。

1 个答案:

答案 0 :(得分:0)

我总是很幸运的用pyHook而不是wx来挂接全局鼠标和键盘事件。这是一个简单的示例:

import pyHook
import pyHook.cpyHook  # ensure its included by cx-freeze


class ClickCatcher:
    def __init__(self):

        self.hm = None

        self._is_running = True
        self._is_cleaned_up = False
        self._is_quitting = False

        self.set_hooks()

    # this is only necessary when not using wx
    # def send_quit_message(self):
    #     import ctypes
    #     win32con_WM_QUIT = 18
    #     ctypes.windll.user32.PostThreadMessageW(self.pump_message_thread.ident, win32con_WM_QUIT, 0, 0)

    def __del__(self):
        self.quit()

    def quit(self):
        if not self._is_running:
            return
        self._is_quitting = True
        self._is_running = False
        if self.hm:
            # self.hm.UnhookKeyboard()
            self.hm.UnhookMouse()
        # self.send_quit_message()
        self._is_cleaned_up = True

    def set_hooks(self):
        self._is_running = True
        self._is_cleaned_up = False
        self.hm = pyHook.HookManager()
        self.hm.MouseRightUp = self.on_right_click
        # self.hm.HookKeyboard()
        self.hm.HookMouse()


    def on_right_click(self):
        # create your menu here
        pass

如果您未使用wx,则必须使用pythoncom.PumpMessages将鼠标和键盘事件推送到您的程序中,但是App.Mainloop()会完成相同的操作(如果您使用PumpMessages和Mainloop一起大约有一半的事件不会推送到您的程序中。

创建wx.Menu很容易。您可以使用wx.GetMousePosition()

查找鼠标坐标