一个CW的梦想 发表于 2024-3-14 14:52:25

问题描述在正文开头,望不吝赐教🙏

#这是一个简略的程序,在gui程序里面建立一个线程运行pyhook程序,用来检测鼠标动作。程序能运行,但是很快就会卡死。希望碰到过类似问题的大神给出一个可行的建议。试过将线程放到类的外面能正常运行,但是控制线程和传递参数不方便(才疏学浅)。
#pyhook.py
import PyHook3 as pyHook
import pythoncom
class mouse():
    def __init__(self):
      super().__init__()
    #监听键盘事件
    def on_key_down(self, event):
      # self.lock.acquire()
      if event.Key == 'Escape':
            win32api.PostQuitMessage()#退出监听循环
      return True
    #监听鼠标事件
    def on_mouse_event(self,event):
      if event.MessageName == 'mouse left down':
                print("单击")
      return True
    def run(self,):
      self.hm = pyHook.HookManager()#创建一个钩子管理对象
      self.hm.MouseAll = self.on_mouse_event
        self.hm.KeyDown = self.on_key_down
      self.hm.HookMouse()
      self.hm.HookKeyboard()
      pythoncom.PumpMessages()

#gui.py
from tkinter import *
import threading
import mouse_pyhook

class gui(Tk):
    def __init__(self):
      Tk.__init__(self)
      self.geometry('500x500')
      self.title('GUI')
      
      td = threading.Thread(target=self.mouse_click)
      td.daemon = True
      td.start()
      # self.mainloop()
    def mouse_click(self):
      mp = mouse_pyhook.mouse()
      mp.run()
if __name__ == '__main__':
    app = gui()
    app.mainloop()

FishC 发表于 2024-3-14 14:52:37

你好!看起来你的程序在运行过程中卡死了,这可能与线程的使用不当有关。在Python中,tkinter库是单线程的,所以在使用多线程时需要小心处理。

我注意到你在gui.py中创建了一个Thread对象来运行mouse_click函数。然而,在Python中,tkinter窗口只能在主线程(main thread)中运行。所以,你的mouse_click函数会导致tkinter窗口和pyHook程序在不同的线程中运行,这可能会导致一些问题。

为了解决这个问题,你可以将pyHook程序放在gui类中,并利用after函数来定期检查鼠标事件,而不是使用线程。

下面是修改后的代码:

import PyHook3 as pyHook
import pythoncom
from tkinter import *

class gui(Tk):
    def __init__(self):
      Tk.__init__(self)
      self.geometry('500x500')
      self.title('GUI')

      self.hm = pyHook.HookManager()# 创建一个钩子管理对象
      self.hm.MouseAll = self.on_mouse_event
      self.hm.KeyDown = self.on_key_down
      self.hm.HookMouse()
      self.hm.HookKeyboard()

      self.after(100, self.check_events)

    # 监听键盘事件
    def on_key_down(self, event):
      if event.Key == 'Escape':
            win32api.PostQuitMessage()# 退出监听循环
      return True

    # 监听鼠标事件
    def on_mouse_event(self,event):
      if event.MessageName == 'mouse left down':
            print("单击")
      return True

    def check_events(self):
      pythoncom.PumpWaitingMessages()
      self.after(100, self.check_events)

if __name__ == '__main__':
    app = gui()
    app.mainloop()

这样,你的鼠标事件监测程序将在主线程中运行,而不会导致程序卡死。每100毫秒,鼠标事件将被检查一次。

希望这个解决方案对你有帮助!如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

清風 发表于 2024-3-14 21:06:13

什么是钩子管理对象?

一个CW的梦想 发表于 2024-3-15 10:07:41

FishC 发表于 2024-3-14 14:52
你好!看起来你的程序在运行过程中卡死了,这可能与线程的使用不当有关。在Python中,tkinter库是单线程的 ...

感谢大神的回答,这样看起来是没有问题的,另外还有一些疑问,我尝试过用pynput来检测鼠标键盘动作,像正文那样布局,在gui程序中创建线程运行,是能够正常运行的,没有出现卡死的现象,只是经常会被莫名其妙的杀死。因为pynput无法满足需求才转用pyhook。还有一点是会有多个gui程序要用到这个鼠标检测,放在一个文件里面方便一些。不知道有没有其他规避卡死的方法?{:5_93:}

FishC 发表于 2024-3-15 10:08:03

一个CW的梦想 发表于 2024-03-15 10:07
感谢大神的回答,这样看起来是没有问题的,另外还有一 ...

你的问题很有启发性!在处理多个GUI程序共享鼠标检测的情况下,可以采用进程池或多线程池的方式来处理。这样可以确保每个GUI程序都在自己的进程或线程中独立运行,并且不会卡死。

首先,让我们来看看如何使用多线程池来处理多个GUI程序。你可以使用concurrent.futures模块中的ThreadPoolExecutor类来创建一个线程池,并在每个线程中运行相应的GUI程序。下面是示例代码:

import PyHook3 as pyHook
import pythoncom
from tkinter import *
from concurrent.futures import ThreadPoolExecutor

