Layout changes using Tkinter - python

I am trying to make a full screen app for my Raspberry Pi. I got the code working to a degree. All I want to do now is split the top red section into 3 parts which I can put labels in containing data that will frequently change.
#!/usr/bin/python
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Learning Number Bonds!")
test = StringVar(value="XX + XX = XXX")
score = StringVar(value="0")
question = StringVar(value="7/10")
time = StringVar(value="8s")
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (w, h))
topFrame = Frame(root, bg="red", width=w, height=h/4)
##Label(topFrame, text="test").grid(row=1, column=1)
topFrame.pack()
bottomFrame = Frame(root, bg="blue", width=w, height= h-(h/4))
bottomFrame.pack()
equation = Label(bottomFrame, textvariable=test, font=("Arial", 70))
equation.pack(fill=X)
root.mainloop()
This is what I have, and the bottom how I want
But when I add the commented line it looks like this:
[It all breaks - Removed]
How can I get 3 equal size boxes at the top with labels in them?!
EDIT:
I must have just been too tired and stupid to think about this and got caught up in the fact the boxes "HAD" to be the same size. After a few minutes of code changes from the original above, I ended up with:
#!/usr/bin/python
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Learning Number Bonds!")
test = StringVar(value="XX + XX = XXX")
score = StringVar(value=999)
question = StringVar(value="10/10")
time = StringVar(value="10")
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (w, h))
topFrame = Frame(root, bg="red", width=w, height=h/4)
##Score
scoreTextLabel = Label(topFrame, text="Score: ", font=("Arial", 30))
scoreTextLabel.pack(side=LEFT)
Label2 = Label(topFrame, textvariable=score, font=("Arial", 30))
Label2.pack(side=LEFT, padx=(0,50))
##Question
qTextLabel = Label(topFrame, text="Question: ", font=("Arial", 30))
qTextLabel.pack(side=LEFT)
TextLabel2 = Label(topFrame, textvariable=question, font=("Arial", 30))
TextLabel2.pack(side=LEFT, padx=(0,50))
##Time
tTextLabel = Label(topFrame, text="Time: ", font=("Arial", 30))
tTextLabel.pack(side=LEFT)
TextLabel3 = Label(topFrame, textvariable=time, font=("Arial", 30))
TextLabel3.pack(side=LEFT, padx=(0,50))
topFrame.pack(pady=(0,120))
bottomFrame = Frame(root, bg="blue", width=w, height= h-(h/4))
bottomFrame.pack()
equation = Label(bottomFrame, textvariable=test, font=("Arial", 70))
equation.pack(fill=X)
root.mainloop()
Which looks like this
Thanks for all the help!

This shows how to configure the top row so it shows, and uses sticky to stretch the frame so it occupies the entire space, and uses a set width for the Label as well. You might also want to increase the font size of the label if you want the type to be larger.
root = Tk()
root.title("Learning Number Bonds!")
test = StringVar(value="XX + XX = XXX")
score = StringVar(value="0")
question = StringVar(value="7/10")
time = StringVar(value="8s")
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.geometry("%dx%d+0+0" % (w, h))
topFrame = Frame(root, bg="red", width=w, height=h/4)
## put an empty row on top
topFrame.rowconfigure(0, weight=1, minsize=100)
Label(topFrame, text="test", bg="lightblue", width=50).grid(row=1, column=1)
topFrame.grid(sticky="nsew")
bottomFrame = Frame(root, bg="blue", width=w, height= h-(h/4))
bottomFrame.grid(row=1)
equation = Label(bottomFrame, textvariable=test, font=("Arial", 70))
equation.pack(fill=X)
root.mainloop()

Related

How to align the LabelFrames to left on tkinter?

