每当我做几次“ wx”操作时,无论单击按钮,菜单,在文本区域内,等等,我的python应用程序都停止响应。
这似乎与我在程序其他地方使用Windows挂钩有关。当两者一起使用时,情况就会变糟。
尽管在实际应用程序的上下文之外,下面的示例可能没有多大意义,但这是我作为最小示例提出的。我竭尽所能来尝试以最小的额外复杂性诊断问题。
从工作线程中调用的第二个Windows消息泵似乎确实是实现它的因素。如果我将其注释掉,则该应用程序无法挂起...或执行任何有用的操作...钩子需要一个泵,并且我无法将其放在UI线程上,否则钩子将超时,这导致我首先这个POC ...
如果运行此程序并单击鼠标十次左右,您会发现文本块出现乱码,然后应用程序挂起。有谁知道为什么?
我正在使用
(更新)我也尝试了相同的结果
我们在实际的应用程序中使用它们,因为我的更高版本希望继续支持Windows XP(完全不同的对话)
main.py
import wx
from twisted.internet import wxreactor
from windows_hooks import WindowsHooksWrapper
from main_window import MainWindow
def main():
hook_wrapper = WindowsHooksWrapper()
hook_wrapper.start()
app = wx.App(False)
frame = MainWindow(None, 'Hooks Testing', hook_wrapper)
from twisted.internet import reactor
reactor.registerWxApp(app)
reactor.run()
hook_wrapper.stop()
if __name__ == "__main__":
wxreactor.install()
main()
windows_hooks.py
import pyHook
import threading
import pythoncom
class WindowsHooksWrapper(object):
def __init__(self):
self.hook_manager = None
self.started = False
self.thread = threading.Thread(target=self.thread_proc)
self.window_to_publish_to = None
print "HookWrapper created on Id {}".format(threading.current_thread().ident)
def __del__(self):
self.stop()
def start(self):
if self.started:
self.stop()
self.started = True
self.thread.start()
def stop(self):
if not self.started:
return
self.started = False
self.thread.join()
def on_mouse_event(self, event):
"""
Called back from pyHooks library on a mouse event
:param event: event passed from pyHooks
:return: True if we are to pass the event on to other hooks and the process it was intended
for. False to consume the event.
"""
if self.window_to_publish_to:
from twisted.internet import reactor
reactor.callFromThread(self.window_to_publish_to.print_to_text_box, event)
return True
def thread_proc(self):
print "Thread started with Id {}".format(threading.current_thread().ident)
# Evidently, the hook must be registered on the same thread with the windows msg pump or
# it will not work and no indication of error is seen
# Also note that for exception safety, when the hook manager goes out of scope, the
# documentation says that it unregisters all outstanding hooks
self.hook_manager = pyHook.HookManager()
self.hook_manager.MouseAll = self.on_mouse_event
self.hook_manager.HookMouse()
while self.started:
pythoncom.PumpMessages()
print "Thread exiting..."
self.hook_manager.UnhookMouse()
self.hook_manager = None
main_window.py
import threading
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, title, hook_manager):
wx.Frame.__init__(self, parent, title=title, size=(800, 600))
self.hook_manager = hook_manager
self.CreateStatusBar()
menu_file = wx.Menu()
menu_item_exit = menu_file.Append(wx.ID_EXIT, "E&xit", " Terminate the program")
menu_help = wx.Menu()
menu_item_about = menu_help.Append(wx.ID_ABOUT, "&About", " Information about this program")
menu_bar = wx.MenuBar()
menu_bar.Append(menu_file, "&File")
menu_bar.Append(menu_help, "&Help")
self.SetMenuBar(menu_bar)
self.panel = MainPanel(self, hook_manager)
self.Bind(wx.EVT_MENU, self.on_about, menu_item_about)
self.Bind(wx.EVT_MENU, self.on_exit, menu_item_exit)
self.Show(True)
def on_about(self, e):
dlg = wx.MessageDialog(self, "A window to test Windows Hooks", "About Test Windows Hooks",
wx.OK)
dlg.ShowModal()
dlg.Destroy()
def on_exit(self, e):
self.Close(True)
class MainPanel(wx.Panel):
def __init__(self, parent, hook_manager):
self.hook_manager = hook_manager
hook_manager.window_to_publish_to = self
self.consuming = False
wx.Panel.__init__(self, parent)
self.textbox = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY)
self.horizontal = wx.BoxSizer()
self.horizontal.Add(self.textbox, proportion=1, flag=wx.EXPAND)
self.sizer_vertical = wx.BoxSizer(wx.VERTICAL)
self.sizer_vertical.Add(self.horizontal, proportion=1, flag=wx.EXPAND)
self.SetSizerAndFit(self.sizer_vertical)
self.called_back_count = 0
def print_to_text_box(self, event):
self.called_back_count += 1
print "Printing message {} on Thread with Id {}".format(self.called_back_count,
threading.current_thread().ident)
self.textbox.AppendText('MessageName: {}\n'.format(event.MessageName))
self.textbox.AppendText('Message: {}\n'.format(event.Message))
self.textbox.AppendText('Time: {}\n'.format(event.Time))
self.textbox.AppendText('Window: {}\n'.format(event.Window))
self.textbox.AppendText('WindowName: {}\n'.format(event.WindowName))
self.textbox.AppendText('Position: {}\n'.format(event.Position))
self.textbox.AppendText('Wheel: {}\n'.format(event.Wheel))
self.textbox.AppendText('Injected: {}\n'.format(event.Injected))
self.textbox.AppendText('---\n')
我还尝试了不使用Twisted的版本,而是使用wxPostEvent和自定义事件,但是我们怀疑这可能是问题所在,所以我将其更改为使用Twisted,但这仍然没有好处。
我将稍后发布一个编辑过的列表。