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.
Related
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()
There was a problem in getting the coordinates inside the picture (not the main root window, the source code will be at the end), the image is loaded using cv2 and added to the application interface via label. How can I get coordinates when clicking the mouse only on the picture? If it is possible to do this through tkinter, again only inside the picture.
import tkinter as tk
from tkinter import ttk, filedialog
import cv2
from PIL import Image
from PIL import ImageTk
class interface:
def __init__(self):
self.panelA = None
self.path = None
self.s = None
self.a = None
self.root = tk.Tk()
self.f1 = tk.Frame(self.root)
self.f1.grid(row=0, column=0)
self.f2 = tk.Frame(self.root)
self.f2.grid(row=0, column=1)
self.e = tk.Entry(self.f1)
self.e.grid(column=1, row=1, sticky='ew')
self.l1 = tk.Label(self.f1, text="Choose a picture")
self.l1.grid(column=0, row=0, sticky='ew')
self.l2 = tk.Label(self.f1, text="Введите напор H, м")
self.l2.grid(column=0, row=1, sticky='ew')
b1 = tk.Button(self.f1, text="Specify the file with the characteristic", command=self.select_image)
b1.grid(column=0, row=0, sticky='ew', columnspan=3)
b2 = tk.Button(self.f1, text="select the pressure")
b2.grid(column=2, row=1, sticky='ew')
columns = ['N', 'ny']
self.table = ttk.Treeview(self.f1, columns=columns, show='headings', height=20)
self.table.heading("N", text="N")
self.table.heading("ny", text="%")
self.table.grid(column=0, row=3, columnspan=3, sticky='ew')
self.root.mainloop()
def get_s(self):
return self.s
def select_image(self):
self.path = filedialog.askopenfilename()
if self.path:
image = cv2.imread(self.path)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
image = Image.fromarray(image)
image = ImageTk.PhotoImage(image)
if self.panelA is None:
self.panelA = tk.Label(self.f2, image=image)
self.panelA.image = image
self.panelA.grid()
else:
self.panelA.configure(image=image)
self.panelA.image = image
obj_interface = interface()
I tried it in tkinter, but it turned out to click only in the entire application
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
In my code, I have to list boxes that are bound to 2 different functions.
here's the code:
from tkinter import *
import string
class App:
def change_dropdown(self, *args):
print(self.Lb1.curselection())
self.Lb2.insert(self.count, self.choices[self.Lb1.curselection()[0]])
self.count+=1
def delete_dropdown_selected(self, *args):
print(self.Lb2.curselection())
def __init__(self, master):
self.count = 0
self.left = Frame(master)
self.left.config()
self.left.pack(side=LEFT)
self.choices = []
self.yscroll = Scrollbar(master, orient=VERTICAL)
self.Lb1 = Listbox(self.left, selectmode=SINGLE, yscrollcommand=self.yscroll.set, font=50, bd=2)
self.Lb2 = Listbox(self.left, selectmode=SINGLE, bd=2)
for j in range(2):
for i in range(26):
self.Lb1.insert(i,string.ascii_lowercase[i])
self.choices.append(string.ascii_letters[i])
self.Lb1.config(width=50, height=30)
self.Lb1.pack(side=TOP, fill=BOTH, expand=1)
self.Lb2.config(font=30, width=50, height=10)
self.Lb2.pack(side=BOTTOM, fill=BOTH, expand=1, pady=10)
self.Lb2.bind('<<ListboxSelect>>', self.delete_dropdown_selected)
self.Lb1.bind('<<ListboxSelect>>', self.change_dropdown)
self.yscroll.pack(side=LEFT, fill=Y)
self.yscroll.config(command=self.Lb1.yview)
root = Tk()
root.resizable(width=False, height=False)
app = App(root)
root.mainloop()
The problem is that when I click an item in Lb2, it goes to change_dropdown() instead of delete_dropdown_selected(). I don't understand why because I specify it here:
self.Lb2.bind('<<ListboxSelect>>', self.delete_dropdown_selected)
use exportselection=0 option in the Tkinter Listbox.
self.Lb1 = Listbox(self.left, selectmode=SINGLE, yscrollcommand=self.yscroll.set, font=50, bd=2, exportselection=0)
self.Lb2 = Listbox(self.left, selectmode=SINGLE, bd=2, exportselection=0)
How to keep selections highlighted in a tkinter Listbox?
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?