Tkinter throws exception, but the code still works, why? - python-3.x

I am working on a comic book reader and my code so far seems to be working great, except for a small result that happens when I update my canvas to display a jpg of the page of the comic book.
The Code:
from tkinter import *
from tkinter import filedialog, Tcl
from PIL import ImageTk, Image
from pyunpack import Archive
import shutil
import tempfile
import os
def open_comic():
os.mkdir('tmp/')
text_file = filedialog.askopenfilename(title="Open Comic Book File", filetypes=(("CBR Files", "*.cbr"), ("CBZ Files", "*.cbz"), ))
tempdir = tempfile.mkdtemp(suffix='.tmp', dir='tmp/')
print('Created temp directory', tempdir)
Archive(text_file).extractall(tempdir)
file_list = os.listdir(tempdir)
file_list.sort()
img = ImageTk.PhotoImage(Image.open(tempdir + "/" + file_list[1]))
my_image = comic_canvas.create_image(0, 0, anchor=NW, image=img)
canvas.update()
# Create the Main Window of the Application
mainWindow = Tk()
mainWindow.title("Comic Reader")
mainWindow.geometry("1200x1500")
buttonFrame = LabelFrame(mainWindow)
canvasFrame = LabelFrame(mainWindow, bg="light gray", border=2)
statusFrame = LabelFrame(mainWindow, bg="black", border=2)
comic_canvas = Canvas(canvasFrame, width="1100", height="1400", bg="light gray")
# Create the Menu Bar for the Application
main_menu = Menu(mainWindow)
mainWindow.config(menu=main_menu)
# The File Menu
file_menu = Menu(main_menu, tearoff=False)
main_menu.add_cascade(menu=file_menu, label="File")
file_menu.add_command(label="Open", command=open_comic)
file_menu.add_separator()
file_menu.add_command(label="Quit", command=quit_it)
# The Edit Menu
edit_menu = Menu(main_menu, tearoff=False)
main_menu.add_cascade(menu=edit_menu, label="Edit")
edit_menu.add_command(label="Cut", accelerator="(CTRL+X)")
edit_menu.add_command(label="Copy", accelerator="(CTRL+C)")
edit_menu.add_command(label="Paste", accelerator="(CTRL+V)")
button_back = Button(buttonFrame, text="<=", command=back)
button_exit = Button(buttonFrame, text="Exit", command=quit_it)
button_next = Button(buttonFrame, text="=>", command=lambda: forward(2))
buttonFrame.pack()
canvasFrame.pack()
statusFrame.pack()
button_back.grid(row=1, column=0)
button_exit.grid(row=1, column=1)
button_next.grid(row=1, column=2)
comic_canvas.grid(row=2, column=1)
# Start the Application Here
mainWindow.mainloop() # Creates the GUI for the Application
Now as it is above, it works to update the canvas, and lets you see the image, but throws the error:
> Exception in Tkinter callback Traceback (most recent call last):
> File
> "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/tkinter/__init__.py",
> line 1884, in __call__
> return self.func(*args) File "/Users/kb2mob/Python Projects/Comic Reader/comicreader.py", line 28, in open_comic
> canvas.update() NameError: name 'canvas' is not defined
Which, yeah it should because the canvas is named "comic_canvas". But then I do use the correct name for the .update() method, it flashes quickly and then vanishes, and of course doesn't throw an error because it's the correct use.
Does anyone know why that is?
This is in Python 3.9.1 on a latest Mac OS.

Found the issue:
Wasn't keeping the image reference at the end of my function open_comic()
comic_canvas.img = img
dropped that on the end of it and it worked.

Related

Python: TypeError: 'Label' object is not callable

