如何使用第二个Tkinter窗口在第一个中更改图像?

时间:2020-08-03 19:56:23

标签: python tkinter

快速摘要:选择图像后,绿色按钮应该会更改,但不会:

enter image description here

我有一个带有按钮的Tkinter window-A,当按下该按钮时,它将使用单独的Python文件创建新的window-BWindow-B有两个按钮:新的屏幕截图或从文件夹中选择图像。然后,应该使用此方法来更改self.image_selected,以便可以将其用于更新window-A中的按钮以具有新图像。

我已经在下面尝试了两行代码,但都不起作用。我也没有任何错误:

        self.button.configure(image = img.image_selected) # first try
        self.button['image'] = img.image_selected         # second try

这是我的代码(为清晰起见,已简化):

import tkinter as tk
import get_image_or_snip

class ButtonImg:
    def __init__(self, master):
        self.newWindow = None
        self.master = master
        self.title = "My Minimum Reproducible Example"
        self.fontA = ("arial", 20, "bold")
        self.canvas = tk.Canvas(height = 5)
        self.canvas.pack()
        self.button = tk.Button(bg="#93d9cc", height = 5, text = "Select Image",
                                font = self.fontA, command = self.changeImage)
        self.button.pack(fill="both")

    def changeImage(self):
        self.newWindow = tk.Toplevel(self.master)
        img = get_image_or_snip.AcquireImage(self.newWindow)
        self.button.configure(image = img.image_selected)
        #self.button['image'] = img.image_selected

root = tk.Tk()
app = ButtonImg(root)
root.mainloop()

以下是上述get_image_or_snip.py代码:

import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk, Image
import snipping_tool


class AcquireImage:
    def __init__(self, master):
        self.master = master
        self.fontA = ("arial", 20, "bold")
        self.frame = tk.Frame(master, bg="#1B2631")
        self.frame.pack(fill="both", expand=True)
        self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
                              font = self.fontA, command =lambda: self.show_dialogs(1))
        self.button1.grid(row=0, column=0, sticky="nsew")
        self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
                              font = self.fontA, command=lambda: self.show_dialogs(2))
        self.button2.grid(row=0, column=1, sticky="nsew")
        self.image_selected = None
        self.master.mainloop()

    def show_dialogs(self, method):
        if method == 1:
            ret = filedialog.askopenfilename()
            load_img = Image.open(ret)
            self.image_selected = ImageTk.PhotoImage(load_img)

        if method == 2:
            ret = snipping_tool.get_snip()
            self.image_selected = ret


def main():
    root = tk.Tk()
    AcquireImage(root)
    root.mainloop()


if __name__ == '__main__':
    main()


1 个答案:

答案 0 :(得分:2)

如果您在print()中的get_image_or_snip.AcquireImage(self.newWindow)之前和之后添加changeImage(),则应该只看到第一个文本,因为您运行了第二个mainloop(),并且它永远不会结束此循环,也永远不会消失回到changeImage(),再也不会运行self.button.configure(image=img.image_selected)

您应该只使用一个mainloop()并最终使用

root.wait_window(self.newWindow)

等待直到您关闭第二个窗口,然后它将运行self.button.configure(image=img.image_selected)

但是还有其他问题。

当第二个窗口被破坏时,它将图像从内存中删除,因此您必须将其分配给第一个窗口中的变量。

当您发送文本时,按钮使用字符的高度,但是当您分配图像时,按钮使用像素的高度,因此您必须将其从5更改为image.height()`


所有代码在一个文件中

import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk


class AcquireImage:
    
    def __init__(self, master):
        self.master = master
        self.fontA = ("arial", 20, "bold")
        
        self.frame = tk.Frame(master, bg="#1B2631")
        self.frame.pack(fill="both", expand=True)
        
        self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
                              font=self.fontA, command=lambda:self.show_dialogs(1))
        self.button1.grid(row=0, column=0, sticky="nsew")
        
        self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
                              font=self.fontA, command=lambda:self.show_dialogs(2))
        self.button2.grid(row=0, column=1, sticky="nsew")
        
        self.image_selected = None

    def show_dialogs(self, method):
        
        if method == 1:
            ret = filedialog.askopenfilename(initialdir='/home/user/images/')
            if ret:
                self.image_selected = ImageTk.PhotoImage(file=ret)
                self.master.destroy()
     
        elif method == 2:
            self.image_selected = snipping_tool.get_snip()


class ButtonImg:
    
    def __init__(self, master):
        self.newWindow = None
        self.master = master
        self.title = "My Minimum Reproducible Example"
        self.fontA = ("arial", 20, "bold")
        
        self.canvas = tk.Canvas(height=5)
        self.canvas.pack()
        
        self.button = tk.Button(bg="#93d9cc", height=5, text="Select Image",
                                font=self.fontA, command=self.changeImage)
        self.button.pack(fill="both")

    def changeImage(self):
        print('open second window')
        self.newWindow = tk.Toplevel(self.master)
        img = AcquireImage(self.newWindow)
        self.master.wait_window(self.newWindow)
        print('close second window')

        if img.image_selected: # check if image was selected
            self.image = img.image_selected
            self.button.configure(image=self.image, height=self.image.height())
        

root = tk.Tk()
app = ButtonImg(root)
root.mainloop()

顺便说一句::如果要更改图像而不关闭第二个窗口,则应将第一个窗口(或第一个窗口中的按钮)作为参数发送给第二个窗口,并在show_dialogs()中更改图像< / p>

import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk


class AcquireImage:
    
    def __init__(self, master, first_window):
        self.master = master
        self.first_window = first_window
        
        self.fontA = ("arial", 20, "bold")
        
        self.frame = tk.Frame(master, bg="#1B2631")
        self.frame.pack(fill="both", expand=True)
        
        self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
                              font=self.fontA, command=lambda:self.show_dialogs(1))
        self.button1.grid(row=0, column=0, sticky="nsew")
        
        self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
                              font=self.fontA, command=lambda:self.show_dialogs(2))
        self.button2.grid(row=0, column=1, sticky="nsew")
        
        self.image_selected = None

    def show_dialogs(self, method):
        
        if method == 1:
            ret = filedialog.askopenfilename(initialdir='/home/user/images/')
            if ret:
                self.image_selected = ImageTk.PhotoImage(file=ret)
                self.first_window.image = self.image_selected
                self.first_window.button.configure(image=self.first_window.image, height=self.first_window.image.height())

        elif method == 2:
            self.image_selected = snipping_tool.get_snip()


class ButtonImg:
    
    def __init__(self, master):
        self.newWindow = None
        self.master = master
        self.title = "My Minimum Reproducible Example"
        self.fontA = ("arial", 20, "bold")
        
        self.canvas = tk.Canvas(height=5)
        self.canvas.pack()
        
        self.button = tk.Button(bg="#93d9cc", height=5, text="Select Image",
                                font=self.fontA, command=self.changeImage)
        self.button.pack(fill="both")

    def changeImage(self):
        self.newWindow = tk.Toplevel(self.master)
        img = AcquireImage(self.newWindow, self) # first window as `self` but you can send `self.button`

        

root = tk.Tk()
app = ButtonImg(root)
root.mainloop()

编辑:有关创建Dialog Windows

的文档