Search code examples
pythonpython-3.xtkinterpng

Saving tkinter window as an image


I'm using tkinter as a way to layout information in a weather app. As the information changes so does the layout. Each time the script runs I need to save an image of the window as a png, if possible have the image cropped down to remove the title bar.

Here is my watered down code:

from tkinter import *
import tkinter as tk

#Values hardcoded for testing
Temperature = "87°F"
Alert = "Weather Alert"
Sky = "Sunny"
Humidity = "45%"

#Build Window
root = Tk()
root.title("Weather App")
root.geometry("500x200+200+200")
root.resizable(False,False)

#Label Text
weather = Label(root, text = "Today's Weather")
weather.config(font =("Helvetica", 14))

Weather_Sky = Label(root, text=Sky, font=("Helvetica", 15, 'bold'))
Weather_Sky.place(x=300, y=50)

Weather_Temp = Label(root, text=Temperature, font=("Helvetica", 15, 'bold'))
Weather_Temp.place(x=300, y=75)

Weather_Humidity = Label(root, text=Humidity + " Humidity", font=("Helvetica", 15, 'bold'))
Weather_Humidity.place(x=300, y=100)

Weather_Alert = Label(root, text=Alert, font=("Helvetica", 15, 'bold'), fg='#f00')
Weather_Alert.place(x=300, y=125)

weather.pack()
root.mainloop()

Most of what I find online deals with a tkinter canvas, I don't if I need to add that to my code or if a solution exists without dealing with a canvas.

I'm expecting a single .png file of my tkinter window saved in the same directory as my .py file.


Solution

  • The PIL library has a module named ImageGrab, and allows the user to take a picture of the screen. So you could make a function that gets that gets the image like so:

    import tkinter as tk
    # import PIL
    from PIL import ImageGrab
    
    window = tk.Tk()
    window.title("Hello world")
    window.geometry("300x300")
    
    # function to save window as image
    def capture_window():
        x = window.winfo_rootx()
        y = window.winfo_rooty()
        width = window.winfo_width()
        height = window.winfo_height()    #get details about window
        takescreenshot = ImageGrab.grab(bbox=(x, y, width, height))
        takescreenshot.save("screenshot.png")
    
    hello = tk.Label(text="Hello world!")
    hello.pack()
    button = tk.Button(text="Click me!")
    button.pack()
    screenshot = tk.Button(window, text="Screenshot", command=capture_window)
    screenshot.pack()                  # button to take screenshot
    tk.mainloop()
    

    If you need it to call it without a button, you could wait 1 second so that the window probably fully loaded:

    ...
    window.after(1000, capture_window)
    ...
    

    Or even better, wait till the window has signaled it's done loading:

    ...
    window.wait_visibility()
    window.update()
    capture_window()
    ...