AttributeError: 'dict' object has no attribute 'tk' [duplicate] - python

This question already has an answer here:
AttributeError: object has no attribute 'tk'
(1 answer)
Closed 2 years ago.
I've looked around for a bit, but might of got off track trying to fix the issue.
Trying to scan selected folder for extensions, then populate checkboxes with found extensions for user to select what extensions to move forward with. the amount of checkboxes can change source to source, tried using the super() but don't believe to be using it right.
import os
from tkinter import *
import tkinter #as tk
from tkinter import filedialog
root = tkinter.Tk()
root.withdraw()
file_path = filedialog.askdirectory()
print(file_path)
#src_folder = "../../"
src_folder = file_path
ListFiles = os.walk(src_folder)
SplitTypes = []
for walk_output in ListFiles:
for file_name in walk_output[-1]:
SplitTypes.append(file_name.split(".")[-1])
#print(SplitTypes)
extensions = []
for i in SplitTypes:
if i not in extensions:
extensions.append(i)
extensions = str(extensions)
#print(str(extensions))
print(extensions)
class CheckBox(tkinter.Checkbutton):
boxes = [] # Storage for all buttons
def __init__(self, master, *args, **options):
super(CheckBox, self).__init__()
tkinter.Checkbutton.__init__(self, *args, options) # Subclass checkbutton to keep other methods
self.boxes.append(self)
self.var = tkinter.BooleanVar() # var used to store checkbox state (on/off)
self.text = self.cget('text') # store the text for later
self.configure(variable=self.var) # set the checkbox to use our var
a=0
while a<len(extensions):
button=CheckBox(tkinter, text=extensions[a], command=print(extensions[a])) # Replace Checkbutton
a=a+1
button.pack()
extensions_check = []
for box in CheckBox.boxes:
if box.var.get(): # Checks if the button is ticked
extensions_check.append(box.text)
print(extensions_check)
error that i am getting is
C:\Users\Python\Projects\filescanner\Scripts\python.exe C:/Users/Python/Projects/filescanner/extensionfinder.py
F:/TestFolder
['xlsx', 'txt', 'avi', 'nxt']
[
Traceback (most recent call last):
File "C:/Users/Python/Projects/filescanner/extensionfinder.py", line 45, in <module>
button=CheckBox(tkinter, text=extensions[a], command=print(extensions[a])) # Replace Checkbutton
File "C:/Users/Python/Projects/filescanner/extensionfinder.py", line 36, in __init__
tkinter.Checkbutton.__init__(self, *args, options) # Subclass checkbutton to keep other methods
File "C:\Python\Current Install\lib\tkinter\__init__.py", line 2993, in __init__
Widget.__init__(self, master, 'checkbutton', cnf, kw)
File "C:\Python\Current Install\lib\tkinter\__init__.py", line 2561, in __init__
BaseWidget._setup(self, master, cnf)
File "C:\Python\Current Install\lib\tkinter\__init__.py", line 2530, in _setup
self.tk = master.tk
AttributeError: 'dict' object has no attribute 'tk'
Process finished with exit code 1
I am new to the python world and up for any advise, thank you all in advance

There are two errors (at least, two that cause the error you describe):
button=CheckBox(tkinter, text=extensions[a], command=print(extensions[a]))
Should be:
button=CheckBox(root, text=extensions[a], command=print(extensions[a]))
And:
tkinter.Checkbutton.__init__(self, *args, options)
Should be:
tkinter.Checkbutton.__init__(self, master, *args, options)
You should either use one of the two lines below:
super().__init__(master, *args, options)
tkinter.Checkbutton.__init__(self, master, *args, options) # Subclass checkbutton to keep other methods
Both are equivalent though most people prefer to use super()

Related

_tkinter.TclError: encountered an unsupported criticial chunk type "exIf"

So I am trying to put some pictures into my window and whenever I run the program it gives me this error:
_tkinter.TclError: encountered an unsupported criticial chunk type "exIf"
I tried putting it into other formats, such as .jpg, .png and .gif, but they don't work. Can you please help me?
This is my code:
from tkinter import *
from tkinter import ttk
class Window:
def __init__(self, master):
self.master = master
master.iconbitmap('ta.ico')
master.title('Tamagochi')
master.minsize(width=480, height=240)
master.maxsize(width=480, height=240)
self.pic1 = PhotoImage(file='pic1.png')
self.pic2 = PhotoImage(file='pic2.png')
self.pic3 = PhotoImage(file='pic3.png')
self.pic4 = PhotoImage(file='pic4.png')
self.smFrame = ttk.Frame(master)
self.smButton1 = ttk.Button(self.smFrame, text='Start', command=self.start)
self.smButton2 = ttk.Button(self.smFrame, text='Options', command=self.options)
self.smButton3 = ttk.Button(self.smFrame, text='Quit', command=self.quit)
self.smPhoto1 = ttk.Label(self.smFrame, image=self.pic1)
self.smFrame.pack()
self.smPhoto1.grid()
self.smButton1.grid(pady=40, padx=200)
self.smButton2.grid(pady=0, padx=200)
self.smButton3.grid(pady=40, padx=200)
def start(self):
pass
def options(self):
pass
def quit(self):
exit()
root = Tk()
Window(root)
root.mainloop()
This is the full error:
Traceback (most recent call last):
File "C:/Users/NemPl/Desktop/ProLan/Python/Python programi/Tamagochi/Tamagochi.py", line 35, in <module>
Window(root)
File "C:/Users/NemPl/Desktop/ProLan/Python/Python programi/Tamagochi/Tamagochi.py", line 14, in __init__
self.pic3 = PhotoImage(file='pic3.png')
File "C:\Users\NemPl\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 3539, in __init__
Image.__init__(self, 'photo', name, cnf, master, **kw)
File "C:\Users\NemPl\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 3495, in __init__
self.tk.call(('image', 'create', imgtype, name,) + options)
_tkinter.TclError: encountered an unsupported criticial chunk type "exIf"
PhotoImage is a tkinter class which, unfortunately, can not deal with .png files.
The solution is to rely on the Python Imaging Library1 which offers support to several image formats and transforms them to image objects that can be "understood" by tkinter:
from PIL import Image, ImageTk
self.img1 = Image.open("pic1.png")
self.pic1 = ImageTk.PhotoImage(self.img1)
1. You can install PIL as described here.
Just wanted to share a solution that solved for me!
I figured out that other '.png' images were working with the same code, so the problem was happening with the image file.
What solved my problem was simply modifying the image (just saved it from a image editor).

How to hide a button by using a class function in python

from tkinter import*
root = Tk()
shape = Canvas(root)
class GUI():
def __init__(self):
pass
def create_button(self, info, boom, posit):
self.Button(root)
self.config(text=info)
self.bind("<Button-1>",boom)
self.grid(column=posit[0],row=posit[1])
def create_label(self, info, posit):
self.Label(root)
self.config(text=info)
self.grid(column=posit[0],row=posit[1])
def go_away(self):
print("GO AWAY before")
self.button.grid_forget()
print("GO AWAY")
def make_GUI():
root.title("Hexahexaflexagon")
hexahexa = GUI()
quit_butt = GUI()
quit_butt.create_button("Exit","root.destroy()",[0,1])
quit_butt.go_away()
make_GUI()
root.mainloop()
Okay so I am trying to write a class function to just hide (and if not that then delete) a button created by tkinter, I'm new to classes and the error message I keep getting is that the GUI class does not have that function or that object does not have that attribute, I've tried code such as frm.forget(), .lower(), .grid_forget() but there not working for me.
The traceback is:
Traceback (most recent call last):
File "N:\HW\Hexahexaflexagon generator.py", line 94, in <module>
make_GUI()
File "N:\HW\Hexahexaflexagon generator.py", line 63, in make_GUI
quit_butt.go_away()
File "N:\HW\Hexahexaflexagon generator.py", line 51, in go_away
self.button.grid_forget()
AttributeError: 'function' object has no attribute 'grid_forget'
The problem is this line:
self = Button(root)
You are redefining self from referring to the current object, to now refer to a different object. You have the same problem further down with a label. This is simply not how python works.
You must store the widgets as attributes on self, not as self itself.
self.button = Button(root)
...
self.label = Label(root)
Once you do that, you can hide the button or label with grid_forget since you're using grid to make it visible:
self.button.grid_forget()
You have another problem in that you're passing in a command as a string. This will not work the way you think it does. If you want to be able to pass in a function, it needs to be a reference to an actual function:
quit_butt.button("Exit",root.destroy,[0,1])

Tkinter: Display image after opening from dialog

This is the first program I'm writing utilizing Tkinter, so I apologize in advance if my questions are a bit naive.
I have the following:
class Example(Frame):
def __init__(self, master=None):
Frame.__init__(self,master)
menubar = Menu(self)
master.config(menu=menubar)
self.centerWindow(master)
self.Top_Bar(menubar,master)
self.pack(fill = BOTH, expand = 1)
def Top_Bar(self,menubar,master):
fileMenu = Menu(menubar,tearoff=False)
menubar.add_cascade(label="File",menu=fileMenu)
fileMenu.add_command(label="Open",command = self.open_file)
fileMenu.add_command(label="Exit",command = self.quit)
fileMenu = Menu(menubar,tearoff=False)
menubar.add_cascade(label="Edit",menu=fileMenu)
fileMenu = Menu(menubar,tearoff=False)
menubar.add_cascade(label="Shortcuts",menu=fileMenu)
fileMenu = Menu(menubar,tearoff=False)
menubar.add_command(label="About",command = Message_About)
Notice that I have self.open_file as a command, which is itself a function:
def open_file(self):
""" A function that opens the file dialog and allows a user to select a single file, displaying it on the page """
global filename
filename = []
filename.append(str(unicodedata.normalize("NFKD",tkFileDialog.askopenfilename(filetypes=[("Astronomical Data","*.fit;*fits")])).encode("ascii","ignore")))
for i in filename:
stretch_type = "linear"
image_manipulation_pyfits.create_png(i,stretch_type)
x = Image.open("file.png")
Label(image = x).pack()
I'm certain there's a shorter, more efficient way of writing this function, but that isn't my primary goal at this point -- it's just to get everything to work. My goal is to take this image x and display it in the Tkinter window. It gives me the error
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\python27\lib\lib-tk\Tkinter.py", line 1486, in __call__
return self.func(*args)
File "tkinter1.py", line 125, in open_file
Label(image = x).pack()
File "C:\python27\lib\lib-tk\ttk.py", line 766, in __init__
Widget.__init__(self, master, "ttk::label", kw)
File "C:\python27\lib\lib-tk\ttk.py", line 564, in __init__
Tkinter.Widget.__init__(self, master, widgetname, kw=kw)
File "C:\python27\lib\lib-tk\Tkinter.py", line 2055, in __init__
(widgetName, self._w) + extra + self._options(cnf))
TclError: image specification must contain an odd number of elements
For clarity, the prior function simply takes an input .fits image (selected from the dialog box that pops up) and applies the linear stretch, then saves it as a .png image to the same directory under the name "file.png".
I've Googled for the past day or so and haven't been able to find any threads on this error.
One solution I have found:
x = Image.open("file.gif")
x = ImageTk.PhotoImage(x)
label = Label(image = x)
label.image = x
label.pack()
Save the image as a .gif and open
Need to use PhotoImage from ImageTk.
I would comment if I could, but just a note about #bjd2385's answer. In his case, label.image = x saves a reference of the image, however if this line of code is omitted, then you would need to save a reference by using self, if using classes in your design pattern. Instead of im = ImageTk.PhotoImage("...") it would then be self.im = ImageTk.PhotoImage("...") otherwise it can get garbage collected and still display an outline of where the image would be, but not actually have an image present.
Also, you can directly open an image from the PhotoImage call. I'm not sure of the complete limitations of image files possible to be used, but I know you can use .gif and .png. Here's his answer reworked for Python3.4:
import tkinter
self.img = ImageTk.PhotoImage(file = "./images/file.png")
label = Label(image = self.img)
label.image = self.img # this line can be omitted if using the 'self' method to save a reference
label.pack()