from PIL import Image, ImageTk
from tkinter import *
from tkinter import Label
def open_window():
menu = Toplevel(root)
menu.geometry("800x800")
menu.title("my game's menu")
menu.resizable(False, False)
menu.geometry("800x800")
lbl = Label(menu, text ="Hello!").pack
menu.mainloop()
root = Tk()
root.geometry("400x300")
Label = Label(root, text="Are you ready?")
Label.pack()
root.title("quick question")
btn = Button(root, text="Yes", command= open_window)
btn.pack(padx=20, pady = 20)
root.mainloop()
I got this error while I was working on previously seen code: File "C:\Users\User\Desktop\naujas zaidimas\scratch.py", line 11, in open_window
lbl = Label(menu, text ="Hello!").pack
TypeError: 'Label' object is not callable
Does anyone know why/how to fix it?
The code has a number of fairly obvious errors and one insidious error
This import plays no role in current code
from PIL import Image, ImageTk
Not a good or preferred way to import tkinter
This will cause problems later on
from tkinter import *
This is unnecessary with the current inport method
from tkinter import Label
def open_window():
The rule for Python functions is: Names created in functions stay in functions.
It will require a global instruction to make 'menu' available elsewhere in your code
menu = Toplevel(root)
menu.geometry("800x800")
menu.title("my game's menu")
menu.resizable(False, False)
Duplicated geometry instruction
menu.geometry("800x800")
This object has already been defined as a Label object so trying to name it throws a TypeError
lbl = Label(menu, text ="Hello!").pack()
This is unnecessary since root.mainloop() has already been executed
menu.mainloop()
root = Tk()
root.geometry("400x300")
Here is another naming problem caused by the import method chosen
Label = Label(root, text="Are you ready?")
Label.pack()
root.title("quick question")
This button will enable you to create MANY Toplevel windows
The problem is, ALL of them will be called 'menu'!?
This is the insidious error
btn = Button(root, text="Yes", command= open_window)
btn.pack(padx=20, pady = 20)
root.mainloop()
# This solution avoids all the previous problems
import tkinter as tk
root = tk.Tk()
root.title("quick question")
root.geometry("400x300")
tk.Label(root, text = "Are you ready?").pack()
# This will give tkinter time to process the given instructions.
root.update()
menu = tk.Toplevel(root)
# withdraw will make menu temporarily invisible
menu.withdraw()
menu.title("my game's menu")
menu.geometry("800x800")
menu.resizable(False, False)
tk.Label(menu, text = "Hello!").pack()
# command will now make menu window visible
btn = tk.Button(root, text = "Yes", command = menu.deiconify)
btn.pack(padx = 20, pady = 20)
root.mainloop()
from PIL import Image, ImageTk
from tkinter import *
def open_window():
menu = Toplevel(root)
menu.geometry("800x800")
menu.title("my game's menu")
menu.resizable(False, False)
menu.geometry("800x800")
lbl = Label(menu, text ="Hello!").pack()
menu.mainloop()
root = Tk()
root.geometry("400x300")
lbl1 = Label(root, text="Are you ready?").pack()
root.title("quick question")
btn = Button(root, text="Yes", command= open_window)
btn.pack(padx=20, pady = 20)
root.mainloop()
I Played around both our codes and now somewhy it works.

How to Display Progress bar from Windows shell in TKinter?

I am running an "Any file type to PDF Convertor" code using python. When I convert Word files to PDF, it displays a progress bar in the Windows Shell like so:
But I want this progress bar to be displayed inside the Tkinter window.
Is there a way to do this?
Because when I run it as an exe, I cannot let "-w" stay there otherwise the program crashes.
Here's the code:
from tkinter import *
from PIL import Image
from tkinter import filedialog
def buttonclick():
root.filename=filedialog.askopenfilename(initialdir="Pictures", title="Select File", filetypes=(("All Files","*.*"),("PNG Files","*.png"),("JPG Files","*.jpg")))
try:
locus=root.filename.split(".")
dest=str(locus[0]+".pdf")
if str(locus[-1])=="docx":
from docx2pdf import convert
'''
import ttk as t
progressbar = t.Progressbar(orient=HORIZONTAL, length=200, mode='determinate')
progressbar.pack(side="bottom")
'''
convert(root.filename,dest)
#progressbar.start()
notifier=Label(root, text="File converted to PDF successfully!", fg="green", bg="#BFDFFF").pack()
elif str(locus[-1])=="pdf":
notifier=Label(root, text="PDF file Selected! Choose another file type.", fg="black", bg="#BFDFFF").pack()
elif str(locus[-1])=="":
notifier=Label(root, text="Please select a file!", fg="black", bg="#BFDFFF").pack()
else:
imge=Image.open(root.filename)
im1 = imge.convert('RGB')
im1.save(dest)
notifier=Label(root, text="File converted to PDF successfully!", fg="green", bg="#BFDFFF").pack()
except:
notifier=Label(root, text="An unexpected error occured!", fg="red", bg="#BFDFFF").pack()
root=Tk()
root.title("Any File to PDF Convertor")
root.config(bg="#BFDFFF")
root.geometry("300x200")
root.iconbitmap("D:\Coding\MyIcon.ico")
convert=Button(root, text="Select File",font=("Helvetica", 20), bg="#85FF97",command=lambda: buttonclick())
convert.pack(pady=20)
root.mainloop()
Why not try a progress bar widget. Check out this code. I did not bother adapting my solution to your case since you have accepted the answer:
from tkinter import *
from tkinter.ttk import *
import os
root = Tk()
# I set the length and maximum as shown to demonstrate the process in the
# proceeding function. Pay attention to the increment r
progress = Progressbar(root, orient = HORIZONTAL,
length = 200/5, maximum=200/5, mode = 'determinate')
# Function
def my_func():
t=0
r= 1/5
for i in range(200):
print(i) #whatever function interests you
t=t+r
progress['value'] = t
root.update_idletasks()
progress.pack()
# Button
Button(root, text = 'Start', command = bar).pack(pady = 10)
mainloop()

