我尝试构建一个GUI应用程序,从相机抓取帧并在Tkinter GUI中显示它们。Tkinter mainloop在主线程中执行,而gui的帧抓取和更新在单独的线程中进行。
下面的代码作为一个视频流被抓取并正确显示在我的gui窗口中。但是,当我通过单击“x”来调用on_close()方法来关闭gui时,gui将关闭,但程序不会完全终止。最后一次CLI输出将为“Mainloop stopped!”,但该计划并没有像我预期的那样终止。因此,即使我通过stop事件退出threads run()方法中的while循环,我还是怀疑额外的线程会继续运行。
这是我的代码:
import threading
import cv2
import tkinter
from tkinter import ttk
from PIL import Image
from PIL import ImageTk
import camera
class mainThread(threading.Thread):
def __init__(self, gui):
threading.Thread.__init__(self)
self.stop_event = threading.Event()
self.gui = gui
def stop(self):
print("T: Stop method called...")
self.stop_event.set()
def run(self):
print("Connecting to camera...")
cam = camera.Camera(resolution=(1280, 960), exposure=-3, bit_depth=12)
cam.connect(device_id=0)
while (not self.stop_event.is_set()):
print("running..., stop event = " + str(self.stop_event.is_set()))
# retrieve frame and frame time
frame, _, _ = cam.get_frame()
# display frame
self.gui.updater(frame)
# wait for displaying image
cv2.waitKey(1)
class gui(object):
def __init__(self, root):
self.root = root
# create and start thread running the main loop
self.main_thread = mainThread(self)
self.main_thread.start()
# bind on close callback that executes on close of the main window
self.root.protocol("WM_DELETE_WINDOW", self.on_close)
# change window title
self.root.title("MCT Laser Welding Quality Control")
# set min size of root window and make window non resizable
self.root.minsize(600, 400)
self.root.resizable(False, False)
# configure grid layout
self.root.rowconfigure(0, weight=1)
self.root.rowconfigure(1, weight=1)
self.root.columnconfigure(0, weight=1)
# create image panel
self.image_panel = None
def on_close(self):
self.main_thread.stop()
self.root.destroy()
def updater(self, image):
# TODO: resize frame first
# convert image to tkinter image format
image = Image.fromarray(image)
image = ImageTk.PhotoImage(image)
# if the panel does not exist, create and pack it
if self.image_panel is None:
# show the image in the panel
self.image_panel = ttk.Label(self.root, image=image)
self.image_panel.image = image # keep reference
# pack object into grid
self.image_panel.grid(row=0, column=0)
# just update the image on the panel
else:
self.image_panel.configure(image=image)
self.image_panel.image = image # keep reference
def run(self):
self.root.mainloop()
if __name__ == "__main__":
# create a main window
root = tkinter.Tk()
# set style
style = ttk.Style()
style.theme_use("vista")
# create gui instance
user_interface = gui(root)
# run the user interface
root.mainloop()
print("Mainloop stopped!")
编辑:我发现,这行
image = ImageTk.PhotoImage(image)
防止线程停止,如上所述。当我删除这一行并简单地用一个递增的数字更新标签文本时,当我关闭gui窗口时,一切都像例外一样工作,线程终止。任何想法,为什么ImageTk.PhotoImage()导致线程不能正确终止?
您需要加入线程以等待它关闭。
def stop(self):
print("T: Stop method called...")
self.stop_event.set()
self.join()
此外,您可能需要关闭摄像头的开放连接。
while (not self.stop_event.is_set()):
...
cam.close() # not sure about exact API here
问题内容: 如何使多线程python程序响应Ctrl + C键事件? 编辑: 代码是这样的: 我试图在所有线程上删除join(),但仍然无法正常工作。是否因为每个线程的run()过程中的锁段? 编辑: 上面的代码应该可以工作,但是当当前变量在5,000-6,000范围内并遍历以下错误时,它总是会中断 问题答案: 在启动主线程之前,将除主线程之外的每个线程都设为守护进程(在2.6或更高版本中,在2.
我正在编写一个JavaFX应用程序,我的对象扩展任务提供了JavaFXGUI线程之外的并发性。 我的主要课程是这样的: 我的GUI控制器示例如下(略作抽象): 目前,我的任务只是进行睡眠并打印数字1到10: 我遇到的问题是,一旦任务完成,就好像启动任务的线程继续运行一样。因此,当我按下右上角的“X”退出JavaFX应用程序时,JVM继续运行,我的应用程序不会终止。如果你看一下我的主课,我已经把系统
主要内容:1 什么是Java终止线程,2 Thread类终止线程的方法,3 Java终止线程的例子1,4 Java终止线程的例子2,5 Java终止线程的例子3,6 isInterrupted和interrupted方法1 什么是Java终止线程 如果任何线程处于睡眠或等待状态(即,调用sleep()或wait()方法),则在线程上调用interrupt()方法,会抛出InterruptedException中断睡眠或等待状态。如果线程未处于睡眠或等待状态,则调用interrupt()方法将执行
问题内容: 我有两个线程:主线程和从主线程生成的线程。 当主线程退出时,整个程序会终止吗? 问题答案: 没有。 当所有非守护程序线程完成时,Java程序终止。 该文档指出: Java虚拟机启动时,通常只有一个非守护程序线程(通常调用某些指定类的名为main的方法)。Java虚拟机将继续执行线程,直到发生以下任何一种情况: 类的方法已被调用,安全管理器已允许进行退出操作。 不是守护程序线程的所有线程
问题内容: 当我测试创建子线程的方法的执行时,JUnit测试会在子线程之前终止并杀死它。 我如何强制JUnit等待子线程完成其执行? 谢谢 问题答案: 阅读问题和评论后,似乎您需要的是 一种对异步操作进行单元测试的技术 。doSomething()立即返回,但是您希望测试代码等待其完成,然后进行一些验证。 问题在于该测试无法识别该调用所产生的线程,因此显然它无法等待它们。人们可以想到许多复杂的(可