I can't pass parent variables through Tkinter in Python 2.7 - python

First of All, I have to say that I am a beginner in Python, so my code might appears redundant or muddled.
I made this code which consists of two classes that are both tkinter frame. The class ExportGUI inherits from Hdf5GUI and is called by the function export. The thing is I am trying to access the parent variable datasetsfilter through a child function but it doesnt work :
# Parent class
class Hdf5GUI(GUI):
def __init__(self,hdf5w,master):
# Frame definition
self.master = master # parent root
self.hdf5w = hdf5w #root
self.hdf5w.title('Hdf5 Reader')
self.hdf5w.rowconfigure(0,weight=1)
self.hdf5w.columnconfigure(0,weight=1)
self.hdf5w.columnconfigure(1,weight=1)
self.frameDataset = Frame(self.hdf5w,padx=5,pady=5)
self.frameDataset.grid(row=0,column=0,sticky='wesn')
self.frameDataset.rowconfigure(1,weight=1)
self.frameDataset.columnconfigure(0,weight=1)
self.datasetpath_button = Button(self.frameDataset,text="Export dataset path",command = self.exportDatasetPath)
self.datasetpath_button.grid(row=0,column=0,columnspan=2,pady=5,sticky='nwe')
self.dataset_scrollbar = Scrollbar(self.frameDataset)
self.dataset_scrollbar.grid(row=1,column=1,sticky='esn')
self.dataset_listbox = Listbox(self.frameDataset,exportselection=0)
self.dataset_listbox.grid(row=1,column=0,sticky='wesn')
self.dataset_listbox.bind('<<ListboxSelect>>', self.onSelectDataset)
self.dataset_listbox.config(yscrollcommand=self.dataset_scrollbar.set)
self.dataset_scrollbar.config(command=self.dataset_listbox.yview)
self.datatype_scrollbar = Scrollbar(self.frameDataset)
self.datatype_scrollbar.grid(row=2,column=1,sticky='esn')
self.datatype_listbox = Listbox(self.frameDataset,selectmode='extended',exportselection=0)
self.datatype_listbox.grid(row=2,column=0,sticky='wesn')
# self.dataset_listbox.bind('<<ListboxSelect>>', self.onSelectDataset)
#
self.datatype_listbox.config(yscrollcommand=self.datatype_scrollbar.set)
self.datatype_scrollbar.config(command=self.datatype_listbox.yview)
self.frameFilter = Frame(self.frameDataset)
self.frameFilter.grid(row=3,column=0,sticky='wen')
self.frameFilter.columnconfigure(0,weight=1)
self.frameFilter.columnconfigure(1,weight=1)
self.frameFilter.columnconfigure(2,weight=1)
self.frameFilter.columnconfigure(3,weight=1)
self.filter_label = Label(self.frameFilter,text="Dataset filter")
self.filter_label.grid(row=0,column=0,columnspan=4,sticky='wen')
self.filter0 = Listbox(self.frameFilter,exportselection=0)
self.filter0.grid(row=1,column=0,sticky='wen')
self.filter0.bind('<<ListboxSelect>>', self.onSelectFilter0)
self.filter1 = Listbox(self.frameFilter,exportselection=0)
self.filter1.grid(row=1,column=1,sticky='wen')
self.filter1.bind('<<ListboxSelect>>', self.onSelectFilter1)
self.filter2 = Listbox(self.frameFilter,exportselection=0)
self.filter2.grid(row=1,column=2,sticky='wen')
self.filter2.bind('<<ListboxSelect>>', self.onSelectFilter2)
self.filter3 = Listbox(self.frameFilter,exportselection=0)
self.filter3.grid(row=1,column=3,sticky='wen')
self.frameFile = Frame(self.hdf5w,padx=5,pady=5)
self.frameFile.grid(row=0,column=1,sticky='wesn')
self.frameFile.rowconfigure(1,weight=1)
self.frameFile.columnconfigure(0,weight=1)
self.folderPath_button = Button(self.frameFile,text="Open files in directory",command=self.exportFiles)
self.folderPath_button.grid(row=0,column=0,columnspan=2,pady=5,sticky='wen')
self.files_listbox = Listbox(self.frameFile,selectmode='extended',exportselection=0)
self.files_listbox.grid(row=1,column=0,sticky='wesn')
self.files_scrollbar = Scrollbar(self.frameFile)
self.files_scrollbar.grid(row=1,column=1,sticky='esn')
self.files_listbox.config(yscrollcommand=self.files_scrollbar.set)
self.files_scrollbar.config(command=self.files_listbox.yview)
self.displayData_button = Button(self.frameFile, text="display dataset", command=self.displayData)
self.displayData_button.grid(row=2,column=0,columnspan=2,padx=10,pady=5,sticky='wen')
self.displayTxt_button = Button(self.frameFile, text="Export", command=self.export)
self.displayTxt_button.grid(row=2,column=1,columnspan=2,padx=10,pady=5,sticky='wen')
# self.lblFrame = LabelFrame()
self.hdf5w.protocol("WM_DELETE_WINDOW", self.onClosing)
self.hdf5w.mainloop()
def exportDatasetPath(self):
self.dataset_listbox.delete(0,'end')
self.filter0.delete(0,'end')
self.filter1.delete(0,'end')
self.filter2.delete(0,'end')
self.filter3.delete(0,'end')
self.ohdf5 = Hdf5()
print(self.ohdf5.loadcase_label_list)
i = 0
for dataset in self.ohdf5.datasets:
self.dataset_listbox.insert(i,dataset)
i+=1
i = 0
for item in self.ohdf5.filter0:
self.filter0.insert(i,item)
i+=1
def onSelectDataset(self,evt):
self.datatype_listbox.delete(0,'end')
index = self.dataset_listbox.curselection()[0]
datasetPath = self.dataset_listbox.get(index)
self.odataset = self.ohdf5.getDataset(datasetPath)
i=0
for col in self.odataset.columns:
self.datatype_listbox.insert(i,col)
i+=1
def onSelectFilter0(self,evt):
self.dataset_listbox.delete(0,'end')
self.filter1.delete(0,'end')
self.filter2.delete(0,'end')
self.filter3.delete(0,'end')
index = self.filter0.curselection()[0]
item0 = self.filter0.get(index)
if item0 == 'NASTRAN':
i = 0
for dataset in self.ohdf5.datasets:
self.dataset_listbox.insert(i,dataset)
i+=1
else:
self.ohdf5.setFilterGroupPath(item0)
self.ohdf5.setFilterGroup(self.ohdf5.filterGroupPath)
i = 0
self.datasetsfilter = self.ohdf5.getDatasets(self.ohdf5.filterGroupPath)
for dataset in self.datasetsfilter:
self.dataset_listbox.insert(i,dataset)
i+=1
i = 0
for item in self.ohdf5.filter1:
self.filter1.insert(i,item)
i+=1
def onSelectFilter1(self,evt):
self.dataset_listbox.delete(0,'end')
self.filter2.delete(0,'end')
self.filter3.delete(0,'end')
index = self.filter0.curselection()[0]
item0 = self.filter0.get(index)
index = self.filter1.curselection()[0]
item1 = self.filter1.get(index)
self.ohdf5.setFilterGroupPath(item0,item1)
self.ohdf5.setFilterGroup(self.ohdf5.filterGroupPath)
i = 0
self.datasetsfilter = self.ohdf5.getDatasets(self.ohdf5.filterGroupPath)
print(self.datasetsfilter)
for dataset in self.datasetsfilter:
self.dataset_listbox.insert(i,dataset)
i+=1
i = 0
for item in self.ohdf5.filter2:
self.filter2.insert(i,item)
i+=1
def onSelectFilter2(self,evt):
self.dataset_listbox.delete(0,'end')
self.filter3.delete(0,'end')
index = self.filter0.curselection()[0]
item0 = self.filter0.get(index)
index = self.filter1.curselection()[0]
item1 = self.filter1.get(index)
index = self.filter2.curselection()[0]
item2 = self.filter2.get(index)
self.ohdf5.setFilterGroupPath(item0,item1,item2)
self.ohdf5.setFilterGroup(self.ohdf5.filterGroupPath)
i = 0
self.datasetsfilter = self.ohdf5.getDatasets(self.ohdf5.filterGroupPath)
print(self.datasetsfilter)
for dataset in self.datasetsfilter:
self.dataset_listbox.insert(i,dataset)
i+=1
i = 0
for item in self.ohdf5.filter3:
self.filter3.insert(i,item)
i+=1
def exportFiles(self):
self.files_listbox.delete(0,'end')
title = 'Choose the working HDF5 directory where there are *.h5 files :'
Tk().withdraw()
dirname_root = askdirectory(initialdir=os.getcwd(), title = title)
self.filePath_list = []
for folders, subfolders,files in os.walk(dirname_root):
for f in files:
ext = os.path.splitext(f)[1]
if ext == '.h5': self.filePath_list.append(os.path.join(folders,f))
i = 0
for path in self.filePath_list:
self.files_listbox.insert(i,os.path.basename(path))
i+=1
def onClosing(self):
# if tkMessageBox.askokcancel("Quit", "Do you want to quit?"):
self.hdf5w.destroy()
self.show(self.master)
def displayData(self):
print('function dislaying datas')
datas = self.datatype_listbox.curselection()
print(datas)
new_window = Toplevel(self.frameFile)
w = DisplayDataGUI(new_window, self.odataset, datas)
def get_datasetsfilter(self):
return self.datasetsfilter
def export(self):
new_window2 = Toplevel(self.frameFile)
w = ExportGUI(self.hdf5w,new_window2)
So until now my code perfectly works but I had to complete my program with some other functions that I call in ExportGUI. For example export_filter.
#==============================================================================
# Child class
#==============================================================================
class ExportGUI(Hdf5GUI):
def __init__(self,hdf5w, master):
self.master = master
self.master.title("Export")
self.master.geometry('200x200')
label = Label(self.master, text="Choose the kind of export")
label.place(x=20, y=0)
export_selected = Button(self.master, text = 'Export filters',command=self.export_filter)
export_selected.place(x=20, y=50)
self.master.mainloop()
def export_filter(self):
print(self.ohdf5.datatsetsfilter)
But I got the following error :
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\ProgramData\Anaconda2\lib\lib-tk\Tkinter.py", line 1542, in __call__
return self.func(*args)
File "GUI\GUI.py", line 397, in export_filter
print(self.ohdf5.datatsetsfilter)
AttributeError: 'ExportGUI' object has no attribute 'ohdf5'
Neither ohdf5 or datatsetsfilter is known by ExportGUI(I had the same error with self.datatsetsfilter).
Considering this code didnt work I tried to use the super function. I created a function get_datasetsfilter in Hdf5GUI :
def get_datasetsfilter(self):
return self.datasetsfilter
and then called it in ExportGUI (I added __metaclass__ = type to fix type prblm in 2.7) :
def export_filter(self):
super(ExportGUI, self).get_datasetsfilter
I admit I saw many other exemple with Super but they all seems to be used in __init__ method. However, it still doesnt work. I am now wondering if the error results from my bad comprehension of inheritance or tkinter.

