How to keep a constant layout in multiple windows Tkinter program? - python

I am working on a Python Tkinter application which is expected to have multiple windows. At the same time, I would like to keep certain layout (background image, Top/bottom labels) constant. I have tried to set the background image (b_image) and top left label (topleft_label ) but it's not showing up. Can someone look at this snippet and advise how to achieve this?
import tkinter as tk
LARGE_FONT= ("Verdana", 12)
HEIGHT = 768
WIDTH = 1024
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("Sales System") # set the title of the main window
self.geometry("%dx%d+0+0" % (WIDTH, HEIGHT)) # set size of the main window to 300x300 pixels
container = tk.Frame(self)
b_image = tk.PhotoImage(file='background.png')
b_label = tk.Label(container, image=b_image)
b_label.place(relwidth=1, relheight=1)
topleft_label = tk.Label(container, bg='black', fg='white', text="Welcome - Login Screen", justify='left', anchor="w", font="Verdana 12")
topleft_label.place(relwidth=0.5, relheight=0.05, relx=0.25, rely=0, anchor='n')
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
frame = StartPage(container, self)
self.frames[StartPage] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
app = MainApp()
app.mainloop()

The approach
The best way of going about this is most likely be to make a base_frame class, which contains the image and the topleft_label, "Welcome - Login Screen". This means the StartPage object can inherit the background image from the base_frame class.
The Code
import tkinter as tk
LARGE_FONT= ("Verdana", 12)
HEIGHT = 768
WIDTH = 1366
class MainApp():
def __init__(self, master):
self.master = master
self.master.title("Sales System")
self.master.geometry("%dx%d+0+0" % (WIDTH, HEIGHT))
self.frames = {}
start_page = StartPage(master)
self.frames[StartPage] = start_page
start_page.grid(row=0, column=0, sticky="nsew")
self.master.grid_rowconfigure(0, weight=1)
self.master.grid_columnconfigure(0, weight=1)
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class base_frame(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(master, *args, **kwargs)
b_image = tk.PhotoImage(file='background.png')
b_label = tk.Label(self, image=b_image)
b_label.image = b_image
b_label.place(x=0, y=0, relwidth=1, relheight=1)
topleft_label = tk.Label(self, bg='black', fg='white', text="Welcome - Login Screen", justify='left', anchor="w", font="Verdana 12")
topleft_label.place(relwidth=0.5, relheight=0.05, relx=0.25, rely=0, anchor='n')
class StartPage(base_frame):
def __init__(self, parent):
super().__init__(self, parent)
label = tk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
def main():
root = tk.Tk() # MainApp()
main_app = MainApp(root)
root.mainloop()
if __name__ == '__main__':
main()
The Breakdown
Starting the Code
The piece of code that makes this class system run is like so:
def main():
root = tk.Tk() # MainApp()
main_app = MainApp(root)
root.mainloop()
if __name__ == '__main__':
main()
The line if __name__ == '__main__':, in English, roughly translates too: If the program is run and not imported. So, if the program is run and not imported, run the main function.
root = tk.Tk() simply creates a Tk window inside of the root variable.
main_app = MainApp(root) initializes the main_app object with its master being the root variable
root.mainloop() starts the tkinter loop.
The MainApp Class
The MainApp Class starts by setting its title to "Sales System" and resetting the geometry to the values defined in HEIGHT & WIDTH:
self.master = master
self.master.title("Sales System")
self.master.geometry("%dx%d+0+0" % (WIDTH, HEIGHT))
Then the self.frames dictionary & the start_page is initialized and the start_page is placed in self.frames:
self.frames = {}
start_page = StartPage(master)
self.frames[StartPage] = start_page
The start_page is then set to fill the whole of the window:
start_page.grid(row=0, column=0, sticky="nsew")
self.master.grid_rowconfigure(0, weight=1)
self.master.grid_columnconfigure(0, weight=1)
We then show the first page:
self.show_frame(StartPage)
The show_frame function is then created
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
The base_frame Class
The first 3 lines creates a class which takes values the same as a tk.Frame object does, with args and key word args passed through:
class base_frame(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(master, *args, **kwargs)
Then the image label is created:
b_image = tk.PhotoImage(file='background.png')
b_label = tk.Label(self, image=b_image)
b_label.image = b_image
b_label.place(x=0, y=0, relwidth=1, relheight=1)
The b_label.image = b_image line is used to make sure the image is shown by the label (this is required when loading from within a function).
We then create the default topleft_label:
topleft_label = tk.Label(self, bg='black', fg='white', text="Welcome - Login Screen", justify='left', anchor="w", font="Verdana 12")
topleft_label.place(relwidth=0.5, relheight=0.05, relx=0.25, rely=0, anchor='n')
You may wish to update this code for these labels to be changed in the future, to do this simply replace topleft_label with self.topleft_label and b_label with self.b_label
The StartPage Class
This class is not much different to the class you created previously:
class StartPage(base_frame):
def __init__(self, parent):
super().__init__(self, parent)
label = tk.Label(self, text="Start Page", font=LARGE_FONT)
label.pack(pady=10,padx=10)
The only difference being instead of inheriting from tk.Frame, it inherits from the base_frame class.

Related

How to prevent multiple windows from popping up in tkinter?

import tkinter as tk
from tkinter import *
from tkinter import ttk
LARGE_FONT = ("Verdana", 12)
class pages(tk.Tk):
#starts us off in the login page
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "ScanNET")
tk.Tk.wm_minsize(self, 800, 800)
container = tk.Frame(self)
container.pack(side=TOP, fill=BOTH, expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (loginpage, GUI):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky=N+E+S+W)
self.show_frame(loginpage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class loginpage(tk.Frame):
#login page content
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
loginlabel = tk.Label(self, text="login page", font=LARGE_FONT)
loginlabel.pack(padx=10, pady=10)
#button moves you to gui
loginbutton1 = tk.Button(self, text= "Go to GUI", command=lambda: controller.show_frame(GUI))
loginbutton1.pack()
class GUI(tk.Frame):
def __init__(self, parent, controller):
#all widths and heights aren't official, most likely change
tk.Frame.__init__(self, parent)
self.root = tk.Tk()
#the tabs
my_notebook = ttk.Notebook(self.root)
my_notebook.pack()
devicestab = Frame(my_notebook, width=800, height=600)
reportstab = Frame(my_notebook, width=800, height=600)
devicestab.pack(fill=BOTH, expand=1)
reportstab.pack(fill=BOTH, expand=1)
my_notebook.add(devicestab, text="Devices")
my_notebook.add(reportstab, text="Reports")
#contents for devices tab
devicesleft = LabelFrame(devicestab, text="Devices found: ", padx=5, pady=5, width=500, height=600)
devicesleft.grid(row=0, column=0)
devicesright = LabelFrame(devicestab, text="Activity Feed: ", padx=5, pady=5, width=300 , height=600)
devicesright.grid(row=0, column=1)
#contents for reports tab
reportsleft = LabelFrame(reportstab, text="Report Summaries: ", padx=5, pady=5, width=400 , height=600)
reportsleft.grid(row=0, column=0)
reportsright= LabelFrame(reportstab, text="Charts and Diagrams: ", padx=5, pady=5, width=400 , height=600)
reportsright.grid(row=0, column=1)
app = pages()
app.mainloop()
When I run this, both the loginpage and GUI windows open. Correct me if I'm wrong, but I think the problem is probably around the
tk.Frame.__init__(self, parent)
self.root = tk.Tk()
my_notebook = ttk.Notebook(self.root)
part in the GUI class. I've searched everywhere and I can't seem to find a way to have a first page as a login page which will move to a second page that has tabs using notebook. I feel as if something else has to be in the ttk.Notebook() part, and perhaps remove self.root = tk.Tk() after. I'd love to hear what y'all think.
I am assuming you want the notebook in the same widget of the rest, so you should not use tk.Tk() and then you place the notebook in the parent which is already your root. Check the code in the end of my answer. Also, since there was a lot of problems with your code I made some changes and comments that will help you to write better codes in tkinter. Please read it carefully. You may also want to study the effbot web page.
import tkinter as tk
# from tkinter import * # just don't do this
from tkinter import ttk
LARGE_FONT = ("Verdana", 12)
# class pages(tk.Tk):
class Pages(tk.Tk): # class names should start with upper case
#starts us off in the login page
# def __init__(self, *args, **kwargs):
def __init__(self):
# tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.__init__(self)
# tk.Tk.wm_title(self, "ScanNET")
self.winfo_toplevel().title("ScanNET")
# tk.Tk.wm_minsize(self, 800, 800)
self.wm_minsize(800, 800) # since you defined tk.Tk as pages parent you can call Tk methods directly
container = tk.Frame(self)
# container.pack(side=TOP, fill=BOTH, expand=True)
# container.grid_rowconfigure(0, weight=1)
# container.grid_columnconfigure(0, weight=1)
container.grid(row=0, column = 0) # don't use pack if you want to use grid
self.frames = {}
for F in (loginpage, GUI):
frame = F(container, self)
self.frames[F] = frame
# frame.grid(row=0, column=0, sticky=N+E+S+W)
frame.grid(row=0, column=0, sticky='NESW') #since we are not importing all we are not importing tk.W but you can use string instead
self.show_frame(loginpage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class loginpage(tk.Frame):
#login page content
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
loginlabel = tk.Label(self, text="login page", font=LARGE_FONT)
loginlabel.pack(padx=10, pady=10)
#button moves you to gui
loginbutton1 = tk.Button(self, text= "Go to GUI", command=lambda: controller.show_frame(GUI))
loginbutton1.pack()
class GUI(tk.Frame):
def __init__(self, parent, controller):
#all widths and heights aren't official, most likely change
tk.Frame.__init__(self, parent)
# self.root = tk.Tk() # don't create new Tk objects, you just need one. The others should be Toplevel objects
### self.root = tk.Toplevel() ### this would be the correct way of creating a new window but you don't want to do that here your root is your parent
#the tabs
# my_notebook = ttk.Notebook(self.root)
my_notebook = ttk.Notebook(self) # this is how you place the notebook in the Frame widget and not in a new one
# my_notebook.pack()
my_notebook.grid() # we are now using grid so it will not accept pack anymore
# devicestab = Frame(my_notebook, width=800, height=600)
devicestab = tk.Frame(my_notebook, width=800, height=600) # again, since we are not importing al we have to use tk. before tkinter methods
# reportstab = Frame(my_notebook, width=800, height=600)
reportstab = tk.Frame(my_notebook, width=800, height=600)
# devicestab.pack(fill=BOTH, expand=1)
devicestab.pack(fill="both", expand=1) # instead of tk.BOTH we can use "both"
reportstab.pack(fill="both", expand=1)
my_notebook.add(devicestab, text="Devices")
my_notebook.add(reportstab, text="Reports")
#contents for devices tab
devicesleft = tk.LabelFrame(devicestab, text="Devices found: ", padx=5, pady=5, width=500, height=600)
devicesleft.grid(row=0, column=0)
devicesright = tk.LabelFrame(devicestab, text="Activity Feed: ", padx=5, pady=5, width=300 , height=600)
devicesright.grid(row=0, column=1)
#contents for reports tab
reportsleft = tk.LabelFrame(reportstab, text="Report Summaries: ", padx=5, pady=5, width=400 , height=600)
reportsleft.grid(row=0, column=0)
reportsright= tk.LabelFrame(reportstab, text="Charts and Diagrams: ", padx=5, pady=5, width=400 , height=600)
reportsright.grid(row=0, column=1)
app = Pages()
app.mainloop()

Tkinter unable to update label text

I am trying to use GPS sensor with RPI and make its GUI using Tkinter. I want to update my GPS value and shows in the GUI. But in GUI it shows only initial value. In backend GPS value is updating but unable to show in GUI.
import tkinter as tk
import serial
import time
import webbrowser as wb
ser = serial.Serial('/dev/ttyUSB0', 9600)
class IotCar(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
width=tk.Tk.winfo_screenwidth(self)
height=tk.Tk.winfo_screenheight(self)
tk.Tk.geometry(self, '{}x{}'.format(width, height))
container=tk.Frame(self)
container.pack(side='top', fill='both', expand='True')
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for each_frame in (StartPage, HomePage):
frame = each_frame(container, self)
self.frames[each_frame]=frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_page(StartPage)
def show_page(self, cont):
frame=self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
next_button = tk.Button(self, text='Next', command=lambda:
controller.show_page(HomePage)).pack(side=tk.TOP,padx=5, pady=5)
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.gps_pos()
self.lat1 = tk.StringVar()
self.lon1=tk.StringVar(self)
self.label_lat = tk.Label(self.HomePage, text='Latitude', justify=tk.LEFT, padx=10).pack()
self.label_lat1 = tk.Label(self.HomePage, textvariable=self.lat1, justify=tk.LEFT,
borderwidth=2, relief='ridge').pack()
self.label_lon = tk.Label(self, text='Longitude', justify=tk.LEFT, padx=10).pack()
self.label_lon1 = tk.Label(self, text=self.lon1, justify=tk.LEFT,
borderwidth=2, relief='ridge').pack()
def gps_pos(self):
print('Entered into gps')
ser.flushInput()
ser.flushOutput()
ser.write(b'AT+CGPSPWR=1\r')
ser.write(b'AT+CGPSOUT=32\r')
while True:
gps=str(ser.readline())
gps=gps[2:].split(',')
if gps[0]=='$GPRMC' and gps[3]!='':
lat=gps[1]
lon=gps[1]
break;
self.after(3000,self.gps_pos)
print(lat, lon)
self.lat1.set(lat1)
app = IotCar()
app.mainloop()
Please help me to understand what is wrong in it. Thank you in advance.
I am unable to run this script as I don't have the serial module however I have modified a few things and this populates the label with text (comments in code). You need a function that will assign the "text" parameters in the labels with a value.
import tkinter as tk
import time
import webbrowser as wb
class IotCar(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
width=tk.Tk.winfo_screenwidth(self)
height=tk.Tk.winfo_screenheight(self)
tk.Tk.geometry(self, '{}x{}'.format(width, height))
container=tk.Frame(self)
container.pack(side='top', fill='both', expand='True')
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for each_frame in (StartPage, HomePage):
frame = each_frame(container, self)
self.frames[each_frame]=frame
frame.grid(row=0, column=0, sticky='nsew')
self.show_page(StartPage)
def show_page(self, cont):
frame=self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
next_button = tk.Button(self, text='Next', command=lambda:
controller.show_page(HomePage)).pack(side=tk.TOP,padx=5, pady=5)
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.lat1 = tk.StringVar()
self.lon1 = tk.StringVar(self)
self.label_lat = tk.Label(self, text='Latitude', justify=tk.LEFT, padx=10)
self.label_lat.pack()
self.label_lat1 = tk.Label(self, justify=tk.LEFT,
borderwidth=2, relief='ridge') # I have removed the "text" parameter because my function will update it.
self.label_lat1.pack()
self.label_lon = tk.Label(self, text='Longitude', justify=tk.LEFT, padx=10)
self.label_lon.pack()
self.label_lon1 = tk.Label(self, justify=tk.LEFT,
borderwidth=2, relief='ridge') # I have removed the "text" parameter because my function will update it.
self.label_lon1.pack()
button = tk.Button(self, text="update label", bg= "#aaaaaa", fg ="#483F44",
font=("Arial", 10, "bold"), relief="groove", command = lambda: helloworld()) # This button will run the helloworld function
button.pack()
def helloworld():
self.label_lat1["text"] = "Hello" #This will update the text parameter in label_lat1 with "Hello"
self.label_lon1["text"] = "World" #This will update the text parameter in label_lon1 with "World"
app = IotCar()
app.mainloop()
A few things to note is to pack/place/grid your labels separately from when you define its parameters i believe that the way you have currently set up the widget is giving it a None type which is why you can't assign text to it:
#You write
self.label_lat1 = tk.Label(self.HomePage, textvariable=self.lat1, justify=tk.LEFT,
borderwidth=2, relief='ridge').pack()
#My example
self.label_lat1 = tk.Label(self, justify=tk.LEFT,
borderwidth=2, relief='ridge')
self.label_lat1.pack()
You then need a command that will run a function and in that function will have a variable which will assign a text value to the label (i.e. the helloworld function in my code).
Looking at your code i believe you will need to amend the way you are packing your widgets and then in your function do something like
def gps_pos(self):
print(lat, lon)
self.label_lat1["text"] = lat
self.label_lon1["text"] = lon
Below is a very useful answer on how to layout your tkinter gui and various other FAQ. I myself found it extremely useful
Switch between two frames in tkinter

having issues with the if statement

With the if-statement that I have put in, it would only display the lose statement even if it is correct.
I'm not sure if the way I wrote the statement is correct.
I'm trying to make it that when pressing start both labels would show a number between 1 to 21.
Also, if it's possible, I want to make it that when the hit button is pressed, a number would be added to the label. For example, pressing hit would add 10 + 5, then display the total.
LOCATED IN CLASS TTY:
import tkinter as tk
k = 10
Q = 10
J = 10
A = 11 or 1
class WINDOW(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Memory") #sets the window title
container = tk.Frame(self)#Name of frame to refer to
container.pack(side="top", fill="both", expand=True)#size of window
container.grid_rowconfigure(0, weight=4)#size of window
container.grid_columnconfigure(0, weight=4)
self.frames = {}
for F in (MainMenu, tty):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("MainMenu")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class MainMenu(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background = 'white')
label = tk.Label(self, text="Memory",font=(15),
borderwidth=5, relief="solid")
label.pack(side="top", fill="y", pady=15, padx=270)
label.pack(fill="both")
button1 = tk.Button(self, text="Start", relief="solid",
borderwidth=5,width=30,
font=(17),command=lambda:
controller.show_frame("tty"))
button1.pack()
button3 = tk.Button(self,
text="Quit",relief="solid",borderwidth=4,width=30,font=(17),command = quit)
button3.place(x="420", y ="50")
button3.pack()
class tty(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background = "white")
def win():
if score > deal:
tts = tk.Label(self, text="win", font=(20))
tts.pack()
else:
lose = tk.Label(self, text="lose", font=(10))
lose.pack() #The if statement
deal = tk.Label(self, text="18", font=(18))
deal.pack(side="top", fill="y", pady=15, padx=270)
score = tk.Label(self, text="19", font=(18))
score.pack()
f = tk.Frame(self)
button1 = tk.Button(f,borderwidth=5, text="stand", font=(18),command =
lambda: win())#This is the button that i want to display the label
button1.grid(row=0,column=0)
button2 = tk.Button(f, text="Hit",borderwidth=5, font=(18))
button2.grid(row=0,column=1)
f.pack(side="bottom")
button3 = tk.Button(self, text="Quit", font=(18))
button3.pack(side="right", pady=50)
if __name__ == "__main__":
app = WINDOW()
app.geometry("800x400")
app.mainloop()
if score > deal: is comparing two tkinter label objects rather than the value of score and deal. Try getting the value of the labels and converting them to integers before doing the comparision.
if int(score['text']) > int(deal['text']):
To help with your other questions.
To chose a random number between 1 and 21, use the randint function contained inside python's random module (see code below). I've added a new randomise function which will be called after the page is created to randomly select a value for deal and score.
With the hit button, i've added a new function hit which will take the current score, and add another random value to it.
import tkinter as tk
from random import randint
k = 10
Q = 10
J = 10
A = 11 or 1
class WINDOW(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Memory") #sets the window title
container = tk.Frame(self)#Name of frame to refer to
container.pack(side="top", fill="both", expand=True)#size of window
container.grid_rowconfigure(0, weight=4)#size of window
container.grid_columnconfigure(0, weight=4)
self.frames = {}
for F in (MainMenu, tty):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("MainMenu")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class MainMenu(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background = 'white')
label = tk.Label(self, text="Memory",font=(15),
borderwidth=5, relief="solid")
label.pack(side="top", fill="y", pady=15, padx=270)
label.pack(fill="both")
button1 = tk.Button(self, text="Start", relief="solid",
borderwidth=5,width=30,
font=(17),command=lambda:
controller.show_frame("tty"))
button1.pack()
button3 = tk.Button(self,
text="Quit",relief="solid",borderwidth=4,width=30,font=(17),command = quit)
button3.place(x="420", y ="50")
button3.pack()
class tty(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.configure(background = "white")
self.deal = tk.Label(self, text="18", font=(18))
self.deal.pack(side="top", fill="y", pady=15, padx=270)
self.score = tk.Label(self, text="19", font=(18))
self.score.pack()
f = tk.Frame(self)
button1 = tk.Button(f,borderwidth=5, text="stand", font=(18),command = self.win)#This is the button that i want to display the label
button1.grid(row=0,column=0)
button2 = tk.Button(f, text="Hit",borderwidth=5, font=(18),command = self.hit)
button2.grid(row=0,column=1)
f.pack(side="bottom")
button3 = tk.Button(self, text="Quit", font=(18))
button3.pack(side="right", pady=50)
self.randomise()
def randomise(self):
self.deal['text'] = str(randint(1,21))
self.score['text'] = str(randint(1,21))
def hit(self):
current_score = int(self.score['text'])
new_score = current_score + randint(1,21)
self.score['text'] = str(new_score)
def win(self):
if int(self.score['text']) > int(self.deal['text']):
tts = tk.Label(self, text="win", font=(20))
tts.pack()
else:
lose = tk.Label(self, text="lose", font=(10))
lose.pack() #The if statement
if __name__ == "__main__":
app = WINDOW()
app.geometry("800x400")
app.mainloop()

the tkinter widgets in my classes are not displaying

I'm trying to write a code that contains multiple pages and can be switched to when a button is clicked on. it worked initially but my widgets are not displaying, and there is neither a warning or an error message. Secondly, what is the difference between using tk and tk.TK?
from tkinter import *
import tkinter as tk
class moreTab(tk.Tk):
def __init__(self):
Tk.__init__(self)
self.geometry("1200x600")
container = Frame(self, bg='#c9e3c1')
container.pack(side = "top", fill = 'both', expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for q in (pageone, widget):
frame = q(container,self)
self.frames[q] = frame
frame.place(x= 0,y = 0)
self.raise_frame(pageone)
def raise_frame(self,cont):
frame = self.frames[cont]
frame.tkraise()
class widget(Frame):
def __init__(self, master, control):
Frame.__init__(self, master)
lab = tk.Label(self, text="main page")
lab.place(x = 10, y = 40)
but = tk.Button(self, text='visit start page', command=lambda:
control.raise_frame(pageone))
but.place(x = 10, y = 70)
class pageone(Frame):
def __init__(self, master, control):
Frame.__init__(self,master)
lab = Label(self, text = 'welcome to Game Analysis')
lab.place(x = 10, y = 10)
but = Button(self, text = "Start", command = lambda:
control.raise_frame(widget))
but.place(x = 10, y = 20)
app = moreTab()
app.mainloop()
It turns the issue was that you were using place(). Use the grid geometry manager. Using both import tkinter as tk and from tkinter import * is meaningless. Use one and be consistent. If you use the latter, you have everything available, hence you will write, say Button(...). But if you use the former, you will have to refer each widget like tk.Button(...).
import tkinter as tk
class moreTab(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.geometry("1200x600")
container = tk.Frame(self, bg='#c9e3c1')
container.pack(side = "top", fill = 'both', expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for q in (pageone, widget):
frame = q(container, self)
self.frames[q] = frame
frame.grid(row=0, column=0, sticky='nsew')
self.raise_frame(pageone)
def raise_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class widget(tk.Frame):
def __init__(self, master, control):
tk.Frame.__init__(self, master)
lab = tk.Label(self, text="main page")
lab.grid(row=0, column=0, padx=10, pady=10)
but = tk.Button(self, text='visit start page', command=lambda: control.raise_frame(pageone))
but.grid(row=1, column=0, padx=10, pady=10)
class pageone(tk.Frame):
def __init__(self, master, control):
tk.Frame.__init__(self, master)
lab = tk.Label(self, text = 'welcome to Game Analysis')
lab.grid(row=0, column=0, padx=10, pady=10)
but = tk.Button(self, text = "Start", command = lambda: control.raise_frame(widget))
but.grid(row=1, column=0, padx=10, pady=10)
app = moreTab()
app.mainloop()

Notebook with Multiple Frames

I am trying to make a tkinter widow with multiple frames, but also the functions of notebook, like multiple widows. The problem is I am kind of unfamiliar with tkinter and am not sure how to do that. This is my current code, and it doesn't work, and would love to know what I should do to make it work. Again, the dream end result would be that I would have a first widow, which says the test text, and then the 2nd window which has multiple tabs.
from tkinter import ttk
import tkinter as tk
Font= ("Verdana", 8)
LargeFont = ("Verdana", 12)
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="Info", font=LargeFont)
label.pack(pady=2,padx=10)
text = tk.Label(self, text="testtestestetetqwegfegeg\ntestwegwegwegweg", font=Font)
text.pack(pady=2,padx=2)
button = tk.Button(self, text="Go to the Card",
command=lambda: controller.show_frame(PageOne))
button.pack(fill="x")
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
nb = ttk.Notebook(ttk.Frame())
nb.grid(row=1, column=0, columnspan = 50, rowspan=49, sticky='nesw')
p1 = (nb)
nb.add(p1, text='test')
label = tk.Label(self, text="", font=LargeFont)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
app = App()
app.mainloop()
The error that I eventually get is that it creates a third frame that is displayed with the test tab. Everything else works.
Thanks for your help
I know exactly what you mean because I'm trying the same. To me
nb = ttk.Notebook(self)
worked.
best
Pkanda
Taubate Brazil

Categories

Resources