Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在单独的线程中运行Tkinter窗体_Python_Multithreading_Tkinter - Fatal编程技术网

Python 在单独的线程中运行Tkinter窗体

Python 在单独的线程中运行Tkinter窗体,python,multithreading,tkinter,Python,Multithreading,Tkinter,我写了一个简短的模块,可以传递一个图像,只需创建一个Tkinter窗口并显示它。我遇到的问题是,即使我实例化并调用在单独线程中显示图像的方法,主程序也不会继续,直到Tkinter窗口关闭 这是我的模块: import Image, ImageTk import Tkinter class Viewer(Tkinter.Tk): def __init__(self,parent): Tkinter.Tk.__init__(self,parent) sel

我写了一个简短的模块,可以传递一个图像,只需创建一个Tkinter窗口并显示它。我遇到的问题是,即使我实例化并调用在单独线程中显示图像的方法,主程序也不会继续,直到Tkinter窗口关闭

这是我的模块:

import Image, ImageTk
import Tkinter


class Viewer(Tkinter.Tk):
    def __init__(self,parent):
        Tkinter.Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()

    def initialize(self):
        self.grid()

    def show(self,img):
        self.to_display = ImageTk.PhotoImage(img)
        self.label_image = Tkinter.Label(self,image=self.to_display)
        self.label_image.grid(column = 0, row = 0, sticky = "NSEW")
        self.mainloop()
它似乎工作得很好,除非我从下面的测试程序调用它,否则它似乎不允许我的测试程序继续,即使是在不同的线程中启动

import Image
from viewer import Viewer
import threading

def showimage(im):
    view = Viewer(None)
    view.show(im)

if __name__ == "__main__":
    im = Image.open("gaben.jpg")
    t = threading.Thread(showimage(im))
    t.start()
    print "Program keeps going..."
我想,也许我的问题是,我应该在模块本身中创建一个新线程,但我只是想尝试保持它的简单性,因为我对Python是新手

无论如何,提前谢谢你的帮助


编辑:为了清晰起见,我只是想制作一个模块,在Tkinter窗口中显示图像,这样我就可以在任何时候显示图像时使用这个模块。我遇到的问题是,每当程序使用此模块时,它都无法恢复,直到Tkinter窗口关闭。

据我所知,Tkinter不喜欢在其他线程中播放。看到这个帖子

解决方法是在主线程中创建一个(可能是隐藏的)顶层,生成一个单独的线程来打开图像,等等,并使用一个共享队列将消息发送回Tk线程


您的项目是否需要使用Tkinter?我喜欢特金特。它“又快又脏。”-但是(很多)情况下,其他GUI工具包是可行的。

Tkinter不是线程安全的,一般的共识是Tkinter不能在非主线程中工作。如果您重写代码以便Tkinter在主线程中运行,那么您可以让工作线程在其他线程中运行

主要的警告是工作人员不能与Tkinter小部件交互。他们必须将数据写入队列,您的主GUI线程必须轮询该队列


如果您所做的只是显示图像,那么您可能根本不需要线程。只有当您有一个长时间运行的进程,否则会阻塞GUI时,线程才有用。Tkinter可以轻松地处理数百个图像和窗口,而不必费吹灰之力。

从您的评论中,听起来您根本不需要GUI。只需将图像写入磁盘并调用外部查看器即可

在大多数系统上,应该可以使用如下方式启动默认查看器:

import subprocess 

subprocess.Popen("yourimage.png")

我试着从一个单独的线程运行tkinter,这不是一个好主意,它冻结了。 有一个解决方案奏效了。在主线程中运行gui,并将事件发送到主gui。这是一个类似的示例,它只显示一个标签

import Tkinter as t
global root;
root = t.Tk()
root.title("Control center")
root.mainloop()

def new_window(*args):
    global root
    print "new window"
    window = t.Toplevel(root)
    label = t.Label(window, text="my new window")
    label.pack(side="top", fill="both", padx=10, pady=10)
    window.mainloop()

root.bind("<<newwin>>",new_window)

#this can be run in another thread
root.event_generate("<<newwin>>",when="tail")
将Tkinter作为t导入
全球根;
root=t.Tk()
root.title(“控制中心”)
root.mainloop()
def新窗口(*args):
全局根
打印“新窗口”
窗口=t.Toplevel(根)
label=t.label(窗口,text=“我的新窗口”)
标签包装(side=“top”,fill=“both”,padx=10,pady=10)
window.mainloop()
root.bind(“,新窗口)
#这可以在另一个线程中运行
root.event_generate(“,when=“tail”)

您的答案的第一部分很好,但我不能放弃,因为建议您尝试其他工具包。Tkinter非常适合这个问题所涉及的类型。非常感谢您的建议。我注意到,如果我在查看器模块中运行self.mainloop(),就像上面的例子一样,在窗口关闭之前,它将永远不会继续运行我的实际程序。如果我把这一行放在程序中(例如view.mainloop()),它也会做同样的事情。我原以为把这一行放在一个单独的线程中可以解决这个问题。你是说我应该能够在没有线程的情况下完成这项工作,你是说有一种方法可以在没有mainloop()的情况下显示窗口?@ballsdotball:如果你想创建一个交互式GUI,你需要调用
mainloop
。就其本质而言,因为您正在运行事件循环,所以可能不需要线程。在调用
mainloop
之后,“它将永远不会继续执行[您的]实际程序”,这是事实,但这就是它的工作原理。您建立了循环,然后您的程序只响应事件
mainloop
几乎总是应用程序启动逻辑中的最后一行代码。我认为问题在于,我只想编写一个显示图像的模块。我需要一种方法让我的程序在使用此模块后继续运行,而不是等待用户关闭映像。你的意思是说没有办法用Tkinter来做这件事吗?@ballsdotballs:一般来说,没有GUI工具包是这样工作的。GUI工具包具有事件循环并响应事件。也就是说,在启动事件循环之后,您仍然可以运行其他代码,但是当这些代码运行时,您的GUI将冻结。如果不知道你真正想要完成的是什么,就很难说得更具体。我不知道这是否有帮助,但看看tkinter的
after
方法的例子。使用它,您可以要求事件循环在将来运行一些东西,这样您就可以用额外的代码创建一个函数,然后在调用
mainloop
几毫秒后运行它。非常感谢您在这方面提供的帮助。我知道我看起来很笨,但我认为你忽视了我的根本问题。我不希望GUI做任何其他事情。它已经做了我想要它做的事情,那就是显示图像。我希望创建查看器的程序(上面的第二个块)能够在查看器运行时继续运行(就像我希望在不关闭GUI的情况下以某种方式进入打印语句行一样)。为下一个访问者或可能是6年后的OP做好准备:除了tkInter和threads之外,主要问题是“threading.Thread(showimage(im))”不在线程中执行“showimage”,但调用“showimage(im)”并将返回(None)作为参数提供给线程构造函数。“线程(目标=部分(showimage,im))”将是正确的thr