简体   繁体   English

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

[英]Providing right-click context menu for a separate program using wxPython

I was having trouble formatting the title of this question, because I wasn't sure I'm going about this the right way, so let me explain. 我在格式化此问题的标题时遇到了麻烦,因为我不确定我的解决方法是否正确,所以让我解释一下。

I want to try and add a right-click context menu to an existing program for which I don't have the source code. 我想尝试将右键单击上下文菜单添加到我没有源代码的现有程序中。 wxPython is generally my framework of choice. wxPython通常是我选择的框架。 I figured there was a couple ways of doing this: 我发现有两种方法可以做到这一点:

1) Create a transparent wx.Frame which is tied to and sits on top of the existing program, intercepting mouse events. 1)创建一个透明的wx.Frame,该框架绑定到现有程序并位于其上方,以拦截鼠标事件。 If I did this, I wasn't sure if the mouse events could then be passed to the underlying window. 如果这样做,则不确定是否可以将鼠标事件传递到基础窗口。 I like this option, because it would allow adding more useful information in the overlay. 我喜欢这个选项,因为它可以在叠加层中添加更多有用的信息。

2) Create a headless program which globally intercepts right-click events, and spawns the context menu at the pointer location when certain conditions are met. 2)创建一个无头程序,该程序全局拦截右键单击事件,并在满足某些条件时在指针位置生成上下文菜单。 Based on the research I've done so far, this didn't seem possible without continuously polling for mouse position. 根据我到目前为止所做的研究,如果不连续轮询鼠标位置,这似乎是不可能的。

What am I missing? 我想念什么? Is there a more elegant solution for this? 有没有更优雅的解决方案呢? Is this even possible using Python? 使用Python甚至可能吗?

edit: I have a partial proof-of-concept working which looks like this: 编辑:我有一个部分的概念验证工作,如下所示:

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()

This seems to work OK, as it passes the right click events to the underlying window, while still recognizing them, but it only does it exactly once. 这似乎行得通,因为它将右键单击事件传递到了基础窗口,同时仍可以识别它们,但只执行了一次。 As soon as it loses focus, it stops working and nothing I've tried to return focus to it seems to work. 一旦失去焦点,它就会停止工作,而我尝试使焦点恢复正常的一切似乎都没有效果。

I've always had better luck hooking global mouse and keyboard events with pyHook rather than wx. wH相比,我总是有更好的运气用pyHook钩住全局鼠标和键盘事件。 Here is a simple example: 这是一个简单的示例:

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

If you weren't using wx , you'd have to use pythoncom.PumpMessages to push mouse and keyboard events to you program, but App.Mainloop() accomplishes the same thing (if you use PumpMessages and Mainloop together about half of the events won't be push to your program). 如果您未使用wx ,则必须使用pythoncom.PumpMessages将鼠标和键盘事件推送到您的程序,但是App.Mainloop()完成相同的操作(如果您将PumpMessages和Mainloop一起使用,则约占一半)不会推送到您的程序)。

Creating a wx.Menu is easy enough. 创建一个wx.Menu很简单。 You can find the mouse coordinates using wx.GetMousePosition() 您可以使用wx.GetMousePosition()找到鼠标坐标

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

相关问题 通过在 Windows 中右键单击“打开方式”上下文菜单将文件传递给 Python,然后在另一个程序中打开 - Pass a file to Python via the Right-Click 'Open With' context menu in windows, to then open in another program 如何通过Windows右键单击上下文菜单将多个参数传递给python程序 - How to pass multiple arguments to a python program via windows right-click context menu PySide QPushButton右键单击上下文菜单未按按钮分配 - PySide QPushButton Right-click context menu not assigning per button wxPython的; 右键单击任何文本字段中的上下文菜单是否可以使程序崩溃并显示错误“ m_menuDepth> 0”? - wxPython; right click context menu in any text field can crash program with the error “m_menuDepth > 0”? 在Firefox的右键菜单中添加选项 - Add option to right-click menu in Firefox 使用 PyGTK 的右键单击菜单(上下文菜单) - Right Click Menu (context menu) using PyGTK wxPython:用鼠标右键单击不会设置焦点 - wxPython: Right-click with mouse does not set focus 如何在使用适配器时在TraitsUI TreeView中启用右键菜单? - How to enable right-click menu in TraitsUI TreeView when using adaptors? 从没有菜单的选择中右键单击复制 - Right-click copy from selection without menu 将我的python代码转换为Windows应用程序(右键菜单) - convert my python code to windows application (right-click menu)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM