我的绘图库需要能够同时显示多个绘图,每个绘图都表示为PIL图像,并且每个绘图都应显示为自己的窗口。窗口应该是独立的,因此关闭其中任何一个窗口都不会影响其他窗口,但是当所有窗口都关闭时,主循环应该退出。在qt和wx中,这种行为很容易实现,但到目前为止,在qt中,这很难证明。
这是我到目前为止最接近的一个
from six.moves import tkinter
from PIL import ImageTk
class Window:
def __init__(self, img):
self.window = tkinter.Toplevel()
self.window.minsize(img.width, img.height)
self.canvas = tkinter.Canvas(self.window, width=img.width, height=img.height)
self.canvas.pack()
self.canvas.configure(background="white")
self.photo = ImageTk.PhotoImage(img)
self.sprite = self.canvas.create_image(0, 0, image=self.photo, anchor=tkinter.NW)
windows = []
for img in imgs:
windows.append(Window(img))
if len(windows) > 0: windows[0].window.mainloop()
这将在每个窗口中显示图像,并且每个窗口都可以独立关闭。但是它还会显示一个空的根窗口,需要关闭该窗口才能退出主循环,并且将导致所有窗口在关闭时关闭,这不是我想要的行为。
如果我将tkinter.Toplevel()
替换为tkinter.Tk()
,则第二个窗口的create_image失败,出现模糊的“ pyimageX不存在”错误消息,其中X是递增的整数。
我将不得不创建一个不可见的根窗口,然后手动计算关闭了多少个子窗口,并在所有子窗口都关闭后触发销毁该不可见的根窗口,以获取所需的行为?还是有一种简单的方法来实现这一目标?
编辑:只是为了澄清:我的程序主要不是Tk应用程序。它几乎将所有时间都花在做其他事情上,并且仅在单个函数中临时使用Tk来显示一些图。这就是为什么在关闭绘图后退出主循环很重要,以便程序可以恢复其正常操作。考虑一下matplotlib中的show()
是如何工作的,以这种情况为例。
答案 0 :(得分:1)
这是您可能要执行此操作的示例。此示例使用根窗口来容纳一个按钮,该按钮将在顶层打开所有图像。
确保将self.path
更改为图像文件夹。
import tkinter as tk
import os
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
tk.Button(self, text="Open Images", command=self.open_images).pack()
self.path = ".\RGB"
def open_images(self):
directory = os.fsencode(self.path)
for file in os.listdir(directory):
filename = os.fsdecode(file)
if filename.endswith(".gif"):
print(filename)
top = tk.Toplevel(self)
img = tk.PhotoImage(file="{}\{}".format(self.path, filename))
lbl = tk.Label(top, image=img)
lbl.image = img
lbl.pack()
if __name__ == '__main__':
app = App()
app.mainloop()
这是我的第二个示例,您可以在其中隐藏根窗口,并且在关闭最后一个顶级窗口时,tkinter实例也被破坏。这是一个简单的跟踪变量。
import tkinter as tk
import os
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.top_level_count = 0
self.path = ".\RGB"
self.open_images()
self.withdraw()
def open_images(self):
directory = os.fsencode(self.path)
for file in os.listdir(directory):
filename = os.fsdecode(file)
if filename.endswith(".gif"):
self.top_level_count += 1
image_top(self, self.path, filename)
def check_top_count(self):
print(self.top_level_count)
if self.top_level_count <= 0:
self.destroy()
class image_top(tk.Toplevel):
def __init__(self, controller, path, filename):
tk.Toplevel.__init__(self, controller)
self.controller = controller
self.protocol("WM_DELETE_WINDOW", self.handle_close)
img = tk.PhotoImage(file="{}\{}".format(path, filename))
lbl = tk.Label(self, image=img)
lbl.image = img
lbl.pack()
def handle_close(self):
self.controller.top_level_count -= 1
self.destroy()
self.controller.check_top_count()
if __name__ == '__main__':
app = App()
app.mainloop()
答案 1 :(得分:0)
好吧,这是我想解决这个问题的几门课:
class ImgRoot(tkinter.Tk):
def __init__(self, imgs):
super(ImgRoot, self).__init__()
for i in imgs:
Window(self, i)
self.withdraw()
self.open=True
self.tick()
def tick(self):
if not self.open:
self.destroy()
self.open=False
self.after(100, self.tick)
def checkin(self):
self.open=True
class Window(tkinter.Toplevel):
def __init__(self, root, img):
super(Window, self).__init__()
self.root=root
self.tick()
self.minsize(img.width, img.height)
self.canvas = tkinter.Canvas(self, width=img.width, height=img.height)
self.canvas.pack()
self.canvas.configure(background="white")
self.photo = ImageTk.PhotoImage(img)
self.sprite = self.canvas.create_image(0, 0, image=self.photo, anchor=tkinter.NW)
def tick(self):
self.root.checkin()
self.after(100, self.tick)
这里的想法是创建一个处理整个事件的主类(ImgRoot
)。然后,每隔0.1秒(100毫秒),它将检查是否有任何图像窗口告诉它它们仍在运行,如果没有,则关闭。图像窗口(Window
s)通过每运行0.1秒将ImgRoot
的{{1}}属性设置为open
来实现。这是一个示例用法:
True