Tkinter取色程序运行时窗口未创建、无法正常工作如何解决
问题根本原因
pynput的Listener.join()是阻塞式方法,代码执行到这一行时会永久停留在鼠标监听的事件循环中,后续的window.mainloop()——也就是Tkinter负责窗口渲染、事件响应的主事件循环——永远得不到执行机会,因此窗口不会弹出。
除此之外原代码还有两个隐性问题:
- pynput的事件回调运行在独立子线程中,Tkinter本身不是线程安全的,直接在子线程修改UI控件大概率会触发程序无响应、崩溃
- 鼠标移动事件触发频率极高(每秒可达上百次),每次触发都做全屏截图会导致CPU占用飙升,程序卡顿严重
修改方法
- 移除
listener.join()的阻塞写法,将监听器设置为守护线程后调用start()启动即可,不会阻塞主线程运行 - 不要在鼠标监听的子线程里直接操作UI:子线程只负责取色、把颜色值存在公共变量里,用Tkinter自带的
after()方法在主线程定时读取颜色值更新界面,规避线程安全问题 - 优化取色逻辑:调用
ImageGrab.grab()时传入鼠标所在位置的1像素范围bbox,只截取需要的单点像素,替代原来的全屏截图,大幅降低性能消耗
修改后可正常运行的代码如下:
import PIL.ImageGrab from tkinter import * from pynput.mouse import Listener # 存储当前取到的十六进制颜色值 current_color = "#FFFFFF" window = Tk() window.title("Colore in esadecimale") # 如果本地不存在trasparente.png图标文件,可注释掉下一行避免文件找不到报错 # window.call('wm', 'iconphoto', window._w, PhotoImage(file="trasparente.png")) window.geometry("500x250") window.resizable(width=False, height=False) window.configure(bg="#3C3F41") etichetta_titolo_valore = Label(window,text="Valore",font=("Ink Free",20),bg="#3C3F41",fg="white") etichetta_titolo_valore.pack(pady=(20,0)) etichetta_valore = Label(window,text="ciao",font=("Ink Free",20),bg="#3C3F41",fg="white") etichetta_valore.pack(pady=(10,0)) def mouse_move(x, y): global current_color try: # 仅截取鼠标位置1像素大小的区域,性能远优于全屏截图 rgb = PIL.ImageGrab.grab(bbox=(x, y, x+1, y+1)).getpixel((0,0)) hex_color = '#%02x%02x%02x' % (rgb) current_color = hex_color.upper() except IndexError: pass def update_ui(): etichetta_valore.config(text=current_color) # 每100毫秒更新一次界面显示,平衡流畅度和性能占用 window.after(100, update_ui) # 启动守护线程运行鼠标监听,不会阻塞主线程 listener = Listener(on_move=mouse_move, daemon=True) listener.start() # 启动界面定时更新 update_ui() # 运行Tkinter主循环 window.mainloop()
内容的提问来源于stack exchange,提问作者Forty966699669
相关产品推荐
相关产品推荐