The problem is that you have overwritten the __init__ method from the parent class. Usually what you is first call the __init__ method from the parent class that can be accessed using the super(). So your code should be something like:
class ExportGUI(Parent_Class):
def __init__(self, hdf5w, master):
super().__init__(hdf5w, master)
self.master = master
self.master.title("Export")
self.master.geometry('200x200')
UPDATE:
Now that you've cleared certain details I can augment this answer. Notice that the __init__ call from the ExportGUI is now called with two passed arguments, namely hdf5w and master, the first one is needed to successfully call the __init__ from the parent class. Thus you need to change the code in the definiton of Parent_Class where you're creating an instance of ExportGUI, so that a proper value for hdf5w will be passed in -- my guess would be, you want to pass the value from the parent class:
def export(self):
new_window2 = Toplevel(self.frameFile)
w = ExportGUI(self.hdf5w, new_window2)
And I can't help but notice, that the arguments passed to Parent_Class.__init__ namely hdf5w and master are not used anywhere. Maybe you want to either save those in variables, for example:
class Parent_Class(GUI):
def __init__(self,hdf5w,master):
self.hdf5w = hdf5w
self.master = master
If those are the same and should be carried across to the ExportGUI they can be simply passed when you're creating an instance in the export function of the Parent_Class. If you don't need them and decide to remove them, make sure to modify the __init__ call of the Parent_Class as well as the super().__init__ call in the ExportGUI.