I am new to tkinter and learning to organize the frames in tkinter.
In the following code, I have created 3 label frames.
The frames are not aligned as per my requirements and I would like to get help organizing them cleanly.
Required
===========
By default it gives me following layout
LabelFrame1 LabelFrame2
LabelFrame3
I would like to have left aligned label frames like this:
LabelFrame1 LabelFrame2
LabelFrame3
How to align all label frames to left so that I can have spaces in right?
MWE
# %%writefile a.py
import tkinter as tk
from tkinter import ttk,messagebox
# variables
padding = dict(padx=20,pady=20)
padding_widget = dict(padx=10,pady=5)
# root app
win = tk.Tk()
w,h = 800, 600 # app
ws, hs = win.winfo_screenwidth(), win.winfo_screenheight() # screen
x,y = -10,hs*0.1
win.geometry('%dx%d+%d+%d' % (w, h, x, y))
#===================== end of Snippets =====================================
# Frame contains labelframes
f = tk.Frame(win,height=200, width=200)
f.grid(row=0,column=0,padx=20, pady=20)
f.pack(fill="both", expand="yes")
#=============================================================================
# label frame: Find and Replace
lf00 = tk.LabelFrame(f,text='Find and Replace from Clipboard')
lf00.grid(row=0,column=0,padx=20, pady=20)
b = tk.Button(lf00,text='Click to Replace')
b.grid(row=2,column=0,sticky='news',**padding)
#=============================================================================
# label frame: Text Manipulation
lf01 = tk.LabelFrame(f,text='Text Manipulation')
lf01.grid(row=0,column=1,padx=20, pady=20)
b = tk.Button(lf01,text='Click to Replace')
b.grid(row=2,column=0,sticky='news',**padding)
#=============================================================================
# LabelFrame: Calculator
lf10 = tk.LabelFrame(f,text='Calculator')
lf10.grid(row=1,column=0,padx=10, pady=10)
l_exp = tk.Label(lf10,text="Expression")
t_i = tk.Text(lf10, height=2, width=70, bg="light yellow", padx=0,pady=0)
t_o = tk.Text(lf10, height=4, width=40, bg="light cyan",padx=0,pady=0)
b_calc = tk.Button(lf10,height=1,width=10,text="Calculate")
l_exp.pack();t_i.pack();b_calc.pack();t_o.pack()
# Main window
win.config()
win.mainloop()
Update
# %%writefile a.py
import tkinter as tk
from tkinter import ttk,messagebox
# variables
padding = dict(padx=20,pady=20)
padding_widget = dict(padx=10,pady=5)
# root app
win = tk.Tk()
w,h = 800, 600 # app
ws, hs = win.winfo_screenwidth(), win.winfo_screenheight() # screen
x,y = -10,hs*0.1
win.geometry('%dx%d+%d+%d' % (w, h, x, y))
#===================== end of Snippets =====================================
# Frame contains labelframes
f = tk.Frame(win,height=200, width=200)
f.grid(row=0,column=0,padx=20, pady=20,sticky="w")
f.pack(fill="both", expand="yes")
#=============================================================================
# label frame: Find and Replace
lf00 = tk.LabelFrame(f,text='Find and Replace from Clipboard')
lf00.grid(row=0,column=0,padx=20, pady=20,sticky="w")
b = tk.Button(lf00,text='Click to Replace')
b.grid(row=2,column=0,sticky='w',**padding)
#=============================================================================
# label frame: Text Manipulation
lf01 = tk.LabelFrame(f,text='Text Manipulation')
lf01.grid(row=0,column=1,padx=20, pady=20,sticky="w")
b = tk.Button(lf01,text='Click to Replace')
b.grid(row=2,column=0,sticky='w',**padding)
#=============================================================================
# LabelFrame: Calculator
lf10 = tk.LabelFrame(f,text='Calculator')
lf10.grid(row=1,column=0,padx=10, pady=10,sticky="w")
l_exp = tk.Label(lf10,text="Expression")
t_i = tk.Text(lf10, height=2, width=70, bg="light yellow", padx=0,pady=0)
t_o = tk.Text(lf10, height=4, width=40, bg="light cyan",padx=0,pady=0)
b_calc = tk.Button(lf10,height=1,width=10,text="Calculate")
l_exp.pack();t_i.pack();b_calc.pack();t_o.pack()
# Main window
win.config()
win.mainloop()
For greater clarity, first draw on a piece of paper what you want to place in the window. Like this:
And you will see that you need to stretch tk.LabelFrame(f, text='Calculator') over several cells ( columnspan=3).
import tkinter as tk
from tkinter import ttk, messagebox
# variables
padding = dict(padx=20, pady=20)
padding_widget = dict(padx=10, pady=5)
# root app
win = tk.Tk()
w, h = 800, 600 # app
ws, hs = win.winfo_screenwidth(), win.winfo_screenheight() # screen
x, y = -10, hs * 0.1
win.geometry('%dx%d+%d+%d' % (w, h, x, y))
# ===================== end of Snippets =====================================
# Frame contains labelframes
f = tk.Frame(win, height=200, width=200)
f.grid(row=0, column=0, padx=20, pady=20)
f.pack(fill="both", expand="yes")
f.columnconfigure(1, weight=1)
# =============================================================================
# label frame: Find and Replace
lf00 = tk.LabelFrame(f, text='Find and Replace from Clipboard')
lf00.grid(row=0, column=0, padx=(20, 2), pady=20, sticky='e')
b = tk.Button(lf00, text='Click to Replace')
b.grid(row=0, column=0, sticky='nswe', **padding)
# =============================================================================
# label frame: Text Manipulation
lf01 = tk.LabelFrame(f, text='Text Manipulation')
lf01.grid(row=0, column=1, padx=2, pady=20, sticky='w')
b = tk.Button(lf01, text='Click to Replace')
b.grid(row=0, column=0, sticky='nswe', **padding)
# =============================================================================
# LabelFrame: Calculator
lf10 = tk.LabelFrame(f, text='Calculator')
lf10.grid(row=1, column=0, columnspan=3, padx=20, pady=20, sticky='w')
l_exp = tk.Label(lf10, text="Expression")
t_i = tk.Text(lf10, height=2, width=70, bg="light yellow", padx=0, pady=0)
t_o = tk.Text(lf10, height=4, width=40, bg="light cyan", padx=0, pady=0)
b_calc = tk.Button(lf10, height=1, width=10, text="Calculate")
l_exp.pack()
t_i.pack()
b_calc.pack()
t_o.pack()
# Main window
win.config()
win.mainloop()