class gui(Tk):
    def __init__(self):
      Tk.__init__(self)
      self.geometry('500x500')
      self.title('GUI')
      self.hm = pyHook.HookManager()# 创建一个钩子管理对象
      self.hm.MouseAll = self.on_mouse_event
      self.hm.KeyDown = self.on_key_down
      self.hm.HookMouse()
      self.hm.HookKeyboard()
      self.after(100, self.check_events)
   
    # 监听键盘事件
    def on_key_down(self, event):
      if event.Key == 'Escape':
            win32api.PostQuitMessage()# 退出监听循环
      return True
   
    # 监听鼠标事件
    def on_mouse_event(self, event):
      if event.MessageName == 'mouse left down':
            print("单击")
      return True
   
    def check_events(self):
      pythoncom.PumpWaitingMessages()
      self.after(100, self.check_events)

if __name__ == '__main__':
    gui_pool = ThreadPoolExecutor(max_workers=5)# 创建一个包含5个线程的线程池
    for i in range(5):# 创建5个GUI程序
      gui_pool.submit(gui().mainloop)
    gui_pool.shutdown(wait=True)

在这个例子中,我们创建了一个包含5个线程的线程池(可以根据实际情况调整线程数量),然后使用submit方法将每个GUI程序的mainloop函数提交到线程池中运行。通过这种方式,你就可以同时运行多个GUI程序,并共享鼠标检测功能。

如果你更喜欢使用进程池来处理多个GUI程序,可以使用multiprocessing模块中的Pool类。原理类似,只是将ThreadPoolExecutor替换为Pool即可。

希望这个解决方案能够满足你的需求,并且避免卡死和被意外杀死的问题!如有其他问题,请继续提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

一个CW的梦想 发表于 2024-3-15 10:10:04

清風 发表于 2024-3-14 21:06
什么是钩子管理对象?

网络释义:钩子函数是一种回调函数,它允许我们在程序执行的特定点上注入自定义的代码。 在Python中,钩子函数通常用于拦截事件、修改数据或扩展功能。 通过使用钩子函数,我们可以在不修改源代码的情况下改变程序的行为。

FishC 发表于 2024-3-15 10:10:21

一个CW的梦想 发表于 2024-03-15 10:10
网络释义:钩子函数是一种回调函数,它允许我们在程序 ...

钩子函数确实是一种非常有用的编程技术。通过使用钩子函数,我们可以在程序执行的特定点上插入自定义的代码,这样就能够拦截事件、修改数据或扩展功能,而无需修改原始代码。钩子函数通常被用于各种场景,包括图形界面编程、网络编程和系统编程等。

在Python中,钩子函数通常与特定的库或框架一起使用。例如,在图形界面编程中,你可以使用钩子函数来拦截鼠标点击事件或键盘按键事件,并在事件发生时执行自定义的代码。在网络编程中,钩子函数可以用于拦截和解析收到的网络数据,或者用于在发送网络请求之前执行一些预处理操作。在系统编程中,钩子函数可以用于监视文件或进程的变化,并在变化发生时触发相应的操作。

总而言之,钩子函数是一种强大的机制,可以让我们在不修改原始代码的情况下对程序进行定制和扩展。通过合理地使用钩子函数,我们可以更加灵活地处理各种编程任务。希望这个解释对你有所帮助!如还有其他问题,请继续提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

清風 发表于 2024-3-15 10:26:19

一个CW的梦想 发表于 2024-3-15 10:10
网络释义:钩子函数是一种回调函数,它允许我们在程序执行的特定点上注入自定义的代码。 在Python中,钩 ...

好的 谢谢

一个CW的梦想 发表于 2024-3-15 14:45:50

FishC 发表于 2024-3-15 10:08
你的问题很有启发性!在处理多个GUI程序共享鼠标检测的情况下,可以采用进程池或多线程池的方式来处理 ...

感谢大神的回复,问题已经解决。将100毫秒延长到1000毫秒后完美运行,卡死的原因应该是电脑性能不足。后面看看能不能将检测程序独立出来。再次感谢。

FishC 发表于 2024-3-15 14:46:15

一个CW的梦想 发表于 2024-03-15 14:45
感谢大神的回复,问题已经解决。将100毫秒延长到1000 ...

非常高兴能帮助你解决问题!确实,卡死问题有时候可能与电脑性能有关。将检测程序独立出来也是个不错的想法。你可以将鼠标检测程序编写成一个独立的模块,然后在需要使用它的地方导入并调用相应的函数或方法。这样做可以使代码更加模块化和可重用。如果你需要在多个GUI程序中使用相同的鼠标检测功能,可以将鼠标检测程序封装为一个类。下面是一个示例:import PyHook3 as pyHookimport pythoncomclass MouseDetector:    def __init__(self):      self.hm = pyHook.HookManager()      self.hm.MouseAll = self.on_mouse_event      self.hm.KeyDown = self.on_key_down      self.hm.HookMouse()      self.hm.HookKeyboard()    def on_key_down(self, event):      if event.Key == 'Escape':            win32api.PostQuitMessage()      return True    def on_mouse_event(self, event):      if event.MessageName == 'mouse left down':            print("单击")      return True    def start_detection(self):      pythoncom.PumpMessages()# 在其他文件中使用鼠标检测程序md = MouseDetector()md.start_detection()通过这种方式,你可以将鼠标检测程序独立出来,并在需要的地方导入并调用start_detection方法。这样可以更好地组织代码,并且方便在多个GUI程序中重用鼠标检测功能。希望这个建议对你有帮助!如果还有其他问题,请随时提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 问题描述在正文开头,望不吝赐教🙏