Related

Image for Canvas is not created

So I want a window that updates a shown picture after clicking.
It works fine as long as there is no further tk.Tk() instance (remove/add line 8 of the code below).
If one is created before, this error is raised:
line 29, in CreatePeakSelectionWindow
[...]
self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.img1)
[...]
_tkinter.TclError: image "pyimage1" doesn't exist
I think I need to pass some argument to Tk()?
I don't know where to even look to address this issue and understand how it is caused.
Sadly this widget is to be used to allow manual selection of some peaks and should be done in an external window.
FYI all arrays are dummies (random arrays) for simplicities sake.
Thank you very much for any help!
The code which causes the issue is the following:
import tkinter as tk
import numpy as np
from PIL import Image,ImageTk
import matplotlib.pyplot as plt
class Dummy:
def __init__(self):
self.MainWin = tk.Tk() #>this line causes the issue
imgs = np.random.randint(0,255,(512,624,2))
self.img = imgs[:,:,0] #self.img is a numpy array in black and white
self.imgSize = self.img.shape
self.peakList = np.array([[200,200],[300,400]])
self.selectedIndexOfPeaksList = []
self.peakListGenerated = True
def CreatePeakSelectionWindow(self):
if self.peakListGenerated:
self.selectedIndexOfPeaksList = []
self.PeakSelectionWindow = tk.Tk()
self.PeakSelectionWindow.protocol("WM_DELETE_WINDOW",self.PeakSelectionWindowClose)
self.PeakSelectionWindow.geometry("%sx%s"%(self.imgSize[1],self.imgSize[0]))
self.PeakSelectionWindow.title("Peak Slection")
self.img1 = ImageTk.PhotoImage(image=Image.fromarray(self.img))
self.imgCanvas = tk.Canvas(self.PeakSelectionWindow,width=self.imgSize[1],height=self.imgSize[0])
self.imgCanvas.place(x=0,y=0)
self.PeakSelectionWindow.bind("<Button 1>",self.LeftClick)
self.PeakSelectionWindow.bind("<Button 3>",self.RightClick)
self.PeakSelectionWindow.update()
self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.img1)
else:
print("List of peaks has not yet been generated!",file=sys.stderr)
def PeakSelectionWindowClose (self):
if len(self.selectedIndexOfPeaksList) > 0:
print("put extraction here")
#self.selectedPeaksEntry.insert(tk.END,", ".join(map(str,self.selectedIndexOfPeaksList)))
self.PeakSelectionWindow.destroy()
def LeftClick(self,event):
distance = np.sqrt((self.peakList[:,1]-event.x)**2+(self.peakList[:,0]-event.y)**2)
index = np.argmin(distance)
if index not in self.selectedIndexOfPeaksList:
self.peakList[index]
self.selectedIndexOfPeaksList += [index]
newImg = np.random.randint(0,255,(self.img.shape[0],self.img.shape[1],3))
self.PeakSelectionWindow.newImg = img = ImageTk.PhotoImage(image=Image.fromarray(newImg.astype("uint8"),mode="RGB"))
self.imgCanvas.delete("all")
self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.PeakSelectionWindow.newImg)
self.imgCanvas.update()
def RightClick (self,event):
distance = np.sqrt((self.peakList[:,1]-event.x)**2+(self.peakList[:,0]-event.y)**2)
index = np.argmin(distance)
print(self.selectedIndexOfPeaksList)
if index in self.selectedIndexOfPeaksList:
if len(self.selectedIndexOfPeaksList) > 1:
self.selectedIndexOfPeaksList.remove(index)
newImg = np.random.randint(0,255,(self.img.shape[0],self.img.shape[1],3))
self.PeakSelectionWindow.newImg = img = ImageTk.PhotoImage(image=Image.fromarray(newImg.astype("uint8"),mode="RGB"))
self.imgCanvas.delete("all")
self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.PeakSelectionWindow.newImg)
self.imgCanvas.update()
else:
self.selectedIndexOfPeaksList = []
self.PeakSelectionWindow.newImg = newImg = ImageTk.PhotoImage(image=Image.fromarray(self.img.astype("uint8")))
self.imgCanvas.delete("all")
self.imgCanvas.create_image((0,0),anchor=tk.NW,image=self.PeakSelectionWindow.newImg)
self.imgCanvas.update()
if __name__ == "__main__":
window = Dummy()
window.CreatePeakSelectionWindow()
tk.mainloop()
Okay so I found a solution.
The additional window needs to be a class with tk.Toplevel().
All changes for the code above are:
class Dummy: to class Dummy (tk.Toplevel()):
def __init__(self): to def __init__ (self,master):
self.peakSelectionWindow to self (as a reference to master
passed to the class)
any tk object (like buttons) also needs this master set as the window too to be rendered
Of course the creation of the first window should be handled outside of the class, passing the windowName = tk.Tk() onto the call of Dummy like a normal variable/reference.
In case you need to share variables of the master to this dummy class, I think windowName.variableName = 5 makes them known/accessable in dummy too (via self.variableName). However this might be messy, so instead pass them on normally if possible.

