wxPython, как украсть фокус из другого приложения при использовании pyxhook?

#python #wxpython #focus #pyhook

#python #wxpython #фокус #pyhook

Вопрос:

Я пытался использовать pyxhook с wxPython. Предполагается, что программа должна делать, когда окно скрыто или свернуто, когда пользователь нажимает «R_Control», даже когда другое приложение все еще находится в фокусе, окно wxPython должно отображаться и находиться в фокусе. Но вместо этого он просто запросил userattention, мигая на панели задач. Я пробовал использовать 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()
  

Комментарии:

1. Вы уверены? Запустите его, не имея ничего на рабочем столе, оно вполне может находиться под другими окнами. Если не добавить свою платформу к вопросу, это может иметь значение.

2. Мой плохой .. после того, как я повозился с некоторыми настройками, я понял, что речь идет о моей среде рабочего стола. Я использую KDE Plasma 5.18, и есть опция предотвращения кражи фокуса. Программа работает нормально, когда я отключаю предотвращение кражи фокуса.

Ответ №1:

Для справки, представленный вами код (по крайней мере, в Linux с wx 4.1.0) действительно работал. Окно было восстановлено под существующими окнами.
Используя 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()
  

Комментарии:

1. Мой плохой .. после того, как я повозился с некоторыми настройками, я понял, что речь идет о моей среде рабочего стола. Я использую KDE Plasma 5.18, и есть опция предотвращения кражи фокуса. Программа работает нормально, когда я отключаю предотвращение кражи фокуса. Спасибо…

2. @RunningRay Нет проблем, обратите внимание на мое изменение в коде pyxhook, которое правильно закрывает поток и позволяет вашему коду завершаться, а не зависать.