Wes Tomer
Wes Tomer

Reputation: 329

How to use 2nd Tkinter window to change image in 1st?

Quick summary: The green button is supposed to change when an image is selected, but it doesn't:

enter image description here

I have a Tkinter window-A with a button that when pressed will use a separate Python file to create a new window-B. Window-B has two buttons: new screen-snip or select image from folder. The method used for this is supposed to then change self.image_selected so that it can be used to update the button in window-A to have this new image.

I've tried both lines of code below, and neither are working. I'm not getting any errors either:

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

Here is my code (simplified for clarity):

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()

Here is the aforementioned get_image_or_snip.py code:

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()


Upvotes: 2

Views: 96

Answers (1)

furas
furas

Reputation: 142641

If you add print() before and after get_image_or_snip.AcquireImage(self.newWindow) in changeImage() then you should see only first text because you run second mainloop() and it never ends this loop and never go back to changeImage() and never runs self.button.configure(image=img.image_selected)

You should use only one mainloop() and eventually use

root.wait_window(self.newWindow)

to wait until you close second window and then it will run self.button.configure(image=img.image_selected)

But there are other problems.

It removes image from memory memory when second windows is destroyed so you have to assign it to variable in first window.

Button use height in chars when you sent text but when you assign image then it use height in pixels and you have to change it from 5 to image.height()`


All code in one file

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()

BTW: If you want to change image without closing second window then you should send first window (or button from first window) as argument to second window and change image in show_dialogs()

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()

EDIT: Doc about creating Dialog Windows

Upvotes: 2

Related Questions