Click to open a new canvas panel with an image- tkinter

Hi I want to click on a picture in the canvas in order to open a new canvas in which there is another picture and for some reason the new canvas opens and the picture does not appear anyone might know how to fix this?
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
root.title("root")
root.geometry('800x550')
canvas = Canvas(root,
bg='white',
bd=5,
relief='groove',
height=500,
width=700,
)
canvas.place(x=80, y=0)
def press_to_open(event):
x, y = event.x, event.y
print('{}, {}'.format(x, y))
new_img = Image.open("images/back_p.png")
w, h = new_img.size
if x >= 3 and x <= 3 + w and y >= 3 and y <= 3 + h:
canvas2 = Canvas(canvas,
bg='white',
bd=2,
relief='groove',
height=120,
width=250,
)
canvas2.place(x=100, y=90)
resize_text = Label(canvas2, text="Resize the image:", bg="white", font=('Bodoni MT',
12))
resize_text.place(x=65, y=10)
img = PhotoImage("images/x.png")
x_button = Button(canvas2, command=canvas2.destroy, bd=0, image=img)
x_button.pack()
canvas2.create_window(10, 10, window=x_button, height=65, width=65)
def destroy_window(event):
global new_label
new_label.destroy()
color_img = ImageTk.PhotoImage(Image.open("images/back_p.png"))
label = Label(canvas, image=color_img)
label.place(x=10, y=10)
root.bind('<Button-1>', press_to_open)
root.bind('<Button-3>', destroy_window)
root.mainloop()

tkinter insert widget in a frame

