I can't figure out this Tkinter error - python

I'm using Python's Tkinter to create a GUI for a project i'm working on.
When I try to run part of the code though, I get this error:
Traceback (most recent call last):
File "calculator.py", line 59, in <module>
app = Application()
File "calculator.py", line 28, in __init__
self.create_widgets()
File "calculator.py", line 45, in create_widgets
self.special_chars.create_button(char, self.add_char_event(special_characters[char]))
File "calculator.py", line 20, in create_button
self.button_list += Button(self, text = txt, command = fcn)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/
lib-tk/Tkinter.py", line 1206, in cget
TypeError: cannot concatenate 'str' and 'int' objects
The problem is that I can't find the file that the error message references; my python2.7/lib-tk folder only contains complied versions (.pyo and .pyc) of Tkinter.
Is there a way to figure out what's going wrong?
Here's the source of calculator.py
from Tkinter import *
from exp import full_eval
from maths import special_characters
class special_char_frame(LabelFrame):
def __init__(self, master = None, text = 'Special Characters'):
LabelFrame.__init__(self, master)
self.grid()
self.button_list = []
def create_button(self, txt, fcn):
self.button_list += Button(self, text = txt, command = fcn)
self.button_list[-1].grid(row = 0)
class Application(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
## equation entry pane
self.text_entry = Entry(self, width = 100)
self.text_entry.grid(row = 0, column = 0)
self.text_entry.bind('<KeyPress-Return>', self.calculate)
## result pane
self.result = StringVar()
self.result_label = Label(self, textvariable = self.result, wraplength = 815, justify = LEFT)
self.result_label.grid(row = 1, column = 0, columnspan = 2, sticky = W)
self.result.set('')
## calculate button
self.calc_button = Button(self, text = 'Calculate', command = self.calculate)
self.calc_button.grid(row = 0, column = 1)
## special character button pane
self.special_chars = special_char_frame(self)
for char in special_characters:
self.special_chars.create_button(char, self.add_char_event(special_characters[char]))
self.special_chars.grid(column = 0, columnspan = 2, row = 2)
def calculate(self, event = None):
try:
self.result.set(full_eval(self.text_entry.get()))
except Exception as error:
raise
#self.result.set(str(error))
self.text_entry.select_range(0, END)
def add_char_event(self, char):
def add_char(self = self, event = None):
self.text_entry.insert(INSERT, char)
return add_char
app = Application()
app.master.title('Calculator')
app.mainloop()
full_eval is a function for evaluating mathematical expressions.
special_characters is a dict containing special characters and their explanations. For now it's just special_characters = {'imaginary unit' : u'\u2148'}

Ok, so I missed this the first time, but the issue is actually that you are trying to add a Button to a list:
self.button_list += Button(self, text = txt, command = fcn)
If you simply wrap the Button in brackets, the error goes away (which makes sense because you are supposed to be able to add two lists):
self.button_list += [Button(self, text = txt, command = fcn)]
ORIGINAL ATTEMPT
My guess:
special_characters is a dictionary. It has key-value mappings where the values are ints. Then, when used in self.text_entry.insert(INSERT, char), text_entry is trying to insert an int into a str and causing the above error. The simple solution: wrap char with str in add_char.
def add_char_event(self, char):
def add_char(self = self, event = None):
self.text_entry.insert(INSERT, str(char))
return add_char
Your other option is to wrap str around the special_characters lookup:
for char in special_characters:
self.special_chars.create_button(char,
self.add_char_event(str(special_characters[char])))

Related

tkinter, unable to call a function from outside of it's class

Put simply, i cannot call filterCBOs from the marked problem area within my program. It returns:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Anaconda\envs\SE_win64_py35\lib\tkinter\__init__.py", line 1550, in __call__
return self.func(*args)
File "<ipython-input-24-b9ade6a4c197>", line 116, in callFilters
Root.filterCBOs(self)
File "<ipython-input-24-b9ade6a4c197>", line 164, in filterCBOs
startDate = dt.datetime(year=int(self.fromDate.get()[2]),month=int(self.fromDate.get()[0]),day=int(self.fromDate.get()[1]))
AttributeError: 'Event' object has no attribute 'fromDate'
As you can see, this function works exactly as it should when it is called within init as well as when it is called by selecting a combobox value. It however does not work when it is called by binding the enter key to the entry fields within DateEntry. I am brand new to classes so im sure its something to do with it being called from within another class but I am lost as to how to navigate around this.
#================================================================================
# Imports
#================================================================================
import os
import pandas as pd
import datetime as dt
import tkinter as tk
from tkinter import ttk
startTimestamp=dt.datetime.now()
print('Starting ' + str(startTimestamp))
#================================================================================
# User Changable Variables
#================================================================================
#signaturePath = r'T:\Process Data\EDM\Signature Files'
#================================================================================
# Functions (mostly used to cleanup variables)
#================================================================================
#commented out because i ran this section once and saved to csv. saves me from indexing
#the directory during testing.
'''
def indexDirectory():
#filenames use the following format:
# yyyy.mm.dd.hh.mm.tool.toolSN.feature.sfc.sig
df = pd.DataFrame(columns=['FullPath', 'Timestamp', 'Feature', 'Machine', 'Tool'])
for root, dirs, files in os.walk(signaturePath):
for file in files:
splitter = file.split('.')
if len(splitter) != 10: #weird filename
continue #skip to next file
date=dt.datetime.strptime(splitter[0]+'-'+splitter[1]+'-'+splitter[2]+' '+splitter[3]+':'+splitter[4],'%Y-%m-%d %H:%M')
df = df.append({'FullPath' : os.path.join(root, file), \
'Timestamp' : date, \
'Feature' : splitter[7], \
'Machine' : os.path.basename(root), \
'Tool' : splitter[5] + '_' + splitter[6] \
}, ignore_index=True)
return df
with open(r'C:\Users\u1106710\Desktop\Index.csv', 'w+') as SaTemp:
indexDirectory().to_csv(SaTemp, header=True, index=False)
'''
# Index available signature files to a dataframe
#sigIndex=indexDirectory
sigIndex=pd.read_csv(r'D:\Tibbert\4) Scripts\Signature Analysis\Temp\Index.csv')
sigIndex['Timestamp'] = pd.to_datetime(sigIndex['Timestamp'])
#================================================================================
# Build GUI
#================================================================================
class DateEntry(tk.Frame):
def __init__(self, master, frame_look={}, **look):
args = dict(relief=tk.SUNKEN, border=1)
args.update(frame_look)
tk.Frame.__init__(self, master, **args)
args = {'relief': tk.FLAT}
args.update(look)
self.entry_1 = tk.Entry(self, width=2, **args)
self.label_1 = tk.Label(self, text='/', **args)
self.entry_2 = tk.Entry(self, width=2, **args)
self.label_2 = tk.Label(self, text='/', **args)
self.entry_3 = tk.Entry(self, width=4, **args)
self.entry_1.pack(side=tk.LEFT)
self.label_1.pack(side=tk.LEFT)
self.entry_2.pack(side=tk.LEFT)
self.label_2.pack(side=tk.LEFT)
self.entry_3.pack(side=tk.LEFT)
self.entries = [self.entry_1, self.entry_2, self.entry_3]
self.entry_1.bind('<KeyRelease>', lambda e: self._check(0, 2))
self.entry_2.bind('<KeyRelease>', lambda e: self._check(1, 2))
self.entry_3.bind('<KeyRelease>', lambda e: self._check(2, 4))
#PROBLEM HERE!
#self.entry_1.bind('<Return>', Root.filterCBOs)
#self.entry_2.bind('<Return>', Root.filterCBOs)
#self.entry_3.bind('<Return>', Root.filterCBOs)
def _backspace(self, entry):
cont = entry.get()
entry.delete(0, tk.END)
entry.insert(0, cont[:-1])
def _check(self, index, size):
entry = self.entries[index]
next_index = index + 1
next_entry = self.entries[next_index] if next_index < len(self.entries) else None
data = entry.get()
if len(data) > size or not data.isdigit():
self._backspace(entry)
if len(data) >= size and next_entry:
next_entry.focus()
def get(self):
return [e.get() for e in self.entries]
class Root(tk.Tk):
def __init__(self):
super(Root, self).__init__()
self.title("Filmcool Siganture Analysis")
self.minsize(width=800,height=600)
self.InitUI()
self.filterCBOs()
def InitUI(self):
#Setup Date Entry
self.fromDateLBL = tk.Label(self, text='Date Range')
self.fromDate = DateEntry(self)
self.toDateLBL = tk.Label(self, text='To')
self.toDate = DateEntry(self)
#Set Date Defaults
self.fromDate.entry_1.insert(0,'01')
self.fromDate.entry_2.insert(0,'01')
self.fromDate.entry_3.insert(0,'2014')
self.toDate.entry_1.insert(0,dt.date.today().month)
self.toDate.entry_2.insert(0,dt.date.today().day)
self.toDate.entry_3.insert(0,dt.date.today().year)
#Setup Feature Combobox
self.featureLBL = tk.Label(self, text='Feature')
self.featureCBO = ttk.Combobox(self, width=15)
self.featureCBO.bind('<<ComboboxSelected>>', self.filterCBOs)
#Setup Tool Combobox
self.toolLBL = tk.Label(self, text='Tool')
self.toolCBO = ttk.Combobox(self, width=15)
self.toolCBO.bind('<<ComboboxSelected>>', self.filterCBOs)
#Arrange UI Elements
self.fromDateLBL.grid(column=0,row=4)
self.fromDate.grid(column=1,row=4,sticky='e')
self.toDateLBL.grid(column=2,row=4,sticky='e')
self.toDate.grid(column=3,row=4)
self.featureLBL.grid(column=0, row=0, sticky='w')
self.featureCBO.grid(column=1, row=0)
self.toolLBL.grid(column=0, row=1, sticky='w')
self.toolCBO.grid(column=1, row=1)
def filterCBOs(self, event=None):
#Create and filter dataframe
df=sigIndex
#Filter by Date
#THROWS ERROR ON NEXT LINE
startDate = dt.datetime(year=int(self.fromDate.get()[2]),month=int(self.fromDate.get()[0]),day=int(self.fromDate.get()[1]))
endDate = dt.datetime(year=int(self.toDate.get()[2]),month=int(self.toDate.get()[0]),day=int(self.toDate.get()[1]))
print(startDate)
print(endDate)
df=df[(df['Timestamp'] >= startDate) & (df['Timestamp'] <= endDate)]
#Filter by Feature
if self.featureCBO.get() == "":
pass
else:
df=df[df['Feature'] == self.featureCBO.get()]
#Filter by Tool
if self.toolCBO.get() == "":
pass
else:
df=df[df['Tool'] == self.toolCBO.get()]
#print(df)
#Filter Feature CBO
self.featureCBO['values'] = df['Feature'].unique().tolist()
self.featureCBO['values'] = (*self.featureCBO['values'], '') #add empty line to end
#Filter Tool CBO
self.toolCBO['values'] = df['Tool'].unique().tolist()
self.toolCBO['values'] = (*self.toolCBO['values'], '') #add empty line to end
if __name__ == '__main__':
window = Root()
window.mainloop()
print('done')
The problem is with trying to reference the function as Root.filterCBOs). The function belongs to an instance of Root, so it needs to bemaster.filterCBOssincemaster` is being set to the root window.
self.entry_1.bind('<Return>', master.filterCBOs)

Python skipped one of my function

I am using a tkinter frame to call another tkinter frame. So from frame one i will click a button and it will check if there is a file at C:\ and if the file is not there it should call the Chrome_gui function which is another tkinter frame at "def p2(self)". When the Chrome_gui is called it will create the test file and the self.p2 will be called again to check if the file is there. But it will become a never ending loop as the function self.Chrome_guiis not called. And when i remove self.p2, the function self.Chrome_gui can be called. So can anyone tell me why it is skipping the self.Chrome_gui function?
def __init__(self):
tk.Tk.__init__(self)
tk.Tk.title(self,"qwerty")
self.b1 = tk.Button(self, text="P2", command = self.p2)
self.b1.grid(row = 3, column = 1, sticky = 'EWNS' )
def p2 (self):
self.values()
print ('printdwo')
my_file1 = Path("C:\test.pdf")
if my_file1.is_file():
print ("File Found")
else:
print ('not found')
self.Chrome_gui()
self.p2()
def Chrome_gui(self):
self.chrome = tk.Tk()
self.chrome.title('Date')
self.label = tk.Label(self.chrome, text="", width=20)
self.label.grid(row = 1, column = 1)
self.c1 = tk.Button(self.chrome, text="Yes", command = self.yes)
self.c1.grid(row = 2, column = 1, sticky = W+E)#side = LEFT)
global e
e = ""
self.c2 = tk.Button(self.chrome, text = "No" , command = self.no)
self.c2.grid(row = 3, column = 1, sticky = W+E)#side = LEFT)
Your code is looping because your condition if my_file1.is_file(): is always false so it's always calling self.p2() in the else part.
When you're defining a string and you want to put a '\', you have to put '\'. In your case you have '\t' so it will replace it by a tabulation. Replace it by Path("C:\\test.pdf")

How to add item to listbox?

I am creating a simple GUI program to manage priorities. I am having troubles with adding items to the listbox. I tried to create an instance of Priority class by passing two attributes to the constructor and then use g.listBox.insert(END, item), but it seems it doesn't work like that. I am getting an error:
/usr/bin/python3.5 /home/cali/PycharmProjects/priorities/priorities.py
Exception in Tkinter callback Traceback (most recent call last):
File "/usr/lib/python3.5/tkinter/init.py", line 1553, in call
return self.func(*args) File "/home/cali/PycharmProjects/priorities/priorities.py", line 52, in
addItem
item = Priority(subject = g.textBox.get("1.0", 'end-1c'), priority = g.textBox.get("1.0", 'end-1c')) AttributeError: 'GuiPart' object has no attribute 'textBox'
Process finished with exit code 0
Here is what I have done:
# priorities.py
# GUI program to manage priorities
from tkinter import *
class Priority:
def __init__(self, subject, priority):
self.subject = subject
self.priority = priority
def subject(self):
return self.subject
def priority(self):
return self.priority
class GuiPart:
def __init__(self):
self.root = self.createWindow()
def createWindow(self):
root = Tk()
root.resizable(width = False, height = False)
root.title("Priorities")
return root
def createWidgets(self):
Button(self.root,
text = "Add",
command = self.addItem).grid(row = 2, column = 0, sticky = W + E)
Button(self.root,
text="Remove",
command = self.removeItem).grid(row = 2, column = 1, sticky = W + E)
Button(self.root,
text="Edit",
command = self.editItem).grid(row = 2, column = 2, sticky = W + E)
listBox = Listbox(width = 30).grid(row = 1, sticky = W + E, columnspan = 3)
textBox = Text(height=10, width=30).grid(row = 3, columnspan = 3, sticky = W + E + N + S)
def addItem(self):
item = Priority(subject = g.textBox.get("1.0", 'end-1c'), priority = g.textBox.get("1.0", 'end-1c'))
g.listBox.insert(END, item)
def removeItem(self):
pass
def editItem(self):
pass
class Client:
pass
if __name__ == "__main__":
g = GuiPart()
g.createWidgets()
g.root.mainloop()
I'm using Python 3.5.
So if I understood your aim, you are trying to describe a priority by allowing the user to type, within the text zone widget, its information which consists in its subject and order; after that, the user can click on the "Add" button to insert the priority information into your list box.
There are lot of things to consider around your code. If I go to fix and comment them one by one, I believe my answer will be long while I feel lazy today.
I think my program below is easy to understand (ask a clarification otherwise). I did not find specifications inherent to how the propriety information is typed in the text zone. So my program below works under the assumption the user types the priority subject on the first line of the text area, and then uses a new line to type the priority order. The click on "Add" button will lead to the insertion of these 2 data on the same line of the text box widget as shown below:
Here is an MCVE:
import tkinter as tk
class ProioritiesManager(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.master.resizable(width = False, height = False)
self.master.title("Priorities")
self.create_buttons()
self.create_listbox()
self.create_priorities_description_zone()
def create_buttons(self):
add_item = tk.Button(self.master, text='Add', command=self.add_item)
add_item.grid(row=2, column=0, sticky=tk.W+tk.E)
remove_item = tk.Button(self.master, text='Remove', command=self.remove_item)
remove_item.grid(row=2, column=1, sticky=tk.W+tk.E)
edit_item = tk.Button(self.master, text='Edit', command=self.edit_item)
edit_item.grid(row=2, column=2, sticky=tk.W+tk.E)
def create_listbox(self):
self.item_alternatives = tk.Listbox(self.master, width=30)
self.item_alternatives.grid(row=1, sticky=tk.W+tk.E, columnspan=3)
def create_priorities_description_zone(self):
self.priority_text_zone = tk.Text(self.master, height=10, width=30)
self.priority_text_zone.grid(row=3, columnspan=3, sticky=tk.W+tk.E+tk.N+tk.S)
def get_priority_subject(self):
return self.priority_text_zone.get('1.0', '1.0 lineend')
def get_priority_order(self):
return self.priority_text_zone.get('2.0', '2.0 lineend')
def add_item(self):
self.item_alternatives.insert(tk.END, self.get_priority_subject()+' '+ self.get_priority_order())
def remove_item(self):
pass
def edit_item(self):
pass
if __name__ == "__main__":
root = tk.Tk()
ProioritiesManager(root)
root.mainloop()
If you want to give a good UX to your GUI then it would be nice if you add a button to allow the user to clear the content of the text area so that he can type in a new priority:
For this purpose, you can add a rest button to create_buttons() function by adding these 2 lines of code:
clear_text_area = tk.Button(self.master, text='Reset', command=self.reset_priority_text_zone)
clear_text_area.grid(row=4, column=2)
The callback reset_priority_text_zone() is defined this way:
def reset_priority_text_zone(self):
self.priority_text_zone.delete('1.0', tk.END)
These Lines are causing Error :
listBox = Listbox(width = 30).grid(row = 1, sticky = W + E, columnspan = 3)
textBox = Text(height=10, width=30).grid(row = 3, columnspan = 3, sticky = W + E + N + S)
Do it like this:
self.listBox = Listbox(self.root,width = 30)
self.listBox.grid(row = 1, sticky = W + E, columnspan = 3)
self.textBox = Text(self.root,height=10, width=30)
self.textBox.grid(row = 3, columnspan = 3, sticky = W + E + N + S)
Actually you are not creating listBox and textBox objects instead grid is returning to listBox and textBox

Global Variable 'getInfo' is undefined

I'm working on developing a GUI for a project and once I put all of this into a class, it is returning saying
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
return self.func(*args)
File "c:\users\ryan\documents\visual studio 2015\Projects\Group_3_Project\Group_3_Project\Group_3_Project.py", line 30, in <lambda>
b1 = Button(root, text = 'Submit', command = (lambda e = ents: getInfo(e)))
NameError: global name 'getInfo' is not defined
Here is my code so far:
from tkinter import*
class GUI:
fields = 'Last Name', 'First Name', 'Field', 'Phone Number', 'Office number'
def getInfo(entries):
for entry in entries:
field = entry[0]
text = entry[1].get()
print('%s: "%s"' % (field, text))
def makeForm(root, fields):
entries = []
for field in fields:
row = Frame(root)
lab = Label(row, width = 15, text = field, anchor = 'w')
ent = Entry(row)
row.pack(side = TOP, fill = X, padx = 5, pady = 5)
lab.pack(side = LEFT)
ent.pack(side = RIGHT, expand = YES, fill = X)
entries.append((field, ent))
return entries
if __name__ == '__main__':
root = Tk()
root.wm_title("HoursWizard")
ents = makeForm(root, fields)
root.bind('<Return>', (lambda event, e = ents: getInfo(e)))
b1 = Button(root, text = 'Submit', command = (lambda e = ents: getInfo(e)))
b2 = Button(root, text = 'Quit', command = root.quit)
b1.pack(side = LEFT, padx = 5, pady = 5)
b2.pack(side = LEFT, padx = 5, pady = 5)
root.mainloop()
I have no idea what is going on and why it isn't working correctly. I'm sure it is an easy fix and I'm just missing something. Any help is appreciated. Thanks!
You should check the official Python tutorial and look at the section on classes. Basically, your scoping and namespaces are not what you think they are. Every class method (unless it's been designated as static) is first passed the instance itself, usually denoted with self. You would then refer to instance attributes with self.myattribute. In getInfo, for example, what you call entries isn't entries at all, but rather the instance of the GUI class that has been created.
I highly recommend you look up some tutorials for how to make an OO Tkinter app. It generally goes like this:
class App:
def __init__(self, parent):
self.parent = parent
self.parent.after(5000, self.other_method) # just a demo
# create buttons, lay out geometry, etc.
def other_method(self):
self.do_print()
def do_print(self):
print('hello world')
root = Tk()
app = App(root)
root.mainloop()

Python Code Error with Tkinter?

When I try to run the code it gives me this nasty error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
return self.func(*args)
File "E:\Tkinter\count_num_CHALLENGE.py", line 39, in count_num
for num in range(start, end):
TypeError: 'Entry' object cannot be interpreted as an integer
Please help I don't know what is wrong! I tried int() Around entry but that did not work either If you guys can help me out that would be great. As I am in need of assistance
from tkinter import *
class Application(Frame):
def __init__(self, master):
super(Application, self).__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
# Create the instruction Label
Label(self,
text = "Enter a starting number then an ending number."
).grid(row = 0, column = 0, sticky = W)
# Create the entry box for starting/ending
self.starting_num = Entry(self)
self.starting_num.grid(row = 2, column = 0, sticky = W)
self.ending_num = Entry(self)
self.ending_num.grid(row = 3, column = 0, sticky = W)
# Create the text box
self.result_txt = Text(self, width = 20, height = 10, wrap = WORD)
self.result_txt.grid(row = 4, column = 0, columnspan = 1)
# Submit button
Button(self,
text = "Count the numbers",
command = self.count_num
).grid(row = 5, column = 0, sticky = W)
def count_num(self):
start = self.starting_num
end = self.ending_num
for num in range(start, end):
print(num)
self.result_txt.delete(0.0, END)
self.result_txt.insert(0.0, count_num)
# Main
root = Tk()
root.title("Count the numbers")
app = Application(root)
root.mainloop()
In your code, self.starting_num is an instance of an Entry widget, but you are trying to use it as if it were a number just as the error message is telling you.
I'm going to guess your intent is to use the value of the entry widget, in which case you need to use something like start=int(self.starting_num.get()), though you will need to handle the case where the entry is emply or has non-digits in it. The same goes for ending_num

Categories

Resources