Python Tkinter: Changing between frames dynamically - python

I'm new to python and decided to fiddle about with a bit of GIU and was wondering how can I switch between frames in a different file dynamically? I've tried adding command=Navigator.change_to_page(self, createMenuFrame) to a button but for some reason, it just combines the frames into one. Is the way I'm trying to do this doable or better to stick with a single main.py file?
I've structured my project in the following way:
main.py:
from tkinter import *
import views.viewMaker as viewMaker
root = Tk()
root.geometry("1200x700")
root.resizable(0, 0)
# Main Frame
mainFrame = Frame(root, bg="gray", width=1200, height=700)
mainFrame.pack()
mainFrame.pack_propagate(0)
viewMaker.ViewMaker.define_views(mainFrame)
root.mainloop()
views/viewMaker.py:
from tkinter import *
import commands.navigator as Navigator
class ViewMaker:
def define_views(self):
mainMenuFrame = Frame(self, bg="white", width=300, height=700) #Define Main Menu
createMenuFrame = Frame(self, bg="white", width=300, height=700) #Define Creator Menu
ViewMaker.populate_main_menu(mainMenuFrame, createMenuFrame) #Populate Main Menu
ViewMaker.populate_create_menu(createMenuFrame) #Populate Create Menu
mainMenuFrame.pack()
mainMenuFrame.pack_propagate(0)
def populate_main_menu(self, createMenuFrame): #Define Main Menu Design
mainMenuTitle = Label(self, text="Title", bg="white", font=("Georgia", 16, "bold"))
mainMenuTitle.pack(pady=25)
generateButton = Button(self, text="Generate New", width=300, font=("Georgia", 12, "bold"))
generateButton.pack(pady=5, side=TOP)
createButton = Button(self, text="Create New", width=300, font=("Georgia", 12, "bold"), command=Navigator.change_to_page(self, createMenuFrame))
createButton.pack(pady=5, side=TOP)
quitButton = Button(self, text="Quit", width=300, font=("Georgia", 12, "bold"), command=self.master.master.destroy)
quitButton.pack(pady=25, side=BOTTOM)
def populate_create_menu(self): #Define Create Menu Design
createMenuTitle = Label(self, text="Create New", bg="white", font=("Georgia", 16, "bold"))
createMenuTitle.pack(pady=25)
commands/navigator.py:
from tkinter import *
def change_to_page(self, newPage):
newPage.pack()
newPage.pack_propagate()
self.pack_forget()

Note that command=Navigator.change_to_page(self, createMenuFrame) will execute Navigattor.change_to_page() immediately which shows the createMenuFrame.
Change it to command=lambda: Navigator.change_to_page(self, createMenuFrame) instead.

Related

How to seperate Tkinter Gui app source code into multiple files

