Global Variable 'getInfo' is undefined - python

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()

Related

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

More on tkinter optionmenu first option vanishes

This is a followup to my question here. I'm trying to use ttk.OptionMenu to enhance the look and feel of a dropdown menu. But as noted in the post here, "A ttk optionmenu widget starts out with all of its values in the dropdown. Upon selecting any value, the first value in the list vanishes, never to reappear..." The workaround as suggested in that post is to add an empty item to the list. In my case, since I am using a dictionary, adding '':[] as the first item in the dictionary fixed the problem. Is this the only solution? I hate to introduce an artifact into my dictionary. Here's the code:
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class App:
def __init__(self, master):
master.title("Continental System")
self.dict = {'':[], 'Asia': ['Japan', 'China', 'Malasia'],
'Europe': ['Germany', 'France', 'Switzerland'],
'Africa': ['Nigeria', 'Kenya', 'Ethiopia']}
self.frame1 = ttk.Frame(master)
self.frame1.pack()
self.frame2 = ttk.Frame(master)
self.frame2.pack()
self.variable_a = tk.StringVar()
self.variable_b = tk.StringVar()
self.variable_a.trace('w', self.updateoptions)
self.optionmenu_a = ttk.OptionMenu(self.frame1, self.variable_a, *self.dict.keys())
self.variable_a.set("Asia")
self.optionmenu_a.grid(row = 0, column = 0)
self.optionmenu_b = ttk.OptionMenu(self.frame1, self.variable_b, '')
self.optionmenu_b.grid(row = 0, column = 1)
self.btn = ttk.Button(self.frame2 , text="Submit", width=8, command=self.submit)
self.btn.grid(row=0, column=1, padx=20, pady=20)
def updateoptions(self, *args):
countries = self.dict[self.variable_a.get()]
self.variable_b.set(countries[0])
menu = self.optionmenu_b['menu']
menu.delete(0, 'end')
for country in countries:
menu.add_command(label=country, command=lambda country=country: self.variable_b.set(country))
def submit(self, *args):
var1 = self.variable_a.get()
var2 = self.variable_b.get()
if messagebox.askokcancel("Confirm Selection", "Confirm your selection: " + var1 + ' ' + var2 + ". Do you wish to continue?"):
print(var1, var2)
def set_window(self, *args):
w = 800
h = 500
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
root = tk.Tk()
app = App(root)
app.set_window()
root.mainloop()
Also I am getting some error messages including AttributeError: 'App' object has no attribute 'optionmenu_b'which seemed to have been resolved in the answer to my first question above.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1487, in __call__
return self.func(*args)
File "C:\Python34\tk1_version2.py", line 32, in updateoptions
menu = self.optionmenu_b['menu']
AttributeError: 'App' object has no attribute 'optionmenu_b'
Python Version 3.4.1
That post you quote is incorrect. You do not need to put a space as the first item in the list. The signature of the ttk.OptionMenu command requires a default value as the first argument after the variable name.
You do not need to add an empty item to your dictionary. You do need to add a default value when you create the optionmenu:
self.optionmenu_a = ttk.OptionMenu(self.frame1, self.variable_a, "Asia", *self.dict.keys())
A slightly better solution would be to get the list of keys and save them to a list. Sort the list, and then use the first element of the list as the default:
options = sorted(self.dict.keys())
self.optionmenu_a = ttk.OptionMenu(self.frame1, self.variable_a, options[0], *options)
The reason you get the error is because you have a trace on the variable which calls a function that references self.optionmenu_b, but you are initially setting that variable before you create self.optionmenu_b. The simple solution is to create the second menu first.
self.optionmenu_b = ttk.OptionMenu(...)
self.optionmenu_a = ttk.OptionMenu(...)

button1 is not defined?

This is my code :
import sys
from tkinter import *
#first new screen
def hypoténusegetdef ():
widgets1 = button1
nextscreen1(widgets1)
def next_screen1(names):
for widget in names:
widget.place_forget()
hyplabel1 = Label (text = "This is my text")
def next_screen(names):
for widget in names:
widget.place_forget()
button1 = Button (text = "Button1",fg = "blue",command = hypoténusegetdef)
button1.grid (row = 1,column = 2)
def forget_page1():
widgets = [mLabel1, button]
next_screen(widgets)
################################################################################
#first page things
mGui = Tk ()
mGui.geometry("600x600+545+170")
mGui.title("MyMathDictionary")
mLabel1 = Label (text = "Welcome to MyMathDictionary. Press Next to continue.",
fg = "blue",bg = "white")
mLabel1.place (x= 150,y = 200)
button = Button (text = "Next", command = forget_page1 )
button.place(x = 275,y = 230)
mGui.mainloop()
I want the user to click on "next" and then a button appears caled "button1" after clicking on that button a text should appear "this is my text" but it gives me an 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 "C:\Python33\Projects\MyMathDictionary.py", line 7, in hypoténusegetdef
widgets1 = button1
NameError: global name 'button1' is not defined
Any help would be apreciated :
button1 is defined in next_screen, but used in hypoténusegetdef -- you can't use a variable from one function inside another. Looking at the rest of the code, the simplest thing would probably be to use a global variable that can be accessed anywhere (generally bad practice, but for short scripts they can make things easier)