Tkinter -tkinter.TclError

I have the following code:
from Tkinter import *
from urllib import urlretrieve
import webbrowser
import ttk
def get_latest_launcher():
webbrowser.open("johndoe.com/get_latest")
global percent
percent = 0
def report(count, blockSize, totalSize):
percent += int(count*blockSize*100/totalSize)
homepage = "http://Johndoe.com"
root = Tk()
root.title("Future of Wars launcher")
Button(text="get latest version", command=get_latest_launcher).pack()
global mpb
mpb = ttk.Progressbar(root, orient="horizontal", variable = percent,length="100",
mode="determinate")
mpb.pack()
root.mainloop()
urlretrieve("https://~url~to~my~file.com",
"Smyprogram.exe",reporthook=report)
however, if I run this script, it won't display the progressbar, and it will only display the button. It wont even download the file, and the cursor will just blink. However, if I close the gui window, I get the following code:
Traceback(most recent call last):
File "C:\Users\user\Desktop\downloader.py", line 28 in <module>
mpb = ttk.Progressbar(root, orient="horizontal", variable =
percent,length="100",mode="determinate")
File "C:\Users/user\Desktop\pyttk-0.3\ttk.py" line 1047, in __init__
Widget.__init__(self, master, "ttk::progressbar", kw)
File "C:\Users/user\Desktop\pyttk-0.3\ttk.py", line 574, in __init__
Tkinter.Widget.__init__(self, master, widgetname, kw=kw)
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1930, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: this isn't a Tk applicationNULL main window
What's wrong?
You have at least two problems in your code, though neither of them cause the error you say you're getting.
First, you use a normal python variable as the value of the variable attribute of the progress bar. While this will work, it won't work as you expect. You need to create an instance of a tkinter StringVar or IntVar. Also, you'll need to call the set method of that instance in order for the progressbar to see the change.
Second, you should never have code after the call to mainloop. Tkinter is designed to terminate once mainloop exits (which typically only happens after you destroy the window). You are going to need to move the call to urlretrieve somewhere else.
variable = percent is wrong. You must use Tkinter Variables which are objects. Such as IntVar.

