tkinter & PIL: removing image - python

I'm trying to write simple app that would display poster of random movie after button is pressed.
Problem: I don't know how to remove one image before displaying next one (so they don't stack on each other, like here: ).
My shortened code:
from tkinter import *
from tkinter import ttk
import random
from PIL import ImageTk, Image
mlist = ['resized.jpg', 'cat.jpg']
class App(Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master, padding='5')
self.grid(column=0, row=0, sticky=(N, W, E, S))
self.create_button()
self.name = ttk.Label()
self.image = ttk.Label()
def create_button(self):
self.button = ttk.Button(self,
text="Press me",
width=12,
command=lambda: self.display()
).grid(column=0, row=2, columnspan=2, pady=10, sticky=N)
def display(self):
self.name.destroy()
k = random.randrange(0, 2)
self.name = ttk.Label(self, font=(None, 16), text=mlist[k])
self.image = Image.open(mlist[k])
poster = ImageTk.PhotoImage(self.image)
display = ttk.Label(self, image=poster)
display.my_image = poster
display.grid(row=2, column=3, rowspan=3)
self.name.grid(row=0, rowspan=2, column=3)
root = Tk()
root.title("Test")
root.geometry("550x575")
app = App(root)
root.mainloop()
I believe, I should apply something similar to 'self.name.destroy()' on 'self.image'. However doesn't have such method... so how to solve it?

Related

ttk Style won't apply to frame in class

just started working with tkinter and i wanted to change the style of the frame but it won't. Can't figure it out so i'm asking you guys.
from tkinter import *
from tkinter import ttk
from tkinter import font
import currencyapi
class Currency():
def __init__(self, parent):
# App settings
parent.title("CoinyAPP")
icon = PhotoImage(file="icon.png")
parent.iconphoto(False, icon)
parent.eval("tk::PlaceWindow . center")
# Font settings
highlightFont = font.Font(
family='Helvetica', name='appHighlightFont', size=12, weight='bold')
# Widgets
self.frame1 = ttk.Frame(
parent, style="Frame1.TFrame").grid(row=0, column=0)
ttk.Label(self.frame1, text="Pick a base currency.", font=highlightFont).grid(
row=0, column=0, padx=48, pady=20)
ttk.Label(self.frame1, text="Pick currency to convert into.", font=highlightFont).grid(
row=0, column=2, padx=18, pady=20)
self.amount = StringVar()
currencyAmount = ttk.Entry(self.frame1, textvariable=self.amount)
currencyAmount.grid(row=1, column=1, padx=40)
self.baseCurrency = StringVar()
base = ttk.Combobox(self.frame1, textvariable=self.baseCurrency, justify='center',
values=list(currencyapi.currencyData['rates'].keys()))
base.grid(row=1, column=0)
base.current(46)
self.convertInto = StringVar()
convert = ttk.Combobox(self.frame1, textvariable=self.convertInto, justify='center',
values=list(currencyapi.currencyData['rates'].keys()))
convert.grid(row=1, column=2)
convert.current(0)
ttk.Button(self.frame1, command=self.currency_convertion,
text='Convert!').grid(row=2, column=1, padx=40, pady=15)
self.result = StringVar()
ttk.Label(self.frame1, font=highlightFont,
textvariable=self.result).grid(row=3, column=1, pady=5)
def currency_convertion(self, *args):
self.conv = currencyapi.currencyData['rates'].get(
self.convertInto.get())
self.amountNumber = self.amount.get()
self.base = currencyapi.currencyData['rates'].get(
self.baseCurrency.get())
Ans = (float(self.conv) * float(self.amountNumber)) / float(self.base)
self.result.set("%.2f" % Ans)
root = Tk()
s = ttk.Style()
s.configure("Frame1.TFrame", background='yellow',
foreground='blue')
Currency(root)
root.mainloop()
It's probably not very well written, sorry for that! Started programming few weeks ago.
Tried to put it into Currency class and outside, both didn't work.
It's possible that the problem is here:
self.frame1 = ttk.Frame(parent, style="Frame1.TFrame").grid(row=0, column=0)
The geometry manager methods (pack, grid, place) return None, so self.frame1 is evaluating to None
To fix this, declare your frame and then put it on the grid separately:
self.frame1 = ttk.Frame(parent, style="Frame1.TFrame")
self.frame1.grid(row=0, column=0)
That said, I put together a quick boilerplate app to test this and it seemed to work without issues...
"""Tkinter Boilerplate App Example"""
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super.__init__()
self.geometry('200x200')
self.title('Stylish')
self.frame = ttk.Frame(self, style='Frame1.TFrame')
self.frame.pack(expand=True, fill=tk.BOTH) # fill available space
self.style = ttk.Style()
# note: 'foreground' doesn't appear to have any effect on a Frame
self.style.configure('Frame1.TFrame', background='pink', foreground='red')
if __name__ == '__main__':
app = App()
app.mainloop()

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

