如何实现Tkinter窗口与OpenCV窗口同时运行并正常刷新?
解决Tkinter与OpenCV窗口同时运行的问题
问题根源
原代码里root.mainloop()是阻塞式的事件循环,会卡住后续代码执行,导致OpenCV窗口必须等Tkinter窗口关闭后才启动;如果强行把OpenCV循环放到主线程,又会占用主线程资源,让Tkinter的事件处理无法正常进行,出现窗口刷新卡顿的情况。
解决方案1:多线程实现
把OpenCV的屏幕捕获、显示逻辑放到单独线程中,避免阻塞Tkinter主循环。
修改后代码:
import numpy as np import cv2 from mss import mss from PIL import Image import tkinter as tk import threading mon = {'left': 500, 'top': 500, 'width': 500, 'height': 500} running = True def opencv_loop(): with mss() as sct: while running: screenShot = sct.grab(mon) img = Image.frombytes( 'RGB', (screenShot.width, screenShot.height), screenShot.rgb, ) cv2.imshow('ProjectZero', np.array(img)) # 捕获退出按键,控制循环频率 if cv2.waitKey(33) & 0xFF in (ord('q'), 27): break cv2.destroyAllWindows() def on_closing(): global running running = False root.destroy() # 初始化Tkinter窗口 root = tk.Tk() root.geometry("400x300") root.title("Tkinter") root.attributes('-transparentcolor', 'red') root.config(bg='red') # 绑定窗口关闭事件,终止OpenCV线程 root.protocol("WM_DELETE_WINDOW", on_closing) # 启动OpenCV后台线程 cv_thread = threading.Thread(target=opencv_loop) cv_thread.start() # 启动Tkinter主循环 root.mainloop() # 等待线程结束 cv_thread.join()
代码说明
- 将OpenCV逻辑封装为独立函数,通过
threading.Thread在后台运行,不阻塞Tkinter主事件循环。 - 用
running变量控制线程循环,关闭Tkinter窗口时触发on_closing函数,终止OpenCV线程并销毁窗口。 - 确保退出时清理OpenCV窗口资源,避免内存泄漏。
解决方案2:Tkinter after 方法实现
利用Tkinter的after定时回调机制,在主事件循环中插入OpenCV更新逻辑,避免阻塞。
修改后代码:
import numpy as np import cv2 from mss import mss from PIL import Image import tkinter as tk mon = {'left': 500, 'top': 500, 'width': 500, 'height': 500} sct = mss() running = True def update_opencv(): if not running: cv2.destroyAllWindows() sct.close() return screenShot = sct.grab(mon) img = Image.frombytes( 'RGB', (screenShot.width, screenShot.height), screenShot.rgb, ) cv2.imshow('ProjectZero', np.array(img)) # 捕获退出按键,用1ms等待避免阻塞Tkinter if cv2.waitKey(1) & 0xFF in (ord('q'), 27): stop_all() return # 33ms后再次调用自身,维持循环 root.after(33, update_opencv) def stop_all(): global running running = False root.destroy() # 初始化Tkinter窗口 root = tk.Tk() root.geometry("400x300") root.title("Tkinter") root.attributes('-transparentcolor', 'red') root.config(bg='red') root.protocol("WM_DELETE_WINDOW", stop_all) # 启动OpenCV定时更新 root.after(0, update_opencv) # 启动Tkinter主循环 root.mainloop()
代码说明
- 用
root.after(33, update_opencv)定时触发OpenCV更新逻辑,模拟循环效果,不阻塞Tkinter事件处理。 - 用
running变量控制循环,关闭窗口时清理OpenCV和mss资源。 cv2.waitKey(1)设置为1毫秒,既可以捕获退出按键,又不会卡住Tkinter窗口。
注意事项
- 多线程方案中,禁止在子线程中操作Tkinter控件(Tkinter非线程安全),本方案中子线程仅处理OpenCV逻辑,无风险。
- 两种方案都需在退出时手动清理资源,避免残留进程或内存泄漏。
内容的提问来源于stack exchange,提问作者Official Onbekende
相关产品推荐
相关产品推荐