Is there anyway that I can assign different name to Labels using Loop? [duplicate]

I am trying to create a framework to create a label, text box and button as an object, I can extend it easily.
Idea:
Original
after extend
and it could extend to have 3, 4, 5 or more if it have more file, just declare in dictionary list, it will extend automatically.
The code I have:
def getpath(entry_box, type):
# path or file
if type == 'path':
entry_box.set(filedial.askdirectory())
elif type == 'file':
entry_box.set(filedial.askopenfilename())
MainWin = tk.Tk() # Create main windows
MainWin.title('Get file and path') # App name
# Create root container to hold Frames
mainFrame = ttk.Frame(MainWin)
mainFrame.grid(column=1, row=1)
# define the object to create in dictionary, format:
# {object name:[title name, default path, button name, file or folder path]}
obj2create ={'file1':['ABC Location: ', r'C:/', 'Get ABC','file'],
'file2': ['DEF Location:', r'C:/1/', 'Get DEF', 'file']}
ttl_obj = 0
for key in obj2create:
ttl_obj +=1
vir = obj2create[key]
# Module for get file:
obj_name = key
title = vir[0]
default_path = vir[1]
btn_name = vir[2]
get_type = vir[3]
# Create main container
pa_frame = ttk.Frame(mainFrame)
pa_frame.grid(column=1, row=10*ttl_obj, sticky=tk.W)
pa_frame.config(width = 100)
# Row 1: Label
frame_name = obj_name + '_name'
print(frame_name)
frame_name = ttk.Label(pa_frame, text= title).grid(column=1, row=10*ttl_obj,sticky=tk.W)
# Row 2: path and button
# assign type
path_loc = obj_name + '_path'
path_loc = tk.StringVar()
path_loc.set(default_path)
# put in frame
fileLocPath = obj_name + '_loc_path'
fileLocPath = ttk.Entry(pa_frame, width=70, textvariable=path_loc)
fileLocPath.grid(column=1, row=30*ttl_obj) # Assign position
# Get file button
# define button display text and assign the command / function
bt_get_file_path = obj_name + '_btn'
bt_get_file_path = ttk.Button(pa_frame, text= btn_name,
command=lambda: getpath(path_loc, get_type))
# Position Button in second row, second column (zero-based)
bt_get_file_path.grid(column=2, row=30*ttl_obj)
# Auto popup when open
MainWin.mainloop() # Let the window keep running until close
Issue:
Default file path appear in second text box only.
All the button location point to second box.
I also not sure how could I get the value in different box, the "path_loc = obj_name + '_path'" not able to get the correct object.
How should I make it work? Or the way I use is wrong?
Tkinter widgets are no different than any other python objects with respect to creating them in a loop. Your problem seems to be that you don't know how to create a unique variable for an unknown number of widgets.
The important thing to know is that you don't need a unique variable for each widget. Instead, you can use a list or dictionary, either of which can be easily extended at runtime.
Saving widget references in a dictionary
Here is a solution using a dictionary:
entries = {}
for key in obj2create:
...
entries[key] = ttk.Entry(...)
...
...
print("the value for file1 is", entries["file1"].get()
Creating a custom compound widget
If you're wanting to create sets of widgets that are to be treated as a group, it may be better to create a class. In effect, you're creating your own custom widget. This type of class is often called a "compound widget" or "megawidget".
For example:
class FileWidget(ttk.Frame):
def __init__(self, parent, name):
ttk.Frame.__init__(self, parent)
self.label = ttk.Label(self, text="%s Location" % name)
self.fileLocPath = ttk.Entry(self)
self.bt_get_file_path = ttk.Button(self, text=name, command=self.get_path)
...
def get_path(self):
return self.fileLocPath.get()
You can then create each row in your GUI like this:
widgets = {}
for key in obj2create:
widgets[key] = FileWidget(mainFrame, key)
widgets[key].pack(side="top", fill="x")
Later, you can get back the values like this:
for key in obj2create:
widget = widgets[key]
print("%s: %s" % (key, widget.get_path())

AttributeError: 'MyReturnWindow' object has no attribute 'selected_index'

So, I have got the following code in my second(return) window:
Why do I get the above error in returnMovie:
index = self.selected_index.get()
I know that the returnMovie function isn't working, I am just curious why I get that error?
def returnMovie(self):
returningAccount = controll1.GetAccount(self.Input.get())
return_dialog = MyReturnWindow(self, returningAccount)
self.wait_window(return_dialog)
class MyReturnWindow(Toplevel):
def __init__(self, parent, Account):
super().__init__(parent)
self.second_frame = Frame(self)
self.second_frame.pack(fill=BOTH, expand=True)
self.myReturnButton = Button(self, text='Return', command=self.returnMovie(Account))
self.myReturnButton.pack(side=LEFT)
self.selected_index = IntVar(self, -1)
self.item_source = Variable(self, Account.get_movies())
self.item_source.set(Account.get_movies())
self.listbox_return = Listbox(self.second_frame, listvariable=self.item_source)
self.listbox_return.bind("<<ListboxSelect>>", self.listbox_return_selection_changed)
self.listbox_return.pack(fill=BOTH, expand=True)
def listbox_return_selection_changed(self, event):
index = self.listbox_return.curselection()[0]
self.selected_index.set(index)
self.selected_movie.set(controll1.GetMovies()[index])
def returnMovie(self, Account):
index = self.selected_index.get()
movie = self.selected_movie.get()
if index in range(0, self.listbox_return.size()):
controll1.GetAccountMovies(Account).pop(index)
controll1.GetMovies().pop(index)
self.item_source.set(controll1.GetAccountMovies(Account))
else:
messagebox.showerror('No Movie found', 'There was no movie found')
You get the error because of this line of code:
self.myReturnButton = Button(self, text='Return', command=self.returnMovie(Account))
The above code is exactly the same as this:
result = self.returnMovie(Account)
self.myReturnButton = Button(self, text='Return', command=result)
Thus, you are calling self.returnMovie(Account) before setting self.selected_index, so it throws an error when it tries to reference that attribute.
When setting the command option you must provide a callable -- essentially the name of a function. Normally you should provide a command that doesn't require an argument, but since your command requires an argument then a simple solution is to use lambda:
self.myReturnButton = Button(..., command=lambda: self.returnMovie(Account))

How to dynamically add remove and delete labels created in a for loop from text file

I am trying to display a list of users saved in a text file on a line by line basis and have it updated as people launch and close my program respectively. I can't figure out how to update the labels as in create new ones and delete ones no longer present in the text file as I can't .set() or .config() them as far as I know since the actual text on the labels doesn't have to change.
Here is my code so far.
def list_users(self):
with open("usercheck.txt", "r") as ulst:
self.usr_list = []
for line in ulst:
self.usr_list.append(line)
def online(self):
for self.name in self.usr_list:
self.onlbl = tk.Label(self, text = self.name,bg = "#42f480")
self.onlbl.grid(row = self.onlcnt,column = 5,padx = 0)
self.onlcnt +=1
Running the online function with after just creates duplicates of the same label and does not update the amount of labels. self.onlcnt is 0
The reason might be that you are using the self keyword in your loop variable, which causes the variable to stay constant: don’t.
def online(self):
for name in self.usr_list:
self.onlbl = tk.Label(self, text = name,bg = "#42f480")
self.onlbl.grid(row = self.onlcnt,column = 5,padx = 0)
self.onlcnt +=1
Also you might want to store the Labels in a list, so you can access them later:
def online(self):
try:
self.labels
except AttributeError:
self.labels = []
self.onlcnt = 0
for name in self.usr_list:
onlbl = tk.Label(self, text = name,bg = "#42f480")
onlbl.grid(row = self.onlcnt,column = 5,padx = 0)
self.labels.append(onlbl)
self.onlcnt +=1
root.after(5000, self.online) #run it again

Python 3.3 Can't change Tkinter Label text attribute

I keep on getting an attribute error when trying to changing the text attribute of a tk label.
I declare it and it uses a temp image so it does exist but when I attempt to change it I get the error. If someone knows a better way to change the image or display it in a better method I would greatly like to here.
Here is the relevent code
self.threadLabelImage = tk.Label(self.threadFrame,image=self.threadImage,wraplength=400,padx=20,pady=5).grid(row=7,column=10,sticky = tk.EW)
self.threadFrame.grid(row=0,column=10,sticky=tk.EW,rowspan=8)
self.threadFrame.grid_propagate(0)
self.QUIT = tk.Button(self, text="QUIT", fg="red", command=main.destroy,padx=5, pady=5).grid(row=7)
def updateSelected(self, event):
# getting selected listbox item
i=self.thread_lb.curselection()
# Returns tuple that must be split
x,self.y,z = re.split("\D+",str(i))
self.y=int(self.y)
print(self.threadTitleList[self.y])
print(self.threadPubDateList[self.y])
print(self.threadLinkList[self.y])
print(self.threadDescList[self.y])
self.threadTitle.set(self.threadTitleList[self.y])
self.threadAuth.set(self.threadAuthList[self.y])
self.threadPub.set(self.threadPubDateList[self.y])
self.threadArtLink.set(self.threadLinkList[self.y])
self.threadLink.set(self.threadDescList[self.y])
self.threadImg.set('Will put image here')
if self.threadLinkList[self.y].find('imgur') != -1:
url = self.threadLinkList[self.y]+'.GIF'
imageName=self.threadLinkList[self.y][-11:-4]
urllib.request.urlretrieve(self.threadLinkList[self.y],imageName+'.jpg')
imgfile = Image.open(imageName+'.jpg')
imgfile = imgfile.resize((150,150),Image.ANTIALIAS)
# img = Image.open(file)
self.threadImage = ImageTk.PhotoImage(imgfile)
self.threadLabelImage.config(text = self.threadImage)
self.threadImage.image = imgfile
And here is the entire program so you can run it if need be.import xml.etree.ElementTree as ET
import webbrowser,time,urllib.request,re
import tkinter as tk
import urllib
from PIL import Image,ImageTk
main = tk.Tk()
class Application(tk.Frame):
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')
photo = Image.open("temp.png")
photo = photo.resize((150,150), Image.ANTIALIAS)
self.threadImage = ImageTk.PhotoImage(photo)
# 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()
# self.threadLabelArtLink = None
# self.threadLabelTitle = None
# self.threadLabelThreadLink = None
# self.threadLabelArtLink = None
# self.threadImgLink = None
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.getXML(self.send_entry.get())).grid(row=0 , column=3)
# Create scrollbar on Y-Axis
self.lb_scrollY = tk.Scrollbar(self,orient=tk.VERTICAL)
# On grid next to Listbox(sticky means fill whole row
self.lb_scrollY.grid(row=1,column=4,sticky=tk.NS,rowspan=6)
# Create Listbox and get Y from scrollbar
self.thread_lb = tk.Listbox(self,yscrollcommand=self.lb_scrollY.set,height=20)
# Calls function whenever a new item is selected
self.thread_lb.bind('<<ListboxSelect>>',self.updateSelected)
self.thread_lb.bind('<Double-Button-1>',self.openPage)
# scrolly will change the view of listbox
self.lb_scrollY['command']=self.thread_lb.yview
self.thread_lb.grid(row=1,column=0,sticky=tk.NS+tk.EW,columnspan=4)
self.threadFrame = tk.LabelFrame(main,text='Reddit',width=450,height=350,labelanchor='n')
self.threadLabelTitle = tk.Label(self.threadFrame,textvariable=self.threadTitle,wraplength=400,padx=20, pady=5).grid(row=1,column=10,sticky= tk.EW)
self.threadLabelAuth = tk.Label(self.threadFrame, textvariable=self.threadAuth,wraplength=400,padx=20, pady=5).grid(row=2,column=10,sticky = tk.EW)
self.threadLabelPub = tk.Label(self.threadFrame, textvariable=self.threadPub,wraplength=400,padx=20, pady=5).grid(row=3,column=10,sticky = tk.EW)
self.threadLabelArtLink = tk.Label(self.threadFrame, textvariable=self.threadArtLink,wraplength=400,padx=20, pady=5).grid(row=4,column=10,sticky = tk.EW)
self.threadLabelThreadLink = tk.Label(self.threadFrame, textvariable=self.threadLink,wraplength=400,padx=20, pady=5).grid(row=5,column=10,sticky = tk.EW)
self.threadImgLink = tk.Label(self.threadFrame, textvariable=self.threadImg,wraplength=400,padx=20, pady=5).grid(row=6,column=10,sticky = tk.EW)
self.threadLabelImage = tk.Label(self.threadFrame,image=self.threadImage,wraplength=400,padx=20,pady=5).grid(row=7,column=10,sticky = tk.EW)
self.threadFrame.grid(row=0,column=10,sticky=tk.EW,rowspan=8)
self.threadFrame.grid_propagate(0)
self.QUIT = tk.Button(self, text="QUIT", fg="red", command=main.destroy,padx=5, pady=5).grid(row=7)
def updateSelected(self, event):
# getting selected listbox item
i=self.thread_lb.curselection()
# Returns tuple that must be split
x,self.y,z = re.split("\D+",str(i))
self.y=int(self.y)
print(self.threadTitleList[self.y])
print(self.threadPubDateList[self.y])
print(self.threadLinkList[self.y])
print(self.threadDescList[self.y])
self.threadTitle.set(self.threadTitleList[self.y])
self.threadAuth.set(self.threadAuthList[self.y])
self.threadPub.set(self.threadPubDateList[self.y])
self.threadArtLink.set(self.threadLinkList[self.y])
self.threadLink.set(self.threadDescList[self.y])
self.threadImg.set('Will put image here')
if self.threadLinkList[self.y].find('imgur') != -1:
url = self.threadLinkList[self.y]+'.GIF'
imageName=self.threadLinkList[self.y][-11:-4]
urllib.request.urlretrieve(self.threadLinkList[self.y],imageName+'.jpg')
imgfile = Image.open(imageName+'.jpg')
imgfile = imgfile.resize((150,150),Image.ANTIALIAS)
# img = Image.open(file)
self.threadImage = ImageTk.PhotoImage(imgfile)
self.threadLabelImage.config(text = self.threadImage)
self.threadImage.image = imgfile
# # threadTitle = self.threadTitleList[y]
# print(self.threadLabelTitle["text"])
# # self.threadLabelTitle['text']=threadTitle
# self.threadLabelAutPub['text']=self.threadPubDateList[y]
# self.threadImgLink['text']=self.threadLinkList[y]
# self.threadLabelThreadLink['text']=self.threadDescList[y]
# main.update()
def openPage(self,event):
webbrowser.get('windows-default').open_new(self.threadLinkList[self.y])
def descStripper(self,desc):
# Intialize values
l1,l2,l2Start = 0,0,0
t1,t2,t2start = 0,0,0
link = ""
thread = ""
# Where to start looking for each in description element
l1=int(desc.find('<br/> <a href="'))
t1=int(desc.find('</a> <a href="'))
a1=int(desc.find('"> '))
# If both of the tags are found then continue
if l1 != -1 and t1 != -1 and a1 != 1:
# Start looking for end of quotes 16 characters from beginning of tag
l2Start = l1+16
l2=int(desc.find('"',l2Start))
# Link is created from what is in the quotes
link = desc[l1+15:l2]
# Same as above but to find thread link
t2start = t1+15
t2=int(desc.find('"',t2start))
thread = desc[t1+14:t2]
a2start = a1+4
a2 = int(desc.find(' <',a2start))
author = desc[a1+3:a2]
return link,thread,author
else:
# If it can't find one it will return an error
link = "Couldn't find the stuff :("
thread = "Couldn't find the thread link :("
return link, thread
def lbPopulator(self,title,pub,link):
# Delete old entries from listbox
self.thread_lb.delete(0,tk.END)
# Iterate through all the items and append them to the listbox
for item in title:
self.thread_lb.insert(tk.END,item)
def getXmlData(self):
# Intialize lists
self.threadPubDateList = []
self.threadTitleList = []
self.threadLinkList = []
self.threadDescList = []
self.threadThumbNailList = []
self.threadAuthList = []
# Use the downloaded rss.xml for XML parsing
tree=ET.parse('rss.xml')
# define root as the base of the XML parsing tree
root=tree.getroot()
for channel in root:
# Iterate through all the channels
for SubChannel in channel:
# Iterate through all the items in the channel
if SubChannel.tag == 'item':
# If the SubChannel is called item then search for the items below
for threadInfo in SubChannel:
# iterate through all the items in the 'item'
if threadInfo.tag == 'title':
# append the tag from the title to the list
self.threadTitleList.append(threadInfo.text)
if threadInfo.tag == 'pubDate':
# Append the pubdate info to the list but remove excess characters
self.threadPubDateList.append(threadInfo.text[:-6])
if threadInfo.tag == 'description':
# Pass all the information from the description to the stripper to get the useful
# information and links
link,thread,author = self.descStripper(threadInfo.text)
self.threadLinkList.append(link)
self.threadDescList.append(thread)
self.threadAuthList.append(author)
# if threadInfo.tag == ''
# Populate the listbox with the newly generated lists
self.lbPopulator(self.threadTitleList,self.threadPubDateList,self.threadLinkList)
def getXML(self,subreddit):
try:
# Try to download the xml file using the user input subreddit
url = 'http://www.reddit.com'+subreddit+'.rss'
source = urllib.request.urlretrieve(url,'rss.xml')
self.getXmlData()
except urllib.error.HTTPError as err:
# Error caused by reddit API limiting connections
print('Too many requests-Try again')
def initial(self):
try:
# Same as above but downloads the front page
source = urllib.request.urlretrieve('http://www.reddit.com/.rss','rss.xml')
self.getXmlData()
except urllib.error.HTTPError as err:
print('Too many requests-Trying again 3')
# If error occurs program waits 3 seconds and then restarts
time.sleep(3)
self.__init__()
# main.geometry("350x400")
app = Application(master=main)
# Begins the applications GUI loop
app.mainloop()
The grid method of a Tkinter widget always returns None. So, any calls to it must be placed on their own line.
Meaning, all of the lines that are written like this:
self.threadLabelTitle = tk.Label(self.threadFrame,textvariable=self.threadTitle,wraplength=400,padx=20, pady=5).grid(row=1,column=10,sticky= tk.EW)
need to be rewritten like this:
self.threadLabelTitle = tk.Label(self.threadFrame,textvariable=self.threadTitle,wraplength=400,padx=20, pady=5)
self.threadLabelTitle.grid(row=1,column=10,sticky= tk.EW)

Categories

Resources