Предоставление контекстного меню правой кнопкой мыши для отдельной программы с использованием wxPython - PullRequest
0 голосов
/ 01 марта 2019

У меня были проблемы с форматированием заголовка этого вопроса, потому что я не был уверен, что поступлю правильно, поэтому позвольте мне объяснить.

Я хочу попытаться добавить контекстное меню, вызываемое правой кнопкой мыши, в существующую программу, для которой у меня нет исходного кода.wxPython, как правило, мой выбор.Я подумал, что есть несколько способов сделать это:

1) Создайте прозрачный wx.Frame, который привязан к существующей программе и сидит над ней, перехватывая события мыши.Если бы я сделал это, я не был уверен, можно ли передать события мыши в основное окно.Мне нравится эта опция, потому что она позволит добавлять больше полезной информации в оверлей.

2) Создайте безголовую программу, которая глобально перехватывает события щелчка правой кнопкой мыши и порождает контекстное меню в месте указателя при выполнении определенных условий.Основываясь на исследовании, которое я провел до сих пор, это не представляется возможным без постоянного опроса положения мыши.

Чего мне не хватает?Есть ли более элегантное решение для этого?Возможно ли это даже с помощью Python?

edit: у меня есть частичная проверка концепции, которая выглядит следующим образом:

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 голосов
/ 08 марта 2019

У меня всегда была удача в подключении глобальных событий мыши и клавиатуры к 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()

...