I'm learning python and encountering issues with what appears to be class decorators from tkinter. I can get tkinter to work as long as I never try to decorate with Frame. The code below gives me no errors, and no window. For whatever reason, the class I define, never gets defined. Below is my code. Below that is testing i've done based on similar questions regarding tkinter.
>>> from tkinter import *
import tkinter
class Apples:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.button = Button(frame, text="Quit", fg="blue", command=frame.quit)
self.button.pack(side=LEFT)
self.hellos = Button(frame, text="Hello", command=self.say_hello)
self.hellos.pack(side=LEFT)
def say_hello(self):
print("Hello World!")
root = Tk()
app = Apples(root)
root.mainloop()
No window shows up. No error. So I check on the class...
>>> test = Apples(root)
Traceback (most recent call last):
File "<pyshell#54>", line 1, in <module>
test = Apples(root)
NameError: name 'Apples' is not defined
>>>
I found a similar question Creating buttons with Python GUI and attempted the code from pythonMan. I still am encountering the same class declaration issue.
>>> from tkinter import *
class Application(Frame):
"""A GUI application with three button"""
def __init__(self,master):
self.master = master
self.create_widgets()
def create_widgets(self):
#"""Create three buttons"""
#Create first buttom
btn1 = Button(self.master, text = "I do nothing")
btn1.pack()
#Create second button
btn2 = Button(self.master, text = "T do nothing as well")
btn2.pack()
#Create third button
btn3=Button(self.master, text = "I do nothing as well as well")
btn3.pack()
root = Tk()
root.title("Lazy Button 2")
root.geometry("500x500")
app = Application(root)
root.mainloop()
>>> Application
Traceback (most recent call last):
File "<pyshell#58>", line 1, in <module>
Application
NameError: name 'Application' is not defined
>>>
I can think something is not being declared properly, but is not generating a syntax error. Any help would be greatly appreciated.
I think you don't need an ">>>" sign.
"from Tkinter import *"
Assuming your code is properly reproduced in the second part of your question, you're defining your class incorrectly. You have def __init__ at the same level of indentation as class Application(Frame). Your methods need to be indented for them to be part of the class.
The code in the first part of your question works fine for me.
Related
I am making a code editor. But when I type in my code editor the following code, it is getting a NameError.
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.label = tk.Label(self, text="iets") # here, tk isn't recognized
self.label.pack()
app = App()
app.mainloop()
All the code of the input tkinter text widget is executed by a exec statement. The whole NameError is:
Traceback (most recent call last):
File "C:\Users\Gebruiker\PycharmProjects\mylanguage\execute.py", line 24, in do
exec(self.input)
File "< string>", line 9, in
File "< string>", line 6, in __ init__
NameError: name 'tk' is not defined
Why do i get this error? in the code I typed in I do have import tkinter as tk!
The hierarchy of my project is the following:
I've 8 files: main.py, execute.py, output.py et cetera
From main.py, the tkinter app is created.
When i press button run, in execute.py the code is, as it says, executed.
Then the output or error is being displayed in a toplevel window from the file output.py.
execute.py:
...
def do(self):
sys.stdout.write = output
try:
set_last("")
exec(self.input) #line 24
except Exception:
set_last("text.config(foreground='red')")
error = traceback.format_exc()
output(error)
...
when i add print(repr(self.input)) on top of do() it outputs:
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.label = tk.Label(self, text="iets")
self.label.pack()
app = App()
app.mainloop()
See the whole project on github: https://github.com/keizertje/myl
thanks in advance!
You file execute.py permits someone to exec() arbitrary code (here be dragons). In this case, the code includes an alias tk that is unknow in the context of execute.py.
Either execute.py needs to import and set this alias or the text file contents of self.input needs to do that.
For example:
import statistics
text = """
print(statistics.mean([1,2]))
"""
exec(text)
or
text = """
import statistics
print(statistics.mean([1,2]))
"""
exec(text)
If yourtext is your class, then this seems to work for me:
text = """
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.label = tk.Label(self, text="iets")
self.label.pack()
app = App()
app.mainloop()
"""
exec(text)
sorry for the consternation, the reason of my problem was totally other than i expected! the problem was that when i put self.input in exec() the program starts with all global variables. how to fix? as acw1668 said: simply use exec(self.input, {}) and it worked! this empty dict means that at the start of executing there are no global variables.
so do() becomes:
def do(self):
sys.stdout.write = output
try:
set_last("")
exec(self.input, {}) # here it's fixed!
except Exception:
set_last("text.config(foreground='red')")
error = traceback.format_exc()
output(error)
New to tkinter, I want a short program to:
create a window to take user input, by means of an entry widget and a submit button
capture the input and return it to main, so that I can do something else with it.
The following code creates the window and captures input, but breaks at the next-to-last line.
from tkinter import *
from tkinter import ttk
class TxtEntryWindow:
def __init__(self):
self.root = Tk()
self.frame = ttk.Frame(self.root).pack()
self.box = ttk.Entry(self.frame)
self.box.pack()
self.but = ttk.Button(self.frame, text='Submit', command=self.capture_txt)
self.but.pack()
self.root.mainloop()
def capture_txt(self):
txt = self.box.get()
return txt
win = TxtEntryWindow()
user_input = win.capture_txt()
print(user_input)
Here's a copy of the error message:
Traceback (most recent call last):
File "C:...\wclass.py", line 22, in
user_input = win.capture_txt()
File "C:...\wclass.py", line 17, in capture_txt
txt = self.box.get()
File "C:...\Python\Python310\lib\tkinter_init_.py", line 3072, in get
return self.tk.call(self._w, 'get')
_tkinter.TclError: invalid command name ".!entry"
I have no idea what this means. I suspect that dependence of "txt" on the button event in the class prevents "win.capture_txt()" in main() at the bottom from fetching the user input.
Can anyone shed light?
Consulted Python's official documentation (unintelligible), Tkinter's official tutorial and command reference. Searched numerous analogies on StackOverflow and on youtube. Googled the error message itself. I've tried to strike out on my own and rewrite the critical command about twenty times. Blind intuition leads nowhere. Stabbing in the dark.
The error means that the entry widget (self.box) has been destroyed when the line user_input = win.capture_txt() is executed.
You can use an instance variable to store the input text instead and access this instance variable after the window is destroyed:
from tkinter import *
from tkinter import ttk
class TxtEntryWindow:
def __init__(self):
self.text = "" # initialize the instance variable
self.root = Tk()
self.frame = ttk.Frame(self.root).pack()
self.box = ttk.Entry(self.frame)
self.box.pack()
self.but = ttk.Button(self.frame, text='Submit', command=self.capture_txt)
self.but.pack()
self.root.mainloop()
def capture_txt(self):
# save the user input into the instance variable
self.text = self.box.get()
self.root.destroy()
win = TxtEntryWindow()
print(win.text) # show the content of the instance variable
I am exploring GUI's at the moment. What I want is to have a GUI with a 2 buttons and I want each of the buttons to run a separate python script when clicked.
I have outlined my code below (the first button runs just fine but I am having issues with the second button.
Error Message when I choose the second button:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
Code:
from tkinter import *
import tkinter as tk
master = Tk()
def First_Scriptcallback():
exec(open(r'Desktop\Automation\First_Script.py').read())
def second_Scriptcallback():
exec(open(r'Desktop\Automation\Second_Script.py').read())
#master.title("Test GUI")
#canvas = tk.Canvas(master, height=300, width = 400)
#canvas.pack()
firstButton = Button(master, text="Run first script", command=First_Scriptcallback)
firstButton.pack()
secondButton = Button(master, text="Run second script", command=second_Scriptcallback)
secondButton.pack()
mainloop()
Thanks
As #matiiss suggested importing the other scripts into your program can help and it can be done like this,
import First_Script as first
import Second_Script as second
from tkinter import *
import tkinter as tk
master = Tk()
def First_Scriptcallback():
first.function_name()#here you must create functions in first_script to call in this main script
def second_Scriptcallback():
second.function_name()
#master.title("Test GUI")
#canvas = tk.Canvas(master, height=300, width = 400)
#canvas.pack()
firstButton = Button(master, text="Run first script", command=First_Scriptcallback)
#command=first.function_name
#we can also directly call an function using above command,but sometimes there are problems related to this approch
firstButton.pack()
secondButton = Button(master, text="Run second script", command=second_Scriptcallback)
#command=second.function_name
secondButton.pack()
mainloop()
here for this example the scripts and the program must be in same directory.
How do i access windows function in Mygui class?
I want to create colored content in my tkinter box#
but i can't pass value to it.
from tkinter import *
class Mygui:
def window(self, colour):
self.main_window=Tk()
self.main_window.geometry('300x100')
self.main_window.title('Login')
self.top_frame=Frame(self.main_window)
self.top_frame.pack()
self.label=Label(self.top_frame, fg=colour, text="Sample Text", width=45)
self.label.pack(side="top")
self.label1=Label(self.top_frame,text=" ", width=45)
self.label1.pack(side="top")
self.my_button = Button(self.main_window, text="Retry", command=self.do_something, height=2, width=18)
self.my_button.pack()
mainloop()
def do_something(self):
print('ok')
class login:
def example(self):
print("Start")
Mygui.window('blue')
a = login.example(' ')
The error i get is:
Start
Traceback (most recent call last):
File "B:/data/loginMech/test.py", line 25, in <module>
a = login.example(' ')
File "B:/data/loginMech/test.py", line 23, in example
Mygui.window('blue')
TypeError: window() missing 1 required positional argument: 'colour'
Mygui is a class, not a function. So, you have to construct an instance of it, like this:
gui = Mygui()
And then you can call methods on that instance:
gui.window('blue')
When you write Mygui.window, that's an unbound method, which you can call by explicitly passing it a self argument along with its other arguments. But you'd still need to have something to pass as that self:
gui = Mygui()
Mygui.window(gui, 'blue')
In general, you don't want to do this. There are cases where unbound methods are useful, but if you have one, you probably know you have one.
And you need to do the same thing with login:
log = login()
log.example()
By calling login.example, you're using an unbound method again. And then you're passing ' ' as the self argument. This doesn't make any sense, because ' ' is not a login instance, but CPython 3.x happens to not check for that error, so you get away with it.
Abarnet pointed out one fix however in Tkinter it might be better to inherit from the Tkinter class Tk to start you GUI.
Take this example. A much smaller amount of code and produces the same results desired.
import tkinter as tk
class MyGUI(tk.Tk):
def __init__(self, colour):
tk.Tk.__init__(self)
self.geometry('300x100')
self.title('Login')
tk.Label(self, fg=colour, text="Sample Text", width=45, pady=10).grid(row=0, column=0)
tk.Button(self, text="Retry", command=self.do_something, height=2, width=18).grid(row=1, column=0)
def do_something(self):
print('ok')
MyGUI("Blue").mainloop()
Results:
I learned the book "programming python' these days. When I run the examples, I met the problem. The shell showed me the error:
AttributeError: 'NoneType' object has no attribute 'pack'
However, I copy the exactly code from the book. I'm a freshman of Python. I try to fix it by myself, but I failed. So I hope anyone could kindly help me.
Thanks !!!!!!
CODEļ¼
#File test.py
from tkinter import *
from tkinter.messagebox import showinfo
def MyGui(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
button = Button(self, text='press', command=reply)
button.pack()
def reply(self):
showinfo(title = 'popup',message ='Button pressed!')
if __name__ == '__main__':
window = MyGui()
window.pack()
window.mainloop()
#File test2.py
from tkinter import *
from test import MyGui
mainwin = Tk()
Label(mainwin,text = __name__).pack()
popup = Toplevel()
Label(popup,text = 'Attach').pack(side = LEFT)
MyGui(popup).pack(side=RIGHT)
mainwin.mainloop()
You can fix this with the following code:
#File test.py
from tkinter import *
from tkinter.messagebox import showinfo
class MyGui(Frame):
def __init__(self, parent = None):
Frame.__init__(self, parent)
button = Button(self, text='press', command=self.reply)
button.pack()
def reply(self):
showinfo(title = 'popup',message ='Button pressed!')
if __name__ == '__main__':
window = MyGui()
window.pack()
window.mainloop()
Basically two small syntax errors. First you were trying to make a class of MyGui, but you used keyword def which made a function instead (that returned None, hence the error you received.) It is syntaxically correct in python to define functions inside of functions so it was a little harder to catch. You have to use the keyword class to define a class.
Secondly when referencing the function reply you must use self.reply within the class itself.