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.
Related
When running the code, I receive this error:
[(<memory at 0x000001ADB67D2040>,)]
1
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=592x1052 at 0x1ADB67FF280>
=-----------------------------------=
pyimage1
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Player 1\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__
return self.func(*args)
File "c:\Users\Player 1\OneDrive\Documents\Year 13\Computer Science\NEA\Code\windows.py", line 373, in <lambda>
images_button = tkinter.Button(self, text="View {} Images".format(listingname), font=('calibre', 20, 'bold'), command=lambda: self.create_command_for_Nav_Buttons("Pictures", condition=listing_id)).grid(column=0, row=0, rowspan=7)
File "c:\Users\Player 1\OneDrive\Documents\Year 13\Computer Science\NEA\Code\windows.py", line 77, in create_command_for_Nav_Buttons
start_window.create_page(condition)
File "c:\Users\Player 1\OneDrive\Documents\Year 13\Computer Science\NEA\Code\windows.py", line 412, in create_page
images = tkinter.Label(master=self, image=photo, width=300, height=300)
File "C:\Users\Player 1\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 3148, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "C:\Users\Player 1\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 2572, in __init__
self.tk.call(
_tkinter.TclError: image "pyimage1" doesn't exist
This is the part of the code that doesn't work.
class picture_page(Window):
def __init__(self, current_window="Pictures!") -> None:
super().__init__(current_window)
def create_page(self, listing_id):
imagesMView_list = dbm.getImagesForListing(listing_id)
print(imagesMView_list)
print(len(imagesMView_list))
if len(imagesMView_list) == 0:
self.create_Label("There are no images!", ('calibre', 20, 'bold'), 0, 0)
else:
processedImage_list = []
for i in range(len(imagesMView_list[0])):
processedImage_list.append(bytes(imagesMView_list[0][i]))
# for i in range(len(processedImage_list)):
# img = Image.open(io.BytesIO(processedImage_list[i]))
# photo = ImageTk.PhotoImage(img)
# print(img)
# print(photo)
# tkinter.Label(master=self, image=photo).pack()
for i in range(len(processedImage_list)):
img = Image.open(io.BytesIO(processedImage_list[i]))
print(img)
print("=-----------------------------------=")
photo = ImageTk.PhotoImage(img)
print(photo)
images = tkinter.Label(master=self, image=photo, width=300, height=300)
images.grid(column=i, row=0)
The commented part that looks like code was another fix I tried.
I also looked through these other stackoverflow questions (Tkinter OOP "PyImage1" doesn't exist, error and Tkinter create image function error (pyimage1 does not exist))
Thank you in advance!
EDIT: I have tried to put Global photo into my code to keep it as a reference, however that still causes the same issue to occur. I also wanted to say that this photo_page subclass inherits from the Windows Class and the Windows class inherits from Tk. This hasn't caused me any issues other than with putting an image in the label. The image comes from a database and in the database is stored as a byte Array and I convert it back into bytes and then into JPEG form (which I know is successful because I printed out the variables I assigned it to and they look fine).
The way I fixed my error was changing what my main class inherited. Initially, it was Windows(Tk): , however I changed it to Windows(Toplevel) and it fixed the issue.
have you by chance accidentally created two or more root windows? Objects in one root window cant see or interact with things
in the second root window
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()
I was trying to make a window with tkinter. On the home screen, I would have a label, a few buttons, and then a Message, all on the tkinter.Canvas. I created them in different functions, but even then, the label and buttons went on the canvas. The Message didn't, returning an error:
File "C:\Users\bobby\AppData\Local\Programs\Python\Python35-32\NFL Model\nflScreen.py", line 54, in homeScreen
self.homeText = tk.Message(master=self.canvas, text=self.getText(0), width=550)
File "C:\Users\bobby\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 2816, in __init__
Widget.__init__(self, master, 'message', cnf, kw)
File "C:\Users\bobby\AppData\Local\Programs\Python\Python35-32\lib\tkinter\__init__.py", line 2139, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: bad window path name ".59508144.59508176"
Here is my code to make the window:
import tkinter as tk
class Window(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.makeScroll(); self.showMenu(); self.homeScreen();
def makeScroll(self):
self.canvas = tk.Canvas(self, bg='#F0F0F0', width=1000, height=600)
self.canvas.grid(row=0, column=0) ###Makes the Canvas. This part works well
def showMenu(self):
self.home = tk.Button(self.canvas, text="Home", command=self.homeScreen, width=10)
self.home.grid(column=0, row=1) ###Make some buttons, this part works well.
self.rank = tk.Button(self.canvas, text="Rankings", command=self.rankingScreen, width=10)
self.rank.grid(column=1, row=1)
###I tried adding a Message here to the canvas, and it worked, but I need the message to be made in another function
def homeScreen(self):
###This part doesn't work. I know that self.canvas is still a variable.
self.homeText = tk.Message(master=self.canvas, text=self.getText(0), width=550)
self.homeText.grid(column=0, row=3, columnspan=7)
Basically, I create the tkinter.Canvas in makeScroll(). When I add widgets to it in showMenu(), that works. But when I try to add widgets in homeScreen(), it doesn't. Does anyone know why, and how to fix it?
I found out after a while that this was just a logic error. In my real code, I called a function that would delete the canvas object at the start of the homeScreen() function.
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()
So I've got a Python 3 and Tkinter app. I'm currently trying to add a menu bar to the top of the window it pops up in. It's fine creating, but as soon as I try to grid() it, it all goes haywire and throws me this error:
[first line omitted]
File "C:\Users\Me\Documents\sync.py", line 13 in __init__
self.createWidgets()
File "C:\Users\Me\Documents\sync.py", line 21, in createWidgets
self.menubar.grid(column = 0, comlumnspan = 3)
File "C:\Program Files (x86)\Python34\lib\tkinter\__init__.py", line 2020, in grid_configure + self._options(cnf,kw))
_tkinter.TclError: can't manage ".41452544.49048880": it's a top-level window
So from that, it's fairly obvious that the flow is working: __init__ calls createWidgets creates self.menubar, adds submenus, calls self.menubar.grid.
What I can't figure out is why Tkinter thinks the menubar it's being called to grid is a top-level window. self.menubar.grid(), being listed in the trace, is clearly the cause of the problem rather than the root window, so that must be what it's thinking.
Here's the bit of code in question:
def createWidgets(self):
self.menubar = tk.Menu(self)
self.menubar.grid(column = 0, columnspan = 3)
SyncMenu = tk.Menu(self.menubar, tearoff = 0)
SyncMenu.add_command(label = "Connect", command = self.Sync.Connect)
SyncMenu.add_command(label = "Disconnect", command = self.Sync.Disconnect)
FileMenu = tk.Menu(self.menubar, tearoff = 0)
FileMenu.add_command(label = "Upload File", command = self.File.Upload)
FileMenu.add_command(label = "Browse Online Files", command = self.File.Browse)
self.menubar.add_cascade(label = "Sync", menu = SyncMenu)
self.menubar.add_cascade(label = "File", menu = FileMenu)
The same error comes up no matter where I put the call to grid().
The other part of this problem is that I'm in Python 3 and the updated Tkinter, so no tk.Tk() for me. Instead, to initialise, I have this:
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master)
self.grid()
self.createWidgets()
self.master.geometry("500x500")
You can't use grid on menus. Tkinter considers them a top-level window because they float above other windows.
The normal way to create a traditional menubar is to associate it with the menu attribute of the root window:
root = tk.Tk()
menubar = tk.Menu(root)
...
root.configure(menu=menubar)
I've figured it out. When I edited the question to add the second code block, I noticed the self.master.geometry line, to which I thought "That line affects the main window, couldn't I use that?"
The answer was yes, so the solution to finding the root window was just to use self.master, which is defined in my __init__ method by the supercall to tk.Frame.__init__:
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self,master) # This line defines self.master
self.grid()
self.createWidgets()
self.master.geometry("500x500") # This line uses it
So the solution to get my menubar into the correct window is now this:
self.master["menu"] = self.menubar
which is in the code after creating all the menu and menu items.