[英]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.