I am currently trying to learn tkinter. I do not understand why the buttons I defined do not appear in this code:
from tkinter import *
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
button1 = Button(self, text="Exit", width=12, command=self.clickButton1)
button1.grid(row=0)
button2 = Button(self, text="Test", width=12, command=self.clickButton2)
button2.grid(row=1)
def clickButton1(self):
exit()
def clickButton2(self):
print("Nice")
root = Tk()
app = Window(root)
root.title("Tkinter window")
root.mainloop()
When I don't use a class it works. Like this for example:
from tkinter import *
root = Tk()
button1 = Button(root, text="Works!!!")
button1.grid(row=0)
button2 = Button(root, text="Also works!!!")
button2.grid(row=1)
root.mainloop()
ยดยดยด
The reason is that the class creates a frame, and then puts widgets inside the frame. However, you never add the frame to the window so the widgets inside the frame will be invisible.
You need to make sure and call pack, grid, or place on the instance of Window, just like you do with any other widget.
app = Window(root)
app.pack(fill="both", expand=True)
Related
My "simple" intention is to create a Dialog - launched by a button - where I have several LabelFrames with their radio button.
I tried with 1 LabelFrame with this simple code the radios appear in the main window, not in the dialogue one !!!! I cannot understand why. Please help.. ty for your attention
Here's the code:
import tkinter as tk
from tkinter import ttk
class PersonEmptyDocsDialog(tk.Toplevel):
def __init__(self, root,personid):
super().__init__(root)
self.personid = personid
self.code = tk.StringVar()
frame1 = ttk.Labelframe(self,text='testo').grid(column=0,row=0,padx=20,pady=20)
ttk.Radiobutton(frame1, text="Option 1", variable=self.code, value="0-0-0").pack()
ttk.Radiobutton(frame1, text="Option 1", variable=self.code, value="0-0-1").pack()
ttk.Radiobutton(frame1, text="Option 1", variable=self.code, value="0-0-2").pack()
self.ok_button = tk.Button(self, text="OK", command=self.on_ok).grid(column=0,row=1)
#self.ok_button.pack()
def on_ok(self, event=None):
self.destroy()
def show(self):
self.wm_deiconify()
self.wait_window()
return self.code.get()
class Example():
def __init__(self, root):
mainframe = ttk.Frame(root).pack(fill="both", expand=True)
self.root = root
ttk.Button(mainframe, text="Get Input", command=self.on_button).pack(padx=8, pady=8)
ttk.Label(mainframe, text="", width=20).pack(side="bottom", fill="both", expand=True)
def on_button(self):
string = PersonEmptyDocsDialog(self.root, 12).show()
print(string)
root = tk.Tk()
root.wm_geometry("400x200")
Example(root)
root.mainloop()
You cannot put in one line. You need to break this into in line 11
frame1 = ttk.Labelframe(self,text='testo')
frame1.grid(column=0,row=0,padx=20,pady=20)
Output:
Output after clicking Get input button:
Attempting to create a menu box but I am having trouble adding multiple buttons, there is only a "Quit" button visible when I run the code, please assist xx
class Menu(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.init_menu()
def init_menu(self):
self.master.title("DUNGEON MENU")
self.pack(expand = True, fill=BOTH)
quitB = Button(self, text = "Quit", fg = "red", command = self.client_exit)
quitB.grid(row = 0, column = 3, padx = 120)
def client_exit(self):
exit()
lootB = Button(self, text = "Loot", command = None)
lootB.grid(row = 1, column = 3, padx = 120)
root = Tk()
root.geometry("300x300")
app = Menu(root)
root.mainloop()
button.pack()```
I have created a working version from your code. You can find my finding in the below code as comments.
I am not totally sure what your expectation about your code. Now the "Quit" and "Loot" buttons are visible on the Frame and if you click to "Quit" button, the program will be end (Loot button does nothing).
Code:
from tkinter import Frame, BOTH, Button, Tk
class Menu(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_menu()
# You have to call the "client_exit" method to rendering the "Loot" button to Frame.
self.client_exit()
def init_menu(self):
self.master.title("DUNGEON MENU")
self.pack(expand=True, fill=BOTH)
# Destroy the master if you click to the "Quit" button.
quitB = Button(self, text="Quit", fg="red", command=lambda: self.master.destroy())
quitB.grid(row=0, column=0, padx=120)
def client_exit(self):
# exit() # This exit is not needed because it breaks the program running.
# You can define the call-back of button in "command" parameter of Button object.
lootB = Button(self, text="Loot", command=None)
lootB.grid(row=1, column=0, padx=120)
root = Tk()
root.geometry("300x300")
app = Menu(root)
root.mainloop()
# button.pack() # It does not have effect. You cannot define widgets after "mainloop"
Output:
>>> python3 test.py
I am trying to create an application that will allow you to put in multiple websites and check if they are down. When I run the code the window opens and everything works fine until i click search. Then i get the following error
AttributeError: 'Window' object has no attribute 'text_entry'
Any help would be greatly appreciated
#Import everything from tkinter
from tkinter import *
import urllib.request
#Main window
class Window(Frame):
#Master Widget
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.init_window()
#Creation of init_window
def init_window(self):
# changing the title of our master widget
self.master.title("GUI")
# allowing the widget to take the full space of the root window
self.pack(fill=BOTH, expand=1)
#Menu
menu = Menu(self.master)
self.master.config(menu=menu)
#File Menu option
file = Menu(menu)
file.add_command(label="Exit", command=self.client_exit)
menu.add_cascade(label="File", menu=file)
#Text Box
text_entry = Entry(self, width=20, bg="white")
text_entry.place(x=0, y=0)
#Submit button
searchButton = Button(self, text='SUBMIT', width=6,
command=self.search)
searchButton.place(x=200, y=30)
#Output Box
output = Text(self, width=20, height=1, bg="white")
output.place(x=0, y=50)
def search(self):
entered_text = self.text_entry.get()
output.delete(0.0, END)
definition=(int(urllib.request.urlopen(entered_text).getcode()))
output.insert(END, definition)
root = Tk()
#Size of the window
root.geometry("400x300")
#Window instance
app = Window(root)
#Show and mainloop
root.mainloop()
You haven't put text_entry on the self object and you can't access it in search function.
#Text Box
self.text_entry = Entry(self, width=20, bg="white")
self.text_entry.place(x=0, y=0)
I've used Tkinter to create a GUI with different menu options (a similar example is produced below). Each menu has different commands, which when clicked create a new frame. Now what is happening is if I switch to a different command, the new frame stacks below the current frame instead of replacing the old one.
I want to know what is the best way to move forward.
import Tkinter as tkinter
root = tkinter.Tk()
root.minsize(400,300)
welcome = tkinter.Frame(root).grid()
label = tkinter.Label(welcome, text="Welcome to my program").grid(row=0, column=3)
button = tkinter.Button(welcome,text="Exit",command=root.destroy).grid(row=3, column=1)
def newFrame():
newFrame = tkinter.Frame(root).grid()
newFrame_name = tkinter.Label(newFrame, text="This is another frame").grid()
menu = tkinter.Menu(root)
root.config(menu=menu)
main_menu = tkinter.Menu(menu)
menu.add_cascade(label="Main Menu", menu= main_menu)
main_menu.add_command(label="New Frame", command=newFrame)
main_menu.add_command(label="Another Frame", command=newFrame)
#menu.add_command(label="Exit", command=root.destroy, menu= filemenu)
root.mainloop()
Now if I switch between New Frame and Another Frame, the windows stack up, but I want one window to replace the other.
Any ideas? Thanks.
Here is a minimal example of one method I used recently; the key is in PythonGUI.show_frame, which moves the appropriate frame to the front for display.
import Tkinter as tk
class BaseFrame(tk.Frame):
"""An abstract base class for the frames that sit inside PythonGUI.
Args:
master (tk.Frame): The parent widget.
controller (PythonGUI): The controlling Tk object.
Attributes:
controller (PythonGUI): The controlling Tk object.
"""
def __init__(self, master, controller):
tk.Frame.__init__(self, master)
self.controller = controller
self.grid()
self.create_widgets()
def create_widgets(self):
"""Create the widgets for the frame."""
raise NotImplementedError
class ExecuteFrame(BaseFrame):
"""The application home page.
Attributes:
new_button (tk.Button): The button to switch to HomeFrame.
"""
def create_widgets(self):
"""Create the base widgets for the frame."""
self.new_button = tk.Button(self,
anchor=tk.W,
command=lambda: self.controller.show_frame(HomeFrame),
padx=5,
pady=5,
text="Home")
self.new_button.grid(padx=5, pady=5, sticky=tk.W+tk.E)
class HomeFrame(BaseFrame):
"""The application home page.
Attributes:
new_button (tk.Button): The button to switch to ExecuteFrame.
"""
def create_widgets(self):
"""Create the base widgets for the frame."""
self.new_button = tk.Button(self,
anchor=tk.W,
command=lambda: self.controller.show_frame(ExecuteFrame),
padx=5,
pady=5,
text="Execute")
self.new_button.grid(padx=5, pady=5, sticky=tk.W+tk.E)
class PythonGUI(tk.Tk):
"""The main window of the GUI.
Attributes:
container (tk.Frame): The frame container for the sub-frames.
frames (dict of tk.Frame): The available sub-frames.
"""
def __init__(self):
tk.Tk.__init__(self)
self.title("Python GUI")
self.create_widgets()
self.resizable(0, 0)
def create_widgets(self):
"""Create the widgets for the frame."""
# Frame Container
self.container = tk.Frame(self)
self.container.grid(row=0, column=0, sticky=tk.W+tk.E)
# Frames
self.frames = {}
for f in (HomeFrame, ExecuteFrame): # defined subclasses of BaseFrame
frame = f(self.container, self)
frame.grid(row=2, column=2, sticky=tk.NW+tk.SE)
self.frames[f] = frame
self.show_frame(HomeFrame)
def show_frame(self, cls):
"""Show the specified frame.
Args:
cls (tk.Frame): The class of the frame to show.
"""
self.frames[cls].tkraise()
if __name__ == "__main__":
app = PythonGUI()
app.mainloop()
exit()
There are two basic ways to solve the problem:
stack all of the frames on top of each other (eg: put in the same grid cell, or use place with the same options) and then raise the one that should be visible to the top of the stack (using frame.lift()). An example of the technique is in this answer: Switch between two frames in tkinter
Whenever you show a new frame, destroy (with .destroy() or hide (with pack_forget or grid_forget) the old frame.
I have a simple example. I'm sorry, because I don't know how to do this code by class. I just using simple code. But it's works!
:D
Here it is:
from Tkinter import *
def gantihal(frame):
frame.tkraise()
root = Tk()
f1 = Frame(root)
f2 = Frame(root)
f3 = Frame(root)
f4 = Frame(root)
for frame in (f1, f2, f3, f4):
frame.grid(row=0, column=0, sticky='news')
Button(f1, text='goto frame 2', command=lambda:gantihal(f2)).pack()
Label(f1, text='this is in frame 1').pack()
Label(f2, text='this is in frame two').pack()
Button(f2, text='goto frame 3', command=lambda:gantihal(f3)).pack()
Label(f3, text='this is in frame 3').pack(side='left')
Button(f3, text='next frame :)', command=lambda:gantihal(f4)).pack(side='left')
Label(f4, text='fourth frame').pack()
Button(f4, text='goto 1st frame', command=lambda:gantihal(f1)).pack()
gantihal(f1)
root.mainloop()
I am trying to to change my Tkinter Label text from another function. Somehow I cannot reference the Label and therefore not changing the Label, only add a new on top of the old.
self.errorLabel['text'] = 'second' works inside the init-function of Window, but I need to be able to do it from another function, therefore a reference fault somehow.
This is my code:
import sys
from tkinter import *
from tkinter import ttk
class Window(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.errorLabel = Label(self, text="some text").grid(row=0)
self.init_window()
def init_window(self):
self.master.title("Example")
self.pack(fill=BOTH, expand=1)
goButton = Button(self, text="Go!", command=self.client_go).grid(row=1, column=1)
quitButton = Button(self, text="Close", command=self.client_exit).grid(row=1, column=0)
def client_exit(self):
exit()
def client_go(self):
self.errorLabel['text'] = 'second' # TypeError: 'NoneType' object does not support item assignment
self.errorLabel = Label(self, text="second").grid(row=0)
return
root = Tk()
root.geometry("800x500")
app = Window(root)
root.mainloop()
This is a very common error with tkinter code. Widget.grid returns None, so when you write:
self.errorLabel = Label(self, text="some text").grid(row=0)
self.errorLabel is None. Instead, create the widget and use it's geometry manager in separate lines of code:
self.errorLabel = Label(self, text="some text")
self.errorLabel.grid(row=0)