Updating Python Tkinter GUI using .after method

I have a listbox that I want to update every minute or so. It pulls XML data, parses it and put it into the list box automatically. I have figured out to use the .after method but upon implementing it outside of the class I run into bug after bug trying to make it run. I believe my main issue is just not calling the application correctly but I could be wrong. Here is some of the relevent code.
This is all outside the main class
def refresher(frame):
subreddit=Application.entryVar(Application)
Application.getXML(subreddit)
frame.after(1000,refresher,frame)
main = tk.Tk()
main.wm_title("Readdit")
# main.geometry("350x400")
app = Application(master=main)
# Begins the applications GUI loop
# app.__init__()
refresher(main)
app.mainloop()
Here is the beginning of the program and this is where it ultimately falls back upon with all the bugs.
class Application(tk.Frame):
print("what about this?")
def __init__(self, master=None):
self.threadTitle = tk.StringVar()
self.threadAuth = tk.StringVar()
self.threadPub = tk.StringVar()
self.threadArtLink = tk.StringVar()
self.threadLink = tk.StringVar()
self.threadImg = tk.StringVar()
self.threadArtLink.set('Click something to display thread info')
self.photo = Image.open("temp.png")
self.photo = self.photo.resize((250,250), Image.ANTIALIAS)
self.threadImage = ImageTk.PhotoImage(self.photo)
self.errMes = tk.StringVar()
if not os.path.exists('Pics'):
os.makedirs('Pics')
# print('Something')
# Intializes tkinter gui framework
tk.Frame.__init__(self, master)
# Packs widgets needed
self.grid()
# Creates the widgets functions
self.createWidgets()
# Intializes the man rss.xml
self.initial()
def createWidgets(self):
# Create entrybox and align to grid
self.send_entry = tk.Entry(self)
self.send_entry.grid(row=0,column=0)
# Create button,allign to grid, get xml
self.change_sub = tk.Button(self,text='Change Subreddit',padx=5, pady=5, command=lambda :self.entryVar())
And here is the full error
Traceback (most recent call last):
File "S:/Projects/xmlParser.py", line 306, in <module>
refresher(main)
File "S:/Projects/xmlParser.py", line 296, in refresher
subreddit=Application.entryVar(Application)
File "S:/Projects/xmlParser.py", line 290, in entryVar
rawInput=self.createWidgets(self).send_entry.get()
File "S:/Projects/xmlParser.py", line 40, in createWidgets
self.send_entry = tk.Entry(self)
File "C:\Python33\lib\tkinter\__init__.py", line 2506, in __init__
Widget.__init__(self, master, 'entry', cnf, kw)
File "C:\Python33\lib\tkinter\__init__.py", line 2068, in __init__
BaseWidget._setup(self, master, cnf)
File "C:\Python33\lib\tkinter\__init__.py", line 2046, in _setup
self.tk = master.tk
AttributeError: type object 'Application' has no attribute 'tk'
I think you should use your app directly in the function call to refresher:
def refresher(frame):
frame.getXML()# I Don`t know what do this function, just an example
frame.after(1000,refresher,frame)
main = tk.Tk()
main.wm_title("Readdit")
# main.geometry("350x400")
app = Application(master=main)
# Begins the applications GUI loop
# app.__init__()
refresher(app) #use app here
app.mainloop()
It looks like the problem is here:
Application.entryVar(Application)
Application is a class rather than an object, so my guess is that you should be using an instance of Application both places in that code.

Categories

Resources