鱼C论坛

 找回密码
 立即注册
查看: 458|回复: 9

[已解决]问题描述在正文开头,望不吝赐教🙏

[复制链接]
发表于 2024-3-14 14:52:25 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
#这是一个简略的程序,在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()
最佳答案
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 小助理,如未能正确解答您的问题,请继续追问。

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-3-14 21:06:13 | 显示全部楼层
什么是钩子管理对象?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-15 10:07:41 | 显示全部楼层
FishC 发表于 2024-3-14 14:52
你好!看起来你的程序在运行过程中卡死了,这可能与线程的使用不当有关。在Python中,tkinter库是单线程的 ...

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

使用道具 举报

发表于 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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-3-15 10:10:04 | 显示全部楼层
清風 发表于 2024-3-14 21:06
什么是钩子管理对象?

网络释义:钩子函数是一种回调函数,它允许我们在程序执行的特定点上注入自定义的代码。 在Python中,钩子函数通常用于拦截事件、修改数据或扩展功能。 通过使用钩子函数,我们可以在不修改源代码的情况下改变程序的行为。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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


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

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

好的 谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

感谢大神的回复,问题已经解决。将100毫秒延长到1000毫秒后完美运行,卡死的原因应该是电脑性能不足。后面看看能不能将检测程序独立出来。再次感谢。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-15 10:10

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表