I am trying to make the following layout
tkinter layout
but the ID: label and the entry box are center left , and center right when then they should be next to each other , and they keep getting separated by the grid
I am also trying to use a for loop to make the number pad but im not sure how to make a new variable outside of the loops, and increment by 1 in the loop that creates the button
from tkinter import *
window = Tk()
#BOTTOM FRAME SECTION
bottomframe = Frame(window,bg="cyan", width =900, height = 100)
bottomframe.pack(fill=BOTH,side=BOTTOM)
button = Button(window,text="LOG IN")
button.pack(fill=BOTH,side=BOTTOM)
checkbutton = Checkbutton(window, text="Use pseudonym?")
checkbutton.pack(side=BOTTOM)
topframe = Frame(window,bg="red",width =900, height = 100)
topframe.pack(fill=BOTH,side=TOP)
label1 = Label(window, text="Majestic 12 Identifier")
label1.pack(side=TOP)
label2 = Label(window, text="ID")
label2.pack(side=LEFT)
label3 = Label(window,text="Enter keycode:")
label3.pack(side=TOP)
entry1 = Entry(window)
entry1.pack(side=LEFT)
#GRID SECTION
frame = Frame(window)
frame.pack(fill=BOTH,side=BOTTOM)
n = +1
for i in range(3):
Grid.rowconfigure(frame,i,weight=1)
Grid.columnconfigure(frame,i,weight=1)
for i in range(3):
b = Button(frame, text="%d" % (i+n))
for j in range(3):
b = Button(frame, text="%d" % (j+1))
b.grid(row=i, column=j,ipadx=2,ipady=2,padx=2,pady=2,sticky= W+E+N+S)
window.mainloop()
any help is welcome
Ok, I gave it a try. I played around a bit with the Frame objects. I deleted one, that was not needed. And I introduced topframe2 in order to make it possible for label2 and entry1 to be in the same row.
Watch carefully the parent of the various entries and labels. Not everything should get the window object as direct parent.
I am using expand and fill arguments - here I am basically applying what I just learned at Textbox not expanding with containing frame - TKinter and tkinter gui layout using frames and grid
from tkinter import *
window = Tk()
# BOTTOM FRAME SECTION
topframe = Frame(window, width=900, height=100)
topframe.pack(fill=BOTH, side=TOP)
label1 = Label(topframe, text="Majestic 12 Identifier")
label1.pack(side=TOP, fill=BOTH, expand=1)
topframe2 = Frame(topframe, width=900, height=100)
topframe2.pack(fill=BOTH, side=TOP)
label2 = Label(topframe2, text="ID")
label2.pack(side=LEFT)
entry1 = Entry(topframe2)
entry1.pack(side=LEFT, fill=X, expand=1)
label3 = Label(window, text="Enter keycode:")
label3.pack(side=TOP)
# GRID SECTION
frame = Frame(window)
frame.pack(fill=BOTH, side=TOP, expand=1)
n = +1
for i in range(3):
Grid.rowconfigure(frame, i, weight=1)
Grid.columnconfigure(frame, i, weight=1)
for i in range(3):
b = Button(frame, text="%d" % (i + n))
for j in range(3):
b = Button(frame, text="%d" % (j + 1))
b.grid(row=i, column=j, ipadx=2, ipady=2, padx=2, pady=2, sticky=W + E + N + S)
button = Button(window, text="LOG IN")
button.pack(fill=BOTH, side=BOTTOM)
checkbutton = Checkbutton(window, text="Use pseudonym?")
checkbutton.pack(side=BOTTOM)
if __name__ == '__main__':
window.mainloop()

Python Tkinter frame newby geometry problem?

I am very new in tkinter and python. Thats how my code looks:
import tkinter as tk
main = tk.Tk()
# Window size
main.geometry("400x700")
main.resizable(0, 0)
# Window position
w = main.winfo_reqwidth()
h = main.winfo_reqheight()
ws = main.winfo_screenwidth()
hs = main.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
main.geometry('+%d+%d' % (x, y))
fr1 = tk.Frame(main, borderwidth=2, relief="solid", bg = "#271ee3", width=400, height=50)
fr2 = tk.Frame(main, borderwidth=2, relief="solid", bg = "#0d9467", width=200, height=650)
fr3 = tk.Frame(main, borderwidth=2, relief="solid", bg = "#3e1854", width=200, height=650)
fr1.pack()
fr2.pack(side="left")
fr3.pack(side="right")
main.mainloop()
With this code I get the
following window
So far so good. The problem comes when i add this code:
# Label
l = tk.Label(fr2, text="Heyho")
l.grid(row=0, column=0)
Now it looks so
My goal is to get a window where i have in the first frame (fr1) a button that has the same geometry like fr1. In fr2 und fr3 I want to have severel labels among each other. My labels in fr2 und fr3 should have column 0 but ascending rows (0,1,2,3...). How can I do it??
It automatically resize Frame to Label's size so you don't see green background which is hidden behind label - and you see main window's gray background.
You can see it better if you add other longer label and red background in main window
If you add
fr2.grid_propagate(False)
then frame will keep its size
but you still have problem with grid which doesn't use full size of Frame and you can't center it or align to right.
If you add
fr2.grid_columnconfigure(0, weight=1)
then column 0 will try to use full size if there is no other columns, and label will be centered in cell
If you use
sticky='we'
in grid() for labels then they will fill cell
import tkinter as tk
main = tk.Tk()
# Window size
main.geometry("400x200")
main.resizable(0, 0)
main['bg'] = 'red'
# Window position
w = main.winfo_reqwidth()
h = main.winfo_reqheight()
ws = main.winfo_screenwidth()
hs = main.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
main.geometry('+%d+%d' % (x, y))
fr1 = tk.Frame(main, borderwidth=2, relief="solid", bg = "#271ee3", width=400, height=50)
fr2 = tk.Frame(main, borderwidth=2, relief="solid", bg = "#0d9467", width=200, height=650)
fr3 = tk.Frame(main, borderwidth=2, relief="solid", bg = "#3e1854", width=200, height=650)
fr1.pack()
fr2.pack(side="left")
fr3.pack(side="right")
fr2.grid_propagate(False)
fr2.grid_columnconfigure(0, weight=1)
l1 = tk.Label(fr2, text="Heyho")
l1.grid(row=0, column=0, sticky='we')
l2 = tk.Label(fr2, text="Hello World")
l2.grid(row=1, column=0, sticky='we')
main.mainloop()