Can't seem to change the window background colour in tkinter

Here is my code so far for a GUI I am making in tkinter, I have attempted to change the background colour of the window but it doesn't seem to work.
from tkinter import *
from tkinter.font import Font
class Window(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("Main Menu")
self.pack(fill=BOTH, expand=1)
videoButton = Button(self, text="Video Mode", font=helv18, bg="white", height=1, width=18)
videoButton.place(relx=0.5, rely=0.35, anchor=CENTER)
timelapseButton = Button(self, text="Time-lapse Mode", font=helv18, bg="white", height=1, width=18)
timelapseButton.place(relx=0.5, rely=0.6, anchor=CENTER)
root = Tk()
helv18 = Font(family='Helvetica', size=18, weight='bold')
root.config(bg='black')
root.geometry("480x320")
root.resizable(0, 0)
app = Window(root)
root.mainloop()

Weight is NOT working as expected when i used it Notebook and Frame Widget

Below is the code . Here Page2 is second Tab of the UI (Check the UI Image)
In second tab , i am creating the Frame and adding the label and Entry Box .
import tkinter as tk
from dicttoxml import dicttoxml
import xlrd
import GetValueFromExcel
from AppalyingXSLT import GenerateConfig
#import CreateXMLfromDict
from GetValueFromExcel import ExcelValue
from array import array
from tkinter import *
from tkinter import ttk, Button
from tkinter import *
root = Tk()
CheckBoxSelection=[]
NameOfVariable=[]
KeyName=[]
SelectedCheckbox=[]
dict={}
frame_main = tk.Frame(root)
frame_main.grid(sticky='news')
canvas=tk.Canvas()
class UICreation():
def __init__(self):
print ("I m in __init__")
self.nb=ttk.Notebook(frame_main)
self.page1=ttk.Frame(self.nb)
self.page2=ttk.Frame(self.nb)
def tabcreation(self):
print ("I M in Tab Creation")
self.nb.add(self.page1,text="Select")
canvas = tk.Canvas(self.page1)
canvas.grid(row=0, column=0, sticky="news")
vsb = tk.Scrollbar(self.page1, orient="vertical", command=canvas.yview)
vsb.grid(row=0, column=1, sticky='ns')
canvas.configure(yscrollcommand=vsb.set)
canvas.config(scrollregion=canvas.bbox("all"))
f = tk.Frame(canvas)
canvas.create_window((0, 0), window=f, anchor="n")
self.nb.grid(sticky=NW)
print ("I M in checkBox")
ListNumber=len(List_key)
print (ListNumber)
for value in range(0,ListNumber, 1):
NameOfVariable= "checkBox" + str(value)
CheckBoxSelection.append("var"+str(value))
CheckBoxSelection[value]=IntVar()
NameOfVariable = Checkbutton(f, text=str(List_key[value]),variable=CheckBoxSelection[value])
Checkbutton()
NameOfVariable.grid(sticky=NW)
NameOfVariable.cget("text")
KeyName.append(NameOfVariable.cget("text"))
canvas.update()
canvas.config(scrollregion=canvas.bbox("all"))
def addNew(self):
self.nb.add(self.page2,text="Add")
self.nb.grid_columnconfigure(0,weight=1)
page2frame=Frame(self.page2)
page2frame.grid(row=0, column=0, sticky='WE', padx=5, pady=5, columnspan=3)
page2frame.grid_columnconfigure(1, weight=1)
lblentry = Label(page2frame, text="Entry Box:")
lblentry.grid(row=0, column=0, sticky='W')
entrybx = Entry(page2frame)
entrybx.grid(row=0, column=0, sticky=E+W, columnspan=10)
#codeName=tk.Label(page2frame,text="Name").grid(row=1,rowspan=2,pady=(10,10),sticky="NW")
if __name__ == '__main__':
ui = UICreation()
ui.tabcreation()
ui.addNew()
In above image , from the above code I am getting entry box only for some columns (As mentioned in "red" section)even if i try to extend .
Please let me know , how to extend it like i need which i have shown in the "Green Box"
Update:
From your updated question I can see that you need to put weight in column1 of page2.
self.page2.columnconfigure(0, weight=1)
Replace:
class UICreation():
def __init__(self):
print ("I m in __init__")
self.nb=ttk.Notebook(frame_main)
self.page1=ttk.Frame(self.nb)
self.page2=ttk.Frame(self.nb)
With this:
class UICreation():
def __init__(self):
print ("I m in __init__")
self.nb=ttk.Notebook(frame_main)
self.page1=ttk.Frame(self.nb)
self.page2=ttk.Frame(self.nb)
self.page2.columnconfigure(0, weight=1)
I have updated your code to reflect a cleaner example that follows PEP8 better.
Let me know if you have any questions:
import tkinter as tk
import tkinter.ttk as ttk
class UICreation():
def __init__(self, master):
self.nb=ttk.Notebook(master)
self.page1=ttk.Frame(self.nb)
self.page2=ttk.Frame(self.nb)
self.page2.columnconfigure(0, weight=1)
self.check_box_election=[]
self.name_of_variable=[]
self.key_name=[]
self.selected_checkbox=[]
self.dict={}
self.frame_main = tk.Frame(root)
self.frame_main.grid(sticky='news')
self.canvas=tk.Canvas()
self.list_key = ["1", "2"]
def tabcreation(self):
self.nb.add(self.page1,text="Select")
canvas = tk.Canvas(self.page1)
canvas.grid(row=0, column=0, sticky="news")
vsb = tk.Scrollbar(self.page1, orient="vertical", command=canvas.yview)
vsb.grid(row=0, column=1, sticky='ns')
canvas.configure(yscrollcommand=vsb.set)
canvas.config(scrollregion=canvas.bbox("all"))
f = tk.Frame(canvas)
canvas.create_window((0, 0), window=f, anchor="n")
self.nb.grid(sticky="nw")
list_number = len(self.list_key)
for value in range(0,list_number, 1):
name_of_variable= "checkBox" + str(value)
self.check_box_election.append("var"+str(value))
self.check_box_election[value] = tk.IntVar()
name_of_variable = tk.Checkbutton(f, text=str(self.list_key[value]),variable=self.check_box_election[value])
name_of_variable.grid(sticky="nw")
name_of_variable.cget("text")
self.key_name.append(name_of_variable.cget("text"))
canvas.update()
canvas.config(scrollregion=canvas.bbox("all"))
def add_new(self):
self.nb.add(self.page2,text="Add")
page2frame = tk.Frame(self.page2)
page2frame.grid(row=0, column=0, sticky='ew', padx=5, pady=5, columnspan=3)
page2frame.grid_columnconfigure(1, weight=1)
lblentry = tk.Label(page2frame, text="Entry Box:")
lblentry.grid(row=0, column=0, sticky='w')
entrybx = tk.Entry(page2frame)
entrybx.grid(row=0, column=0, sticky="ew", columnspan=10)
if __name__ == '__main__':
root = tk.Tk()
ui = UICreation(root)
ui.tabcreation()
ui.add_new()
root.mainloop()

How can I automatically update my listbox in tkinter?

I've seen a couple posts similar to my question, but not exactly this, so apologies if this is a repeat question.
I'm using tkinter to read a folder, create a listbox that lists all the files (they're all going to be .tif files), and the user selects the image they want to view. Unfortunately files will be added and removed so I would like to update my listbox automatically. Here's some of the code I have so far:
from tkinter import *
from PIL import Image, ImageTk
import os
file_path = "C:/Users/USX27512/Desktop/Python UI/Test_TIFFs"
root = Tk()
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
os.chdir(file_path)
self.grid()
self.canv = Canvas(self, relief=SUNKEN)
self.canv.grid(row=2, column=1, columnspan=5, sticky=N)
self.canv.config(width=500, height=500)
self.canv.config(highlightthickness=0, background="black")
self.view_files()
def view_files(self):
lb = Listbox(self, height=20)
lb.update_idletasks()
files = sorted(os.listdir(file_path), key=lambda x: os.path.getctime(os.path.join(file_path, x)))
for file in files:
if os.path.isfile(os.path.join(file_path, file)):
lb.insert(END, file)
lb.bind("<Double-Button-1>", self.on_double)
lb.grid(row=2, column=0, sticky=NW)
def on_double(self, event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection[0])
sbarV = Scrollbar(self, orient=VERTICAL)
sbarH = Scrollbar(self, orient=HORIZONTAL)
sbarV.config(command=self.canv.yview)
sbarH.config(command=self.canv.xview)
self.canv.config(yscrollcommand=sbarV.set)
self.canv.config(xscrollcommand=sbarH.set)
sbarV.grid(row=2, column=6, sticky=N+S)
sbarH.grid(row=3, column=1, columnspan= 5, sticky=E+W)
self.im = Image.open(value)
image_width, image_height = self.im.size
self.canv.config(scrollregion=(0, 0, image_width, image_height))
self.im2 = ImageTk.PhotoImage(self.im)
self.imgtag = self.canv.create_image(0,0, anchor=NW, image=self.im2)
app = Application(root)
root.mainloop()
Any suggestions?
I was finally able to find the answer here. From that function, I can check the list and update it as needed.

Categories