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)
Related
I'm trying to create a button which has the same effect as the button from the version test from tkinter when using the command
py -m tkinter
in CMD. The button is supposed to display the text "Button", then with every press a set of brackets will be added on either side of the word. So on the first press, the text will read "[Button]", then the second press "[[Button]]", and so on.
Here is what I have:
from tkinter import *
from tkinter import ttk
def changeText():
textName = "[" + textName + "]"
root = Tk()
root.geometry('400x150')
root.title('Hit the button')
textName = "button"
frame = ttk.Frame(root, padding = 10).grid()
btn = ttk.Button(frame, text = textName, command = changeText).grid(column = 0, row = 0)
root.mainloop()
When I run my code, the window and button pops up correctly, however when the button is pressed, I get the error:
"X:\Pycharm Environments\venv\Scripts\python.exe" "X:/Pycharm Environments/Learning/tkinterPractie.py"
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\jared\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1885, in __call__
return self.func(*args)
File "X:\Pycharm Environments\Learning\tkinterPractie.py", line 5, in changeText
textName = "[" + textName + "]"
UnboundLocalError: local variable 'textName' referenced before assignment
I'm not really sure what I'm doing wrong here. Thanks for any help!
When you call .grid() on your button, the return value is None, so you have already lost the direct reference to your button. There are other ways of accessing it, but it would be much easier to just create the button and then put it in the layout in 2 steps. Also you need to set the button['text'] when changing the text. textName is just a variable holding a string and updating it only updates the value of the variable.
from tkinter import *
from tkinter import ttk
def changeText():
btn['text'] = "[" + btn['text'] + "]" # change to changing the buttons text
root = Tk()
root.geometry('400x150')
root.title('Hit the button')
textName = "button"
frame = ttk.Frame(root, padding = 10).grid()
btn = ttk.Button(frame, text = textName, command = changeText) # return the instance
btn.grid(column = 0, row = 0) # then input into the layout
root.mainloop()
I am trying to bind this function self.copyTextToClipboard(self,t) to multiple different trees to make it more flexible (please see binding below).
from tkinter.ttk import Treeview
from tkinter import *
class App:
def __init__(self, master):
self.master = master
frame = Frame(master)
master.geometry("{}x{}".format(master.winfo_screenwidth() - 100, master.winfo_screenheight() - 100))
master.resizable(False, False)
self.leftFrame = Frame(master, bg="#DADADA", width=375, relief=SUNKEN)
self.leftFrame.pack_propagate(0)
self.leftFrame.pack(side=LEFT, fill=Y, padx=1)
# This table (TreeView) will display the partitions in the tab
self.partitionsOpenDiskTree = Treeview(self.leftFrame, columns=("#"), show="headings", selectmode="browse", height=23)
yscrollB = Scrollbar(self.leftFrame)
yscrollB.pack(side=RIGHT, fill=Y)
self.partitionsOpenDiskTree.column("#", width=50)
self.partitionsOpenDiskTree.heading("#", text="#")
self.partitionsOpenDiskTree.configure(yscrollcommand=yscrollB.set)
# Bind left click on text widget to copy_text_to_clipboard() function
self.partitionsOpenDiskTree.bind("<ButtonRelease-1>", lambda t=self.partitionsOpenDiskTree: self.copyTextToClipboard(self,t))
# Adding the entries to the TreeView
for i in range(3):
self.partitionsOpenDiskTree.insert("", "end", i, values=(i), tags=str(i))
self.partitionsOpenDiskTree.pack(anchor=NW, fill=Y)
#todo: figure out where this is getting called and put in tree
def copyTextToClipboard(self, tree, event=None):
print(type(tree))
# triggered off left button click on text_field
root.clipboard_clear() # clear clipboard contents
textList = tree.item(tree.focus())["values"]
line = ""
for text in textList:
if line != "":
line += ", " + str(text)
else:
line += str(text)
root.clipboard_append(line) # append new value to clipbaord
root = Tk()
app = App(root)
root.mainloop()
However, I am unable to bind it to a TreeView object it seems; when I run the code, I get:
Exception in Tkinter callback
<class '__main__.App'>
Traceback (most recent call last):
File "C:\Users\user1\Anaconda3\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
File "C:/Users/user1/main_merged.py", line 56, in <lambda>
lambda t=self.partitionsOpenDiskTree: self.copyTextToClipboard(self,t))
File "C:/Users/user1/main_merged.py", line 70, in copyTextToClipboard
textList = tree.item(tree.focus())["values"]
AttributeError: 'App' object has no attribute 'item'
If I try to print out tree type, I get that it's a not a TreeView object. Any ideas on how I can get a TreeView object, so that I can figure out which item was selected?
Thanks!
-FF
So, apparently, taking out the self call seemed to work:
from tkinter.ttk import Treeview
from tkinter import *
class App:
def __init__(self, master):
self.master = master
frame = Frame(master)
master.geometry("{}x{}".format(master.winfo_screenwidth() - 100, master.winfo_screenheight() - 100))
master.resizable(False, False)
self.leftFrame = Frame(master, bg="#DADADA", width=375, relief=SUNKEN)
self.leftFrame.pack_propagate(0)
self.leftFrame.pack(side=LEFT, fill=Y, padx=1)
# This table (TreeView) will display the partitions in the tab
self.partitionsOpenDiskTree = Treeview(self.leftFrame, columns=("#"), show="headings", selectmode="browse", height=23)
yscrollB = Scrollbar(self.leftFrame)
yscrollB.pack(side=RIGHT, fill=Y)
self.partitionsOpenDiskTree.column("#", width=50)
self.partitionsOpenDiskTree.heading("#", text="#")
self.partitionsOpenDiskTree.configure(yscrollcommand=yscrollB.set)
# Bind left click on text widget to copy_text_to_clipboard() function
self.partitionsOpenDiskTree.bind("<ButtonRelease-1>", lambda event, t=self.partitionsOpenDiskTree: self.copyTextToClipboard(t))
# Adding the entries to the TreeView
for i in range(3):
self.partitionsOpenDiskTree.insert("", "end", i, values=(i), tags=str(i))
self.partitionsOpenDiskTree.pack(anchor=NW, fill=Y)
#todo: figure out where this is getting called and put in tree
def copyTextToClipboard(self, tree, event=None):
print(type(tree))
# print(type(tree.partitionsOpenDiskTree))
# triggered off left button click on text_field
root.clipboard_clear() # clear clipboard contents
textList = tree.item(tree.focus())["values"]
line = ""
for text in textList:
if line != "":
line += ", " + str(text)
else:
line += str(text)
root.clipboard_append(line) # append new value to clipbaord
print(line)
root = Tk()
app = App(root)
root.mainloop()
Output:
0
When you use bind, the callback function must have an event as its first argument, custom arguments should be put after. But as your callback does not need the event parameters, you may mask it with your lambda. So you have to change both the binding and the def of your callback:
self.partitionsOpenDiskTree.bind("<ButtonRelease-1>", lambda event, t=self.partitionsOpenDiskTree: self.copyTextToClipboard(t))
...
def copyTextToClipboard(self, tree):
should solve the problem
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()
This is my code :
import sys
from tkinter import *
#first new screen
def next_screen(names):
for widget in names:
widget.place_forget()
buttonhyp = Button (text = "button1",fg = "blue",command = hypoténusegetdef())
buttonhyp.grid (row = 1,column = 2)
def forget_page1():
widgets = [mLabel1, button]
next_screen(widgets)
################################################################################
def hypténusegetdef ():
widgets1 = [buttonhyp]
nextscreen1(widgets1)
def next_screen(names):
for widget in names:
widget.place_forget()
hyplabel1 = Label (text = "This is my text")
#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()
What i'm trying to do is to open the program and get the user to click on "Next" and then to show another button which is called "button1" and when the user clicks on "button1" it shows up a text called which says "This is my text" in my code.But when i run it i click on "Next" and nothing shows up i checked and re- checked but nothing seems to work.Any help would be appreciated.
#
I am not an expert, but i will give it a try.
Firstly, import sys is not necessary. And importing all the objects from tkinter module using from tkinter import* is not recommended. You should use import tkinter or import tkinter as tk to avoid unexepcted consequences.
You have 2 functions with the same name. next_screen(names) which should not happen.
Instead of using widgets = [mLabel1, button] to hide the widgets, you should put them in a frame so that you can use winfo_children() to find all the children widgets.
You should put the parent widget name when you create buttons and labels. for example,
import tkinter as tk
root = tk.Tk()
mylabel = tk.Label(root,text='this is a label')
mylabel.pack()
root.mainloop()
In your first next_screen(names) function , you used grid method to display the button. You should not mix the grid method and place method.
This is something i came up with
import tkinter as tk
def Screen_1():
Clear(myframe)
mybutton2= tk.Button(myframe,text = "Button1", command = Screen_2)
mybutton2.pack()
def Screen_2():
Clear(myframe)
mylabel2= tk.Label(myframe,text = "This is my text",fg = "blue",bg = "white")
mylabel2.pack(side='top')
def Clear(parent):
for widget in parent.winfo_children():
widget.pack_forget()
root =tk.Tk()
myframe=tk.Frame(root)
myframe.pack()
mylabel1= tk.Label(myframe,text = "Welcome to MyMathDictionary. Press Next to continue.",fg = "blue",bg = "white")
mylabel1.pack(side='top')
mybutton1= tk.Button(myframe,text = "Next", command = Screen_1)
mybutton1.pack(side='bottom')
root.mainloop()
hope it helps!
This is my code:
import sys
from tkinter import *
def next_screen(names):
for widget in names:
widget.place_forget()
def forget_page1():
widgets = [mLabel1, button]
next_screen(widgets)
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()
It tells me :
Traceback (most recent call last): File
"C:\Python33\Projects\MyMathDictionary.py", line 24, in <module>
button = Button (text = "Next", command = forget_page1 (mLabel,button)) NameError: name 'button' is not defined
What does this error message mean?
Change this line of code:
button = Button (text = "Next", command = forget_page1 ())
To this:
button = Button (text = "Next", command = forget_page1)
Your problem was that you were calling forget_page1 before the window loaded.
Also, as the comments have already said, your error is different than your code. But, I'll go over that quickly too just in case. If you want to send arguments to a button's command function, you need to use a lambda:
button = Button(command = lambda: func(arg1, arg2))