Python Tkinter Text Widget .get method error

I'm very new to Python, sort of following Dive into Python 2 and wanted to dabble with some Tkinter programming. I've tried to make a little program that takes 3 sets of words and makes combinations of each word in the 3 sets to make keywords for websites. When I run the script, the GUI appears as expected, but I get the following error when I click on the Create Combinations button
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.6/lib-tk/Tkinter.py", line 1413, in __call__
return self.func(*args)
File "combomaker.py", line 34, in makeCombinations
primaryraw = primaryKeyWordsBox.get()
AttributeError: 'NoneType' object has no attribute 'get'
The code I'm trying to fix
#!/usr/bin/env python
from Tkinter import *
primaryKeyWordsLabel = None
primaryKeyWordsBox = None
secondaryKeyWordsLabel = None
secondaryKeyWordsBox = None
tertiaryKeyWordsLabel = None
tertiaryKeyWordsBox = None
class Application(Frame):
def __init__(self, master=None, padx = 10, pady= 10):
Frame.__init__(self, master)
self.grid()
self.createWidgets()
def createWidgets(self):
self.primaryKeyWordsLabel = LabelFrame(text="Primary Key Words", padx=10, pady=10)
self.primaryKeyWordsLabel.grid()
self.primaryKeyWordsBox = Text(primaryKeyWordsLabel, autoseparators=True, height=5, undo=True)
self.primaryKeyWordsBox.grid()
self.secondaryKeyWordsLabel = LabelFrame(text="Secondary Key Words", padx=10, pady=10)
self.secondaryKeyWordsLabel.grid()
self.secondaryKeyWordsBox = Text(secondaryKeyWordsLabel, autoseparators=True, height=5, undo=True)
self.secondaryKeyWordsBox.grid()
self.tertiaryKeyWordsLabel = LabelFrame(text="Tertiary Key Words", padx=10, pady=10)
self.tertiaryKeyWordsLabel.grid()
self.tertiaryKeyWordsBox = Text(tertiaryKeyWordsLabel, autoseparators=True, height=5, undo=True)
self.tertiaryKeyWordsBox.grid()
self.goButton = Button(text="Create Combinations", command=makeCombinations)
self.goButton.grid()
def makeCombinations():
primaryraw = primaryKeyWordsBox.get()
primary = primaryraw.split(', ')
secondaryraw = secondaryKeyWordsBox.get()
secondary = secondaryraw.split(', ')
tertiaryraw = tertiaryKeyWordsBox.get()
tertiary = tertiaryraw.split(', ')
output=[]
filename = "output.txt"
for i in range(len(primary)):
for j in range(len(secondary)):
for k in range(len(tertiary)):
rawcombo=str(primary[i])+" "+str(secondary[j])+" "+str(tertiary[k])
output.append(rawcombo)
FILE = open(filename, w)
for combo in output:
FILE.write(combo+",\n")
FILE.close()
app = Application()
app.master.title("Keyword Generator")
app.mainloop()
I may have thrown myself into GUI programming too fast, this is my first attempt at any GUI work but not my first time programming.
Many thanks in advance :)
You're trying to access
primaryKeyWordsBox
outside the class Application in the (free) function makeCombinations(..).
You could make makeCombinations(..) a member of Application by indenting it like the other member functions and add the self argument:
def makeCombinations(self):
You should modify the binding of the makeCombinations(..) to the button:
...,command = self.makeCombinations)
Then you'll have to add self. when you're trying to access the members of this class:
primaryraw = self.primaryKeyWordsBox.get(1.0,END)
...
secondaryraw = self.secondaryKeyWordsBox.get(1.0,END)
...
tertiaryraw = self.tertiaryKeyWordsBox.get(1.0,END)
(I found the examples how to use get here).
If you want to open a file for writing, you should do:
FILE = open(filename, "w")
instead of
FILE = open(filename, w)

Categories

Resources