Related
I have this code in tkinter, all in one file, where I have a main window that has a frame as a menu and another frame that is the main screen. The menu calls other frames that are defined with their respective content. What I want to do is to pass each one of these frames, as inicio_page() to another file so that the code is not so long and also to be able to call them to the main file and that it is still functional.
Actually an example would be like this
from tkinter import *
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Test")
app_width = 1300
app_height = 720
screen_width = self.winfo_screenwidth()
screen_height = self.winfo_screenheight()
x = (screen_width /2) - (app_width / 2)
y = (screen_height /3) - (app_height / 3)
self.geometry(f"{app_width}x{app_height}+{int(x)}+{int(y)}")
self.minsize(width=1300, height=720)
self.maxsize(width=1920, height=1080)
backg = PhotoImage(file="img/trineside.png")
backg1 = PhotoImage(file="img/prueba4.png")
def delete_pages():
for frame in main_frame.winfo_children():
frame.destroy()
def indicate(lb, page):
hide_indicators()
lb.config(bg="white")
delete_pages()
page()
def hide_indicators():
page1_indicate.config(bg="#124e6b")
page2_indicate.config(bg="#124e6b")
menu_frame = tk.Frame(self, bg="#124e6b", highlightbackground="black", highlightthickness=1)
menu_frame.pack(side=tk.LEFT)
menu_frame.pack_propagate(False)
menu_frame.configure(width=195, height=1020)
background_menuframe= Label(menu_frame, image=backg)
background_menuframe.place(x=0, y=0, relwidth=1, relheight=1)
inicio_btn = tk.Button(menu_frame, text="Page1", font=("Bold", 18), fg="white", bd=0, bg="#124e6b", padx=56, activebackground='#124e6b', command=lambda: indicate(page1_indicate, inicio_page))
inicio_btn.place(x=10, y=100)
page1_indicate = tk.Label(menu_frame, text="", bg="#124e6b")
page1_indicate.place(x=3, y=100, width=5, height=43)
#########################################################
clientes_btn = tk.Button(menu_frame, text="Page2", font=("Bold", 18), fg="white", bd=0, bg="#124e6b",padx=40, command=lambda: indicate(page2_indicate, page_2))
clientes_btn.place(x=10, y=150)
page2_indicate = tk.Label(menu_frame, text="", bg="#124e6b")
page2_indicate.place(x=3, y=150, width=5, height=43)
#########################################################
main_frame = tk.Frame(self, highlightbackground="black", highlightthickness=1)
background_mainframe= Label(main_frame, image=backg1)
background_mainframe.place(x=0, y=0, relwidth=1, relheight=1)
main_frame.pack(side=tk.LEFT)
main_frame.pack_propagate(False)
main_frame.configure(height=1020, width=1750)
lb = tk.Label(main_frame, text="Try", font=("bold", 50))
lb.pack(pady=100)
def inicio_page():
background_mainframe= Label(main_frame, image=backg1)
background_mainframe.place(x=0, y=0, relwidth=1, relheight=1)
inicio_frame = tk.Frame(main_frame)
titulo_principal = tk.Label(main_frame,text="INICIO", font=("Bold", 15), bg="#031f3f", fg="white", height="2")
titulo_principal.pack(fill=tk.X)
inicio_frame.pack(pady=80)
#frames
f1_frame = tk.Frame(inicio_frame, bg="yellow", width=600, height=150)
f1_frame.pack()
f2_frame = tk.Frame(inicio_frame, width=500, height=400)
f2_frame.pack()
box1 = tk.Frame(f2_frame, height=20,width=250)
box1.grid(row=0, column=0)
box2 = tk.Frame(f2_frame, height=20,width=250)
box2.grid(row=0, column=1)
btn_logs = Button(box1,text="Abrir Logs",width=18)
btn_logs.pack(pady=20,padx=80)
btn_informes = Button(box2,text="Abrir Informes", width=18)
btn_informes.pack(pady=20,padx=80)
textof1 = Label(f1_frame, text="")
textof1.pack()
if __name__ == "__main__":
app = App()
app.mainloop()
What I did was to pass the inicio_page() function to another file and modify the button command to call the new class. My problem is that when I click on the button it does not show me the content that is in the InicioPage class.
I leave an example of what I tried.
from tkinter import *
import tkinter as tk
from frame_inicio import InicioPage
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Test")
app_width = 1300
app_height = 720
screen_width = self.winfo_screenwidth()
screen_height = self.winfo_screenheight()
x = (screen_width /2) - (app_width / 2)
y = (screen_height /3) - (app_height / 3)
self.geometry(f"{app_width}x{app_height}+{int(x)}+{int(y)}")
self.minsize(width=1300, height=720)
self.maxsize(width=1920, height=1080)
backg = PhotoImage(file="img/trineside.png")
backg1 = PhotoImage(file="img/prueba4.png")
def delete_pages():
for frame in main_frame.winfo_children():
frame.destroy()
menu_frame = tk.Frame(self, bg="#124e6b", highlightbackground="black", highlightthickness=1)
menu_frame.pack(side=tk.LEFT)
menu_frame.pack_propagate(False)
menu_frame.configure(width=195, height=1020)
background_menuframe= Label(menu_frame, image=backg)
background_menuframe.place(x=0, y=0, relwidth=1, relheight=1)
inicio_btn = tk.Button(menu_frame, text="Inicio", font=("Bold", 18), fg="white", bd=0, bg="#124e6b", padx=56, activebackground='#124e6b', command=lambda: delete_pages() and InicioPage(main_frame))
inicio_btn.place(x=10, y=100)
page1_indicate = tk.Label(menu_frame, text="", bg="#124e6b")
page1_indicate.place(x=3, y=100, width=5, height=43)
#########################################################
clientes_btn = tk.Button(menu_frame, text="Page2", font=("Bold", 18), fg="white", bd=0, bg="#124e6b",padx=40, command=lambda: indicate(page2_indicate, page_2))
clientes_btn.place(x=10, y=150)
page2_indicate = tk.Label(menu_frame, text="", bg="#124e6b")
page2_indicate.place(x=3, y=150, width=5, height=43)
#########################################################
main_frame = tk.Frame(self, highlightbackground="black", highlightthickness=1)
background_mainframe= Label(main_frame, image=backg1)
background_mainframe.place(x=0, y=0, relwidth=1, relheight=1)
main_frame.pack(side=tk.LEFT)
main_frame.pack_propagate(False)
main_frame.configure(height=1020, width=1750)
lb = tk.Label(main_frame, text="Try", font=("bold", 50))
lb.pack(pady=100)
frame_inicio.py
from tkinter import *
import tkinter as tk
class InicioPage:
def __init__(self, main_frame):
self.frame = tk.Frame(main_frame)
backg1 = PhotoImage(file="img/prueba4.png")
background_mainframe= Label(main_frame, image=backg1)
background_mainframe.place(x=0, y=0, relwidth=1, relheight=1)
inicio_frame = tk.Frame(main_frame)
titulo_principal = tk.Label(main_frame,text="INICIO", font=("Bold", 15), bg="#031f3f", fg="white", height="2")
titulo_principal.pack(fill=tk.X)
inicio_frame.pack(pady=80)
#frames
f1_frame = tk.Frame(self.frame, bg="yellow", width=600, height=150)
f1_frame.pack()
f2_frame = tk.Frame(self.frame, width=500, height=400)
f2_frame.pack()
box1 = tk.Frame(f2_frame, height=20,width=250)
box1.grid(row=0, column=0)
box2 = tk.Frame(f2_frame, height=20,width=250)
box2.grid(row=0, column=1)
btn_logs = Button(box1,text="Abrir Logs",width=18)
btn_logs.pack(pady=20,padx=80)
btn_informes = Button(box2,text="Abrir Informes", width=18)
btn_informes.pack(pady=20,padx=80)
You aren't instantiating the class InicioPage anywhere I can see. You'll need to create an instance of InicioPage with the desired parent like so:
from frame_inicio import InicioPage
... # other code has been omitted for brevity
# FYI, widgets that are defined within a class should be prefixed with 'self.'
# e.g.: 'self.main_frame = tk.Frame', 'self.main_frame.pack()', etc.
main_frame.pack(side=tk.LEFT)
self.start_page = InicioPage(main_frame) # instantiate the class object to use it
Note that for the expression delete_pages() and InicioPage(main_frame), InicioPage(main_frame) will never be executed because delete_pages() returns None which is evaluated as False in the expression.
Either return True from delete_pages() or change and to or in the expression.
Got from #JRiggles's example.
In line 49 change this:
clientes_btn = tk.Button(menu_frame, text="Page2", font=("Bold", 18), fg="white", bd=0, bg="#124e6b",padx=40, command=lambda: InicioPage(page2_indicate))
to:
clientes_btn = tk.Button(menu_frame, text="Page2", font=("Bold", 18), fg="white", bd=0, bg="#124e6b",padx=40, command=lambda: InicioPage(main_frame))
frame_inicio.py.
Add this self.frame.mainloop() to bottom
Screenshot:
Screenshot when pressed page 2 button:
I am working on a simple counter app in tkinter. I rigged up some code looking at few tutorial on web. All the functions of a counter are set up. But when it comes to the designing of the app, I want the Count, the Count button, and the reset button to be aligned at the center.
The code is as below
from tkinter import Label, Button, Tk
from tkinter import font
window = Tk()
window.geometry('500x500')
window.title("Counter")
window.count = 0
def increment():
window.count += 1
lbl.configure(text=window.count)
def reset():
window.count = 0
lbl.configure(text=window.count)
lbl = Label(window, text="0", font=("Apple Braille", 60))
lbl.grid(column=0, row=0)
btn1 = Button(window, text="Count", command=increment)
btn1.grid(column=0, row=1)
btn2 = Button(window, text="Reset", command=reset)
btn2.grid(column=1, row=1)
btn1['font'] = btn2['font'] = font.Font(size=30)
window.mainloop()
A Screenshot of my counter app is here
Any help in this aspect will be appreciated.
Thanks,
It is easier to use pack() instead of grid() for your requirement.
lbl = Label(window, text="0", font=("Apple Braille", 60))
lbl.pack()
# frame for the two buttons
frame = Frame(window)
frame.pack()
btn1 = Button(frame, text="Count", command=increment)
btn1.grid(column=0, row=1)
btn2 = Button(frame, text="Reset", command=reset)
btn2.grid(column=1, row=1)
If you want to put at the center of the window:
# frame for the label and buttons
frame = Frame(window)
frame.place(relx=0.5, rely=0.5, anchor="c") # put at center of window
lbl = Label(frame, text="0", font=("Apple Braille", 60))
lbl.grid(row=0, column=0, columnspan=2)
btn1 = Button(frame, text="Count", command=increment)
btn1.grid(column=0, row=1)
btn2 = Button(frame, text="Reset", command=reset)
btn2.grid(column=1, row=1)
I was wondering why when I use the columnspan parameter in the .grid() function the button does not change size. Should it not span all columns within the frame? Below I have my code and the output. Thanks all.
# Import Modules
from tkinter import ttk
import tkinter as tk
import os
# Basic Structure
root = tk.Tk()
root.minsize(600, 700)
root.maxsize(600, 700)
root.title("Training HUB")
root.config(bg="slategray")
# Create Frames - Title, Left and Right Frames
title_frame = tk.Frame(root, width=580, height=50, bg='white', highlightbackground="black", highlightthickness=1)
title_frame.grid(row=0, columnspan=2, padx=10, pady=5)
left_frame = tk.Frame(root, width=280, height=550, bg='white', highlightbackground="black", highlightthickness=1)
left_frame.grid(row=1, column=0, padx=10, pady=5)
left_frame.grid_propagate(0)
right_frame = tk.Frame(root, width=280, height=550, bg='white', highlightbackground="black", highlightthickness=1)
right_frame.grid(row=1, column=1, padx=10, pady=5)
right_frame.grid_propagate(0)
# Buttons
button1 = ttk.Button(right_frame, text="Run Processing").grid(
row=0, column=0, columnspan = 2, padx=5, pady=5, sticky = 'ew')
# Run Application
root.mainloop()
Tkinter Output:
This is a part of code from my school project.
from tkinter import *
from tkinter.font import Font
class student_window():
def __init__(self, master):
self.student_win = master
#window = Toplevel(self.master)
self.student_win.geometry("1280x720")
self.header1Font = Font(family='Helvetica', size=20)
self.optionFont = Font(family='Sans Serrif', size=20)
self.student_win.focus()
self.show_window()
def show_window(self):
print("ookk")
self.student_win.title("Student Window")
self.option_frame = Frame(self.student_win, width=200, height=720)
lbl_header = Label(self.option_frame,text="EXAMINATION", font=self.header1Font, fg='white', bg='#172D44').grid(row=0,column=0, sticky=NSEW)
lbl_welcome = Label(self.option_frame, text="Welcome,", fg='#E9F1F7', bg='#2A3F54').grid(row=1,column=0)
lbl_username = Label(self.option_frame, text="Username", fg='white', bg='#2A3F54').grid(row=2,column=0)
lbl_header2 = Label(self.option_frame, text="STUDENT CORNER", fg='white', bg='#2A3F54').grid(row=3, column=0)
self.btn_tests = Button(self.option_frame, text="Attempt Exam", fg='#E9F1F7', bg='#35495D', relief=FLAT)
self.btn_tests.grid(row=4,column=0, sticky=NSEW)
self.btn_attempts = Button(self.option_frame, text="Attempts", fg='#E9F1F7', bg='#2A3F54', relief=FLAT)
self.btn_attempts.grid(row=5, column=0, sticky=NSEW)
self.btn_result = Button(self.option_frame, text="Result", fg='#E9F1F7', bg='#2A3F54', relief=FLAT)
self.btn_result.grid(row=6, column=0, sticky=NSEW)
self.btn_goBack = Button(self.option_frame, text="Go Back", fg='#E9F1F7', bg='#2A3F54', relief=FLAT)
self.btn_goBack.grid(row=7, column=0, sticky=NSEW)
self.option_frame.configure(bg='#2A3F54')
self.option_frame.grid(row=0, column=0)
self.option_frame.grid_propagate(0)
self.main_frame = Frame(self.student_win, width=880, height=720)
self.main_result_frame = Frame(self.main_frame)
self.main_result_frame.grid(row=0,column=0)
self.attempts_frame = Frame(self.main_frame)
self.attempts_frame.grid(row=0, column=0)
self.test_frame = Frame(self.main_frame)
lbl_test = Label(self.test_frame, text="In test frame").pack()
self.test_frame.grid(row=0,column=0)
self.main_frame.grid(row=0,column=1)
self.main_frame.grid_propagate(0)
self.info_frame = Frame(self.student_win, width=200, height=720)
self.btn_username = Button(self.info_frame, text="Username", relief=FLAT)
self.btn_username.grid(row=0,column=0)
self.userInfo_frame = Frame(self.info_frame)
self.info_frame.grid(row=0, column=2)
self.info_frame.grid_propagate(0)
root = Tk()
student_window(root)
root.mainloop()
And it looks something like this.
The Student Panel for my project
The whole window is divided into three frames and want to expand each label and button of the left frame(self.option_frame) to fill it horizontally. I tried doing sticky=EW and sticky=NSEW but still some space is left. How do I fix that?
You need to call self.option_frame.columnconfigure(0, weight=1) to make column 0 to use all the available horizontal space.
I was just trying some things and what I have found to be working is to make the label width bigger than than the frame then anchoring the text to the left.
import time
import tkinter as tk
from tkinter import scrolledtext
win = tk.Tk()
win.title("My First Game")
win.configure(bg="black")
win.geometry("640x400")
label = tk.Label(win, text="test", fg="red", bg="black").pack()
canvas1 = tk.Canvas(win, width=130, height=20)
canvas1.pack()
entry1 = tk.Entry(win, font="Helvetica 10")
canvas1.create_window(65, 10, window=entry1)
entry1.insert(0, "Type here")
def shortcut():
Shortcut = tk.Label(win, fg="red", bg="black", text="test2")
Shortcut.pack()
button1 = tk.Button(win, text="Enter", fg="red", bg="black", command=shortcut)
button1.pack()
exit_button = tk.Button(win, text="Quit", padx=4, pady=2, bg="black", fg="red", command=quit)
exit_button.pack()
exit_button.grid(row=0, column=2)
win.mainloop()
Why is this giving me an error? I tried in a separate project with just a black screen and the button and it worked fine. But when I put it in the code above it doesn't work
line 42, in <module> exit_button.grid(row=0, column=2)
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
As #10Rep mentioned in comment - you can remove grid() to resolve problem with error.
import tkinter as tk
# --- functions ---
def shortcut():
shortcut = tk.Label(win, text="test2")
shortcut.pack()
# --- main ---
win = tk.Tk()
label = tk.Label(win, text="test")
label.pack()
canvas1 = tk.Canvas(win) #, width=130, height=20)
canvas1.pack()
entry1 = tk.Entry(canvas1)
canvas1.create_window(0, 0, window=entry1, anchor='nw')
entry1.insert(0, "Type here")
button1 = tk.Button(win, text="Enter", command=shortcut)
button1.pack()
exit_button = tk.Button(win, text="Quit", command=win.destroy)
exit_button.pack()
win.mainloop()
But I expect that you used grid() to organize two buttons in one line.
Problem is that you can't mix pack() and grid() in one window/frame and I see two solutions:
First is to use only grid() to organize all widgets
import tkinter as tk
# --- functions ---
def shortcut():
shortcut = tk.Label(win, text="test2")
shortcut.grid(row=3, column=0, columnspan=2)
# --- main ---
win = tk.Tk()
label = tk.Label(win, text="test")
label.grid(row=0, column=0, columnspan=2)
canvas1 = tk.Canvas(win) #, width=130, height=20)
canvas1.grid(row=1, column=0, columnspan=2)
entry1 = tk.Entry(canvas1)
canvas1.create_window(0, 0, window=entry1, anchor='nw')
entry1.insert(0, "Type here")
button1 = tk.Button(win, text="Enter", command=shortcut)
button1.grid(row=2, column=0)
exit_button = tk.Button(win, text="Quit", command=win.destroy)
exit_button.grid(row=2, column=1)
win.mainloop()
Second is to put Frame (using pack()) and put buttons inside this frame using grid()
import tkinter as tk
# --- functions ---
def shortcut():
shortcut = tk.Label(win, text="test2")
shortcut.pack()
# --- main ---
win = tk.Tk()
label = tk.Label(win, text="test")
label.pack()
canvas1 = tk.Canvas(win) #, width=130, height=20)
canvas1.pack()
entry1 = tk.Entry(canvas1)
canvas1.create_window(0, 0, window=entry1, anchor='nw')
entry1.insert(0, "Type here")
# - frame with grid -
f = tk.Frame(win)
f.pack()
button1 = tk.Button(f, text="Enter", command=shortcut)
button1.grid(row=0, column=0)
exit_button = tk.Button(f, text="Quit", command=win.destroy)
exit_button.grid(row=0, column=1)
# -
win.mainloop()
or using pack(side=...)
import tkinter as tk
# --- functions ---
def shortcut():
shortcut = tk.Label(win, text="test2")
shortcut.pack()
# --- main ---
win = tk.Tk()
label = tk.Label(win, text="test")
label.pack()
canvas1 = tk.Canvas(win) #, width=130, height=20)
canvas1.pack()
entry1 = tk.Entry(canvas1)
canvas1.create_window(0, 0, window=entry1, anchor='nw')
entry1.insert(0, "Type here")
# - frame with pack(side=...) -
f = tk.Frame(win)
f.pack()
button1 = tk.Button(f, text="Enter", command=shortcut)
button1.pack(side='left')
exit_button = tk.Button(f, text="Quit", command=win.destroy)
exit_button.pack(side='left')
# -
win.mainloop()