首页 > 解决方案 > wxPython,使用pyxhook时如何从另一个应用程序中窃取焦点?

问题描述

我尝试将 pyxhook 与 wxPython 一起使用。程序应该做的是当窗口被隐藏或最小化时,当用户按下“R_Control”时,即使另一个应用程序仍然处于焦点,wxPython 窗口也应该显示并设置焦点。但相反,它所做的只是 RequestUserAttention 在任务栏中闪烁。我已经尝试使用Raise(), Restore(),但它仍然无法正常工作。这是代码的简化版本

import wx, pyxhook

class Frame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, name='', parent=parent, title='test')
        self.panel = wx.Panel(self, wx.ID_ANY)
        self.text_input = wx.TextCtrl(self.panel)
        self.moduleSizer = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(self.moduleSizer)
        self.moduleSizer.Add(self.text_input, flag=wx.ALIGN_CENTER)
        self.text_input.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
        self.moduleSizer.Fit(self)
        self.text_input.SetFocus()

    def onKeyDown(self, event):
        if event.GetKeyCode() == wx.WXK_ESCAPE: self.Hide()
        event.Skip()

class HookMan(pyxhook.HookManager):
    def __init__(self,frame,master=None):
        pyxhook.HookManager.__init__(self,master)
        self.frame = frame
        self.KeyDown = self.key_down
        self.HookKeyboard()

    def key_down(self,event):
        if event.Key == 'Control_R':
            self.frame.Show()

if __name__ == '__main__':
    app = wx.App()
    frame = Frame(None)
    hookman = HookMan(frame)
    hookman.start()
    frame.Show()
    app.MainLoop()

我已经用 TkInter 试过了,它确实有效。root.deconify()只需将窗口设置为焦点。如何在 wxPython 中重新创建这种行为?

import pyxhook
import tkinter as tk

class Root(tk.Tk):
    def __init__(self,master=None):
        tk.Tk.__init__(self,master)
        self.title('test')
        self.text_input = tk.Entry(self)
        self.text_input.pack()
        self.bind("<Escape>", self.minimize)

    def minimize(self,event):
        self.withdraw()

class HookMan(pyxhook.HookManager):
    def __init__(self,frame,master=None):
        pyxhook.HookManager.__init__(self,master)
        self.frame = frame
        self.KeyDown = self.key_down
        self.HookKeyboard()

    def key_down(self,event):
        if event.Key == 'Control_R':
            self.frame.deiconify()

if __name__ == '__main__':
    root = Root()
    hookman = HookMan(root)
    hookman.start()
    root.text_input.focus_set()
    root.mainloop()

标签: pythonwxpythonfocuspyhook

解决方案


作为记录,您提交的代码(至少在带有 wx 4.1.0 的 Linux 上)确实有效。窗户在现有窗户下复活。
通过使用SetWindowStyle和调整对 的调用pyxhook,我们可以让这段代码正常运行。

import wx
import pyxhook

class Frame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, name='', parent=parent, title='test')
        self.SetWindowStyle(wx.STAY_ON_TOP)
        self.panel = wx.Panel(self, wx.ID_ANY)
        self.text_input = wx.TextCtrl(self.panel)
        self.moduleSizer = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(self.moduleSizer)
        self.moduleSizer.Add(self.text_input, flag=wx.ALIGN_CENTER)
        self.text_input.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
        self.Bind(wx.EVT_CLOSE, self.onExit)
        self.moduleSizer.Fit(self)
        self.text_input.SetFocus()
        self.hookman = HookMan(self)
        self.hookman.start()

    def onKeyDown(self, event):
        if event.GetKeyCode() == wx.WXK_ESCAPE:
            self.Hide()
        event.Skip()

    def onExit(self, event):
        self.hookman.cancel()
        self.hookman.join()
        self.Destroy()

class HookMan(pyxhook.HookManager):
    def __init__(self,parent,master=None):
        pyxhook.HookManager.__init__(self,master)
        self.frame = parent
        self.KeyDown = self.key_down

    def key_down(self,event):
        if event.Key == 'Control_R':
            self.frame.Show()
    
    def close(self):
        self.close()

if __name__ == '__main__':
    app = wx.App()
    frame = Frame(None)
    frame.Show()
    app.MainLoop()

推荐阅读