Centering window python tkinter

Ive recently started using tkinter in python, and I was having trouble centering the window. I tried all the tips on this website, but whenever I try them, the window is like a line in the middle of the screen. I have widgets already on it, and it works fine without the centering, but I would really appreciate it if someone could help me solve my problem.
This is what I have been trying so far.
root = Tk()
root.title("Password")
root.resizable(FALSE,FALSE)
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
mainframe.columnconfigure(0, weight=1)
mainframe.rowconfigure(0, weight=1)
w = mainframe.winfo_width()
h = mainframe.winfo_height()
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
You need to use winfo_reqwidth() and winfo_reqheight(), because the window does not have a height or width at the time that you call winfo_height() and winfo_width().
An example program:
from tkinter import Tk
from tkinter import ttk
root = Tk()
style = ttk.Style()
style.configure("BW.TLabel", foreground="black", background="white")
l1 = ttk.Label(text="This is the best label in the world", style="BW.TLabel")
l1.pack()
w = l1.winfo_reqwidth()
h = l1.winfo_reqheight()
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
print(w, h, x, y)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
root.mainloop()
Ok I have found and fixed the problem. Piggybacking off of OregonTrail's solution, i found that if the window is the right size and you just want to change the location, then you can easily instead of setting the root's size, you can just move the window to the center.
w = root.winfo_reqwidth()
h = root.winfo_reqheight()
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('+%d+%d' % (x, y)) ## this part allows you to only change the location
I think that this answer isn't exactly in the center, probably off by a little since h was returning 200 when it should be less, but it looks to be at the center and works fine.
Hopefully someone will find use of this code, basically this is a solution you can use to center a TopLevel window relative to master (parent) window.
Probably not the cleanest solution, but it will get the work done.
from Tkinter import *
class PasswordDialog(Toplevel):
def __init__(self, master=None):
Toplevel.__init__(self, master)
self.master = master
self.title("Password")
self.label_info = Label(self, text="You need to enter your password", pady=10)
self.label_info.grid(row=0, column=0, columnspan=2, padx=20, pady=10, sticky="ew")
self.label_pw = Label(self, text="Enter password:", pady=10)
self.label_pw.grid(row=1, column=0, padx=(20, 2), sticky="e")
self.entry = Entry(self, show="*")
self.entry.bind("<KeyRelease-Return>", self.store_pass_event)
self.entry.grid(row=1, column=1, padx=(2,20), sticky="w")
self.button = Button(self, command=self.store_pass, text="Log in")
self.button.grid(row=2, column=0, columnspan=2, pady=10)
self.update()
size = tuple(int(_) for _ in self.geometry().split('+')[0].split('x'))
parent_offset = tuple(int(_) for _ in self.master.geometry().split('x')[1].split('+'))
parent_width = self.master.winfo_width()
parent_height = self.master.winfo_height()
x = parent_width//2 - size[0]//2 + parent_offset[1]
y = parent_height//2 - size[1]//2 + parent_offset[2]
self.geometry("+%d+%d" % (x, y))
def store_pass_event(self, event):
self.store_pass()
def store_pass(self):
self.master.password = self.entry.get()
self.destroy()

Categories