Trying to add an image that functions like a button, but this error, image "pyimage2" doesn't exist, pops up

I already have a set of code that is similarly formatted as the one below, and that seems to work. But somehow, the image for this one isn't popping up. And they're in the same folder as the code. Def small is the code that has the image working, and def stripes is the one that is giving me an error.
from tkinter import *
import tkinter as tk
from tkinter import ttk
def small():
s = Tk()
s.title('Small Preset Shirt (Not fit to scale)')
canvas = Canvas(s, width = 800, height = 100)
canvas.pack()
b1=ttk.Button(s,text='Click to Start', command = questions)
b1.pack()
photo = PhotoImage(file = 'small.png')
b1.config(image=photo,compound=RIGHT)
s.mainloop()
def stripes():
stripes = Tk()
stripes.title('Black Shirt with Stripes')
canvas = Canvas(stripes, width = 800, height = 100)
canvas.pack()
b2=ttk.Button(stripes,text='Click to See Final Price', command = final)
b2.pack()
photo = PhotoImage(file = 'stripes.png')
b2.config(image=photo,compound=RIGHT)
stripes.mainloop()
Here is the full Traceback:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter /__init__.py", line 1705, in __call__
return self.func(*args)
File "/Users/Business/Documents/Python/small.py", line 159, in stripes
b2.config(image=photo,compound=RIGHT)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter. /__init__.py", line 1485, in configure
return self._configure('configure', cnf, kw)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter. /__init__.py", line 1476, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: image "pyimage2" doesn't exist
When you get an error message "_tkinter.TclError: image "pyimage2" doesn't exist" or something like that then it means tkinter can't decide which window's photo it is. This is due to of more than one Tk() windows. There are few other things that create problems when you use more than one Tk, that is why Tkinter have another type of window Toplevel and it refers to the main window like a child window.
Lets get to your code..
Here I see few other problems other than just that error.
Like I said not more than one Tk() window. I believe you probably have more than two.
If you have a main window and decide to open few more with Toplevel then please don't use another mainloop() one is sufficient to open as many Toplevel windows but remember to use at least one mainloop() at the end of your code.
Sometimes when you define a Photoimage in a function which stored an image in a local variable the image is cleared by python even if it’s being displayed by the Label or Canvas. So always create a reference in that case.
As your code is not runnable so I added necessary things to run and test it.
from tkinter import *
from tkinter import ttk
Main_window = Tk() # Make only one Tk main window
Main_window.geometry('300x150')
Main_window.title("Get Shirts (Buy 1 get 1 Free)")
def small():
s = Toplevel() # For secondary window use Toplevel
s.title('Small Preset Shirt (Not fit to scale)')
canvas = Canvas(s, width = 800, height = 100)
canvas.pack()
b1=ttk.Button(s,text='Click to Start', command = None)
b1.pack()
photo = PhotoImage(file = 'logo.png')
b1.img_ref = photo # Create a reference
b1.config(image=photo,compound=RIGHT)
# s.mainloop() # Don't use mainloop more than once
def stripes():
stripes = Toplevel() # For secondary window use Toplevel
stripes.title('Black Shirt with Stripes')
canvas = Canvas(stripes, width = 800, height = 100)
canvas.pack()
b2=ttk.Button(stripes,text='Click to See Final Price', command = None)
b2.pack()
photo = PhotoImage(file = 'logo.png')
b2.img_ref = photo # Sometimes images in functions becomes garbage value.
b2.config(image=photo,compound=RIGHT)
# stripes.mainloop() # Using two of these will do nothnig.
Category_Lb = Label(Main_window, text='Category', font=('',25))
Category_Lb.pack()
Cate_1 = ttk.Button(Main_window, text='Small Preset Shirt', command=small)
Cate_1.pack()
Cate_2 = ttk.Button(Main_window, text='Black Shirt with Stripes', command=stripes)
Cate_2.pack()
Main_window.mainloop()

displaying an image full screen in Python

The following program works the for the first .jpg in the directory.
When called the second time it gets a "_tkinter.TclError: image
"pyimage2" doesn't exist" exception. Why does it get the error? Is
there a way to reuse the first image rather than creating a second?
import sys, os
if sys.version_info[0] == 2:
import Tkinter
tkinter = Tkinter
else:
import tkinter
from PIL import Image, ImageTk
def showPIL(pilImage):
root = tkinter.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
canvas = tkinter.Canvas(root,width=w,height=h)
canvas.pack()
canvas.configure(background='black')
imgWidth, imgHeight = pilImage.size
# resize photo to full screen
ratio = min(w/imgWidth, h/imgHeight)
imgWidth = int(imgWidth*ratio)
imgHeight = int(imgHeight*ratio)
pilImage = pilImage.resize((imgWidth,imgHeight), Image.ANTIALIAS)
image = ImageTk.PhotoImage(pilImage)
print(image)
imagesprite = canvas.create_image(w/2,h/2,image=image)
root.mainloop()
names = os.listdir("E://Users//scott//Pictures")
print(names)
for file in names:
print(file)
if file[-4:] == ".jpg":
file=Image.open("E://Users//scott//Pictures//"+file)
showPIL(file)
Here is the console output. Traceback (most recent call last): File
"e:\Users\scott\Documents\Python\image test.py", line 36, in
showPIL(file) File "e:\Users\scott\Documents\Python\image test.py", line 27, in showPIL
imagesprite = canvas.create_image(w/2,h/2,image=image) File "C:\Program Files\Python37\lib\tkinter__init__.py", line 2486, in
create_image
return self._create('image', args, kw) File "C:\Program Files\Python37\lib\tkinter__init__.py", line 2477, in _create
*(args + self._options(cnf, kw))))
_tkinter.TclError: image "pyimage2" doesn't exist
>
after searching around I discovered that the first problem that tkinter.Tk() was being called multiple times whereas it must be called
only once so I moved it out of the showPIL function and into the
initialization. The next problem is that mainloop blocks so I
replaced it with the combination of root.update_idletasks() and
root.update(). The following works as I expect and need:
import sys, os
if sys.version_info[0] == 2: # the tkinter library changed it's name from Python 2 to 3.
import Tkinter
tkinter = Tkinter #I decided to use a library reference to avoid potential naming conflicts with people's programs.
else:
import tkinter
from PIL import Image, ImageTk
import time
root = tkinter.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
canvas = tkinter.Canvas(root,width=w,height=h)
canvas.pack()
canvas.configure(background='black')
def showPIL(pilImage):
imgWidth, imgHeight = pilImage.size
# resize photo to full screen
ratio = min(w/imgWidth, h/imgHeight)
imgWidth = int(imgWidth*ratio)
imgHeight = int(imgHeight*ratio)
pilImage = pilImage.resize((imgWidth,imgHeight), Image.ANTIALIAS)
image = ImageTk.PhotoImage(pilImage)
imagesprite = canvas.create_image(w/2,h/2,image=image)
root.update_idletasks()
root.update()
# root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
names = os.listdir("E://Users//scott//Pictures")
print(names)
for file in names:
print(file)
if file[-4:] == ".jpg":
file=Image.open("E://Users//scott//Pictures//"+file)
showPIL(file)
time.sleep(5)

Trying to make a program that you push a button, choose a file, and the program then prints a certain value from that file

I'm very new to coding and I tried a bunch of different things but none of them are working for me.
Here is my code. With this code everything is working correctly so far, but i'm unsure of how to implement the read function into my code. My main problem is that in everyone's read examples they use the exact filename, whereas I need to use raw input.
Edit: I was able to solve this on my own, by using open(filename, "r") it lets you pick which file to read. Instead of having "6543.txt" which would only open that specific file.
from tkinter import Tk
from tkinter import *
from tkinter.filedialog import askopenfilename
root = Tk()
root.title("Amazon Error Handler")
root.geometry("300x150")
frame = Frame(root)
frame.pack()
bottomframe = Frame(root)
bottomframe.pack( side = BOTTOM )
def getfile():
filename = askopenfilename()
print(filename)
getfile = open(filename,"r")
print(getfile.read(1))
print(getfile.read())
button = Button(frame, text="Choose File", fg="black", command=getfile)
button.pack( side = BOTTOM)
root.mainloop()
This is the code I used to solve my own problem. This program is just a button that reads a chosen file and prints it's contents.
from tkinter import Tk
from tkinter import *
from tkinter.filedialog import askopenfilename
root = Tk()
root.title("Amazon Error Handler")
root.geometry("300x150")
frame = Frame(root)
frame.pack()
bottomframe = Frame(root)
bottomframe.pack( side = BOTTOM )
def getfile():
filename = askopenfilename()
print(filename)
getfile = open(filename,"r")
print(getfile.read(1))
print(getfile.read())
button = Button(frame, text="Choose File", fg="black", command=getfile)
button.pack( side = BOTTOM)
root.mainloop()

Resources