i'm working on downloading manager python gui app using Tkinter and halfway there my code started to look very messy so i decided to seperate functions on different file and then import it:
my main code:
from tkinter import *
from functions import add_download
root = Tk()
root.title("The Pownloader!")
canvas = Canvas(root, width=700, height=500).pack()
# Buttons:
ADD_BUTTON = Button(root, text="ADD", bd=4, height=2, width=5, command=add_download)
SETTINGS_BUTTON = Button(root, text="SETTINGS", bd=4, height=2, width=5)
ABOUT_BUTTON = Button(root, text="ABOUT", bd=4, height=2, width=5)
EXIT_BUTTON = Button(root, text="EXIT", bd=4, height=2, width=5, command=quit)
# Mini-Buttons:
PAUSE_MINI_BUTTON = Button(root, text="PAUSE", font=(None, "8"), height=2, width=3)
RESUME_MINI_BUTTON = Button(root, text="RESUME", font=(None, "8"), height=2, width=3)
REMOVE_MINI_BUTTON = Button(root, text="REMOVE", font=(None, "8"), height=2, width=3)
# Side_Mini_Buttons:
DOWNLOAD_WINDOW = Button(root, text="Downloads", font=(None, "8"), height=3, width=6)
ERRORS_WINDOW = Button(root, text="Failed", font=(None, "8"), height=3, width=6)
COMPLETED_WINDOW = Button(root, text="Completed", font=(None, "8"), height=3, width=6)
# Positionning Buttons:
ADD_BUTTON.place(x=70, y=20)
SETTINGS_BUTTON.place(x=145, y=20)
ABOUT_BUTTON.place(x=220, y=20)
EXIT_BUTTON.place(x=295, y=20)
PAUSE_MINI_BUTTON.place(x=290, y=455)
RESUME_MINI_BUTTON.place(x=340, y=455)
REMOVE_MINI_BUTTON.place(x=390, y=455)
DOWNLOAD_WINDOW.place(x=1, y=100)
ERRORS_WINDOW.place(x=1, y=160)
COMPLETED_WINDOW.place(x=1, y=220)
# Download Frame:
DOWNLOAD_LIST_LABEL = Label(root, text="Download List:")
DOWNLOAD_LIST_LABEL.place(x=70, y=80)
DOWNLOAD_ENTRIES = Listbox(root, width=70, height=19)
DOWNLOAD_ENTRIES.place(x=70, y=100)
# Main Loop:
root.mainloop()
However my functions.py code looks like this:
def add_download():
# Defining The Pop-up frame:
top = Toplevel(root, width = 420, height = 150)
top.title("New Download")
# Putting on widgets:
link = StringVar()
LINK_LABEL = Label(top, text = "Paste Link:")
FIELD_ENTRY = Entry(top, width = 40, textvariable=link)
def on_click():
link_to_verify = (link.get()).strip()
if len(link_to_verify)>15:
if link_to_verify[0:11]=="http://www.":
DOWNLOAD_ENTRIES.insert(0, link_to_verify)
else:
print("Stupid")
else:
print("not a valid link")
BUTTONS_WIDGET = Frame(top)
ADD_BUTTON = Button(BUTTONS_WIDGET, text = "Add", width=10, command=on_click)
CANCEL_BUTTON = Button(BUTTONS_WIDGET, text = "Cancel", width=10, command=top.destroy)
# Positionning everythig:
LINK_LABEL.grid(column=0,row=0)
FIELD_ENTRY.grid(column=1,row=0)
BUTTONS_WIDGET.grid(column=1,row=2)
ADD_BUTTON.grid(column=0,row=0)
CANCEL_BUTTON.grid(column=1,row=0)
basically i wanted the function to call and show a pop-up window, i'm sure this could done in a million times better but i'm just learning, however i receive an error says:
Toplevel is not defined
Every file needs to import tkinter.
In addition, any variables in the main file which are needed by the imported functions need to be passed into the functions. For example, you should define add_download to accept the root window as a parameter.
def add_download(root):
...
Then, in the main program, pass root as that parameter:
ADD_BUTTON = Button(root, ..., command=lambda: add_download(root))
You will need to build a class to manage it.
Inside run.py:
import tkinter as tk
from interface import GUI
root = tk.Tk()
GUI(root)
Then inside your interface.py script you can call in additional modules:
import tkinter as tk
from aux import AuxGUI
from menu import MenuGUI
class GUI:
def __init__(self, master):
self.master = master
self.GUI_list = []
self.AuxGUI = AuxGUI(self.master, self.GUI_list) # Additional module
self.MenuGUI = MenuGUI (self.master, self.GUI_list) # Additional module
Then you can use OOP to access functions or objects to dynamically interact with each other.
self.GUI_list.append(self.AuxGUI)
self.GUI_list.append(self.MenuGUI)
Inside menu.py identify the correct index from the GUI_list:
import tkinter as tk
class MenuGUI:
def __init__(self, master, GUI_list):
self.master = master
self.AuxGUI = GUI_list[0]

I need to make a label expand based on the window size

I wanted to make a title label that spans the top of the screen with the text in the middle. this works when the window opens but if I go into fullscreen, the label only spans half the length. if I make the label bigger, the text is not in the middle. it's a win-lose situation. any way to make both of them work?
import tkinter as tk
from tkinter import *
Title_Font = ("Hallo Sans", 20, "bold")
MyBlue = '#30D5C8'
Home = tk.Tk()
Home.title("Guitar Bud")
Home.geometry('1000x700')
Home.configure(bg='grey')
ExersisesLbl = tk.Label(Home, width=60, height=1, bg='black', fg=MyBlue, text='Exersises', font=Title_Font, anchor=CENTER)
ExersisesLbl.grid(row=0, column=0, columnspan=5, sticky='ew')
like #JacksonPro said, use grid_columnconfigure().
import tkinter as tk
from tkinter import *
Title_Font = ("Hallo Sans", 20, "bold")
MyBlue = '#30D5C8'
Home = tk.Tk()
Home.title("Guitar Bud")
Home.geometry('1000x700')
Home.configure(bg='grey')
Home.grid_columnconfigure(0, weight=1)
ExersisesLbl = tk.Label(Home, width=60, height=1, bg='black', fg=MyBlue, text='Exersises', font=Title_Font, anchor=CENTER)
ExersisesLbl.grid(row=0, column=0, columnspan=5, sticky='ew')
mainloop()

How to add background image to the frame in tkinter python? Instead of background color I want an image

Need to add an image as the frame background, the button quit must be on the image.I tried some codes but the image appeared as above and the frame below the image.
from tkinter import *
from tkinter import font
from PIL import ImageTk,Image
root = Tk()
root.title("Sign In")
root.geometry("600x420")
class one:
def __init__(self, root):
self.root = root
self.frame = Frame(self.root, bg="light blue", width=800, height=400)
root.geometry("800x400")
self.header = Label(self.root, bg="blue", fg="white", font=("Times New Roman", 30, "bold"))
self.header.pack(fill=X)
self.heading = Label(self.root, text="First One", fg="white", bg="blue", font=("Times New Roman", 30, "bold"))
self.heading.place(x=10, y=0)
self.q = Button(self.frame, text="Quit", bg="brown", fg="white", font=("Times New Roman", 10), command=self.root.destroy)
self.q.place(x=650, y=320, width=120, height=20)
self.frame.pack()
obj = one(root)
root.mainloop()
In Tkinter, you can add a background image to a frame by adding a label as the frame parent. Set the label background image using PIL and set the frame background to empty string.
Try this code.
from tkinter import *
from tkinter import font
from PIL import ImageTk,Image
root = Tk()
root.title("Sign In")
root.geometry("600x420")
class one:
def __init__(self, root):
self.root = root
self.img = ImageTk.PhotoImage(Image.open("bgredgrad.png")) # label image (frame background)
self.label = Label(self.root, image = self.img, width=800, height=400) # frame parent
self.frame = Frame(self.label, bg="", width=800, height=400) # main widget, clear background
self.frame.place(x=0, y=0, width=800, height=400) # required for correct z-index
root.geometry("800x400")
self.header = Label(self.root, bg="brown", fg="white", font=("Times New Roman", 30, "bold"))
self.header.pack(fill=X)
self.heading = Label(self.root, text="First One", bg="brown", fg="white", font=("Times New Roman", 30, "bold"))
self.heading.place(x=10, y=0)
self.q = Button(self.frame, text="Quit", bg="brown", fg="white", font=("Times New Roman", 10), command=self.root.destroy)
self.q.place(x=650, y=320, width=120, height=20)
self.label.pack() # pack bottom widget
obj = one(root)
root.mainloop()
Output (my background)

New window label

how do I position my label which says "Question One" in my def new_window() function. As you run it the label is being positioned at the bottom, And i want it to be applied on the top.
from tkinter import *
from tkinter import ttk
#User Interface Code
root = Tk() # Creates the window
root.title("Quiz Game")
def new_window():
newWindow = Toplevel(root)
display = Label(newWindow, width=150, height=40)
message = Label(newWindow, text="Question One", font = ("Arial", "24"))
display.pack()
message.pack()
display2 = Label(root, width=100, height=30, bg='green')
button1 = Button(root, text ="Continue", command=new_window, width=16,
bg="red")
message_label1 = Label(text="A Quiz Game", font = ("Arial", "24"), padx=40,
pady=20)
message_label2 = Label(root, text="Click 'Continue' to begin.",
wraplength=250)
display2.pack()
button1.pack()
message_label1.pack()
message_label2.pack()
root.mainloop() # Runs the main window loop
You are packing in the wrong order. Do not pack display before your message. So just swapping the order will fix the issue.
Here is the code. Replace your def new_window(): with this
def new_window():
newWindow = Toplevel()
message = Label(newWindow, text="Question One", font = ("Arial", "24"))
display = Label(newWindow, width=150, height=40)
message.pack()
display.pack()
pack method just blindly packs the widget into the window. And the next pack will be done below it if there is space. So take care of the order while packing widgets :)

Multiple Windows using Python with Tkinter

I have a school project and I need to create my GUI soon and I cant find an efficient way to do so and I need to make a ceaser Cipher button which brings up a window with an input in there and I need it all to look nice. Here is my code for now. Its not finished and needs to be finished but don't know how to?
from tkinter import *
root = Tk()
root.geometry("180x135")
class Welcome:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.button1 = Button(topFrame, text ="Decrypter Mode", bg='Black', fg="red", command = self.new_window)
self.button1.pack(side=RIGHT)
self.quitButton = Button(frame, bg='black', fg='white', text='Quit', command=master.destroy)
self.quitButton.pack(side=LEFT)
def new_window(self):
self.newWindow = tk.Toplevel(self.master)
self.app = Demo2(self.newWindow)
topFrame = Frame(root)
topFrame.pack()
bottomFrame = Frame(root)
bottomFrame.pack(side=BOTTOM)
one = Label(root, text='Welcome to Crypto-coder', bg='black', fg='white')
one.pack(fill=X)
one = Label(root, text='', bg='black', fg='white')
one.pack(fill=X,)
one = Label(root, text='', bg='black', fg='white')
one.pack(fill=X,)
one = Label(root, text='', bg='black', fg='white')
one.pack(fill=X,)
button1 = Button(topFrame, text ="Decrypter Mode", bg='Black', fg="red",)
button2 = Button(topFrame, text ="Encoder Mode", bg='black', fg="blue")
button1.pack(side=RIGHT)
button2.pack(side=LEFT)
W=Welcome(root)
root.mainloop()
I had to move some things for the code to show so you may have to fix it if you try it.

Categories