I can't properly layout buttons within frame nested in tkk.Notebook
In Main.py I create ttk.Notebook and attach mainTab instance
root = tk.Tk()
rootFrame = tk.Frame(root, width=600, height=300)
rootFrame.grid(columnspan=1, rowspan=2)
rootFrame.pack(expand=1, fill="both")
tabs = ttk.Notebook(rootFrame)
tabs.grid(column=0, row=1, columnspan=1, rowspan=1)
mainTab = ttk.Frame(tabs)
mainTab.grid(columnspan=3, rowspan=6)
tabs.add(mainTab, text="Main")
rootFrame.pack(expand=1, fill="both")
mainPane = MainTab(root,mainTab)
root.mainloop()
in mainTab.py I'm trying to insert buttonFrame and layout two buttons within it
class MainTab:
...
def __init__(self, root, mainTab) -> None:
self.root = root
buttonFrame = tk.Frame(mainTab, bg="white")
buttonFrame.grid(column=0, row=4, columnspan=3, rowspan=1)
self.start_btn = tk.Button(buttonFrame, text="Start", command=lambda:self.start_timer(), font=BUTTON_FONT, bg="green", fg="white") # , height=1, width=14
self.start_btn.grid(column=0, row=0, columnspan=2)
self.reset_btn = tk.Button(buttonFrame, text="X", command=lambda:self.reset_timer(), font=BUTTON_FONT, bg="green", fg="white") # , height=1, width=1
self.reset_btn.grid(column=2, row=0)
...
As a result start button is not properly placed in the grid
It looks like buttonFrame takes full parent frame width and buttons placed in the middle regardless of their grid settings.
How I can properly layout buttons within buttonFrame?
Here is the requested "minimal reproducible example" which also look not good
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Time Tracker")
root.iconbitmap('./assets/logoTransp4icon24.ico')
rootFrame = tk.Frame(root, width=600, height=300)
rootFrame.grid(columnspan=1, rowspan=2)
rootFrame.pack(expand=1, fill="both")
tabs = ttk.Notebook(rootFrame)
tabs.grid(column=0, row=1, columnspan=1, rowspan=1)
mainTab = ttk.Frame(tabs)
mainTab.grid(columnspan=3, rowspan=6)
buttonFrame = tk.Frame(mainTab, bg="white")
buttonFrame.grid(column=0, row=4, columnspan=3, rowspan=1)
start_btn = tk.Button(buttonFrame, text="Start", command=lambda:self.start_timer(), font="Arial", bg="green", fg="white") # , height=1, width=14
start_btn.grid(column=0, row=0, columnspan=2)
reset_btn = tk.Button(buttonFrame, text="X", command=lambda:self.reset_timer(), font="Arial", bg="green", fg="white") # , height=1, width=1
reset_btn.grid(column=2, row=0)
timerDisplay = tk.Label(mainTab, text="00:00:00", font="Arial")
timerDisplay.grid(columnspan=2, column=1, row=4)
tabs.add(mainTab, text="Main")
rootFrame.pack(expand=1, fill="both")
root.mainloop()
buttonFrame occupies column 0 to 2 and timerDisplay occupies column 1 to 2. So timerDisplay overlaps buttonFrame. Removing columnspan=3 in buttonFrame.grid(...) can fix the overlapping issue:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Time Tracker")
root.iconbitmap('./assets/logoTransp4icon24.ico')
rootFrame = tk.Frame(root, width=600, height=300)
#rootFrame.grid(columnspan=1, rowspan=2) # override by below line
rootFrame.pack(expand=1, fill="both")
tabs = ttk.Notebook(rootFrame)
tabs.grid(column=0, row=1, rowspan=1)
mainTab = ttk.Frame(tabs)
#mainTab.grid(columnspan=3, rowspan=6) # not necessary
buttonFrame = tk.Frame(mainTab, bg="white")
buttonFrame.grid(column=0, row=4, rowspan=1) # removed columnspan=3
start_btn = tk.Button(buttonFrame, text="Start", command=lambda:self.start_timer(), font="Arial", bg="green", fg="white") # , height=1, width=14
start_btn.grid(column=0, row=0, columnspan=2)
reset_btn = tk.Button(buttonFrame, text="X", command=lambda:self.reset_timer(), font="Arial", bg="green", fg="white") # , height=1, width=1
reset_btn.grid(column=2, row=0)
timerDisplay = tk.Label(mainTab, text="00:00:00", font="Arial")
timerDisplay.grid(columnspan=2, column=1, row=4)
tabs.add(mainTab, text="Main")
#rootFrame.pack(expand=1, fill="both") # already called above
root.mainloop()
Related
Python TKinter Mac: Buttons layout strangely and when a button is clicked it looks the same (as if it hadn't been clicked) however I didn't check to see if the button worked.
and the space is a textbook
the Mac version is: a 2017 iMac running Monterey 12.4
import tkinter as tk
window = tk.Tk()
window.geometry("500x500")
window.title("Stock Watchlist & Logger")
label = tk.Label(window, text="Tester", font=('Ariel', 18))
label.pack(padx=20, pady=20)
textbox = tk.Text(window, height=3, font=('Ariel', 16))
textbox.pack(padx=10, pady=10)
numbuttframe = tk.Frame(window)
numbuttframe.columnconfigure(0, weight=1)
yesnobuttframe = tk.Frame(window)
yesnobuttframe.columnconfigure(1, weight=1)
button1 = tk.Button(numbuttframe, text="1", font=('Arial', 18))
button1.grid(row=0, column=0, sticky=tk.W+tk.E)
button2 = tk.Button(numbuttframe, text="2", font=('Arial', 18))
button2.grid(row=0, column=1, sticky=tk.W+tk.E)
button3 = tk.Button(numbuttframe, text="3", font=('Arial', 18))
button3.grid(row=0, column=2, sticky=tk.W+tk.E)
button4 = tk.Button(numbuttframe, text="4", font=('Arial', 18))
button4.grid(row=0, column=3, sticky=tk.W+tk.E)
button5 = tk.Button(numbuttframe, text="5", font=('Arial', 18))
button5.grid(row=0, column=4, sticky=tk.W+tk.E)
button6 = tk.Button(numbuttframe, text="6", font=('Arial', 18))
button6.grid(row=0, column=5, sticky=tk.W+tk.E)
yesbutton = tk.Button(yesnobuttframe, text="Yes", font=('Arial', 18))
yesbutton.grid(row=0, column=0, sticky=tk.W+tk.E)
nobutton = tk.Button(yesnobuttframe, text="No", font=('Arial', 18))
nobutton.grid(row=0, column=1, sticky=tk.W+tk.E)
numbuttframe.pack(fill='x')
yesnobuttframe.pack(fill='x')
if button1:
print("CELEBRATE!")
window.mainloop()
You set the weight to two cells weight=1 , so they expanded, since the rest have a default weight of 0. Since I don’t see your grid - the buttons are placed in frames one after the other, suggest using the pack method. And shortened your code a bit. The buttons won't work yet, because they don't have a command = call. Complex variable names in Python are usually written with an underscore.
import tkinter as tk
FONT = ('Ariel', 18)
window = tk.Tk()
window.geometry("500x500")
window.title("Stock Watchlist & Logger")
lbl = tk.Label(window, text="Tester", font=FONT)
lbl.pack(padx=20, pady=20)
text_box = tk.Text(window, height=3, font=('Ariel', 16))
text_box.pack(padx=10, pady=10)
num_btn = tk.Frame(window)
yes_no_btn = tk.Frame(window)
num_btn.pack(fill='x')
yes_no_btn.pack(fill='x')
buttons = []
for i in range(1, 7):
btn = tk.Button(num_btn, text=f"{i}", font=FONT)
btn.pack(side="left", fill='x', expand=True)
buttons.append(btn)
yes_btn = tk.Button(yes_no_btn, text="Yes", font=FONT)
yes_btn.pack(side="left", fill='x', expand=True)
no_btn = tk.Button(yes_no_btn, text="No", font=FONT)
no_btn.pack(side="left", fill='x', expand=True)
window.mainloop()
The purpose is to pull a word from the list randomly and display it on the screen in the GUI. The words are displayed in the terminal when I click the button "dammi" but I cannot get them to display in the GUI. I have tried both an Entry and Label with no success.
from tkinter import *
import random
# Window
root = Tk()
root.geometry("400x350")
root.title("Passato Remoto")
root.configure(bg="#000000")
root.resizable(False, False)
# Find Verb
verbi = ['Dare', 'Dire', 'Fare', 'Sapere', 'Prendere']
# Dammi Button
def give():
print(random.choice(verbi))
# Create Buttons
dammi = Button(root, text='Dammi un verbo',
bg='#ffffff',
fg='#000000',
borderwidth=0,
highlightthickness=0,
font=('Helvetica', 16),
height=2,
width=10,
command=give)
dammi.grid(column=0, row=2, pady=50, padx=25)
con = Button(root, text='Coniugazione',
bg='#ffffff',
fg='#000000',
borderwidth=0,
highlightthickness=0,
font=('Helvetica', 16),
height=2,
width=10)
con.grid(column=2, row=2, pady=50, padx=25)
# Put Verb On Screen
verb = Entry(root, text=give(), font=('Helvetica', 40), width=10, bg="#ffffff", fg="#000000")
verb.grid(column=0, columnspan=3, row=1, pady=50, padx=80)
root.mainloop()
The easiest way is probably to use a StringVar. I've added this into the question code.
from tkinter import *
import random
root = Tk()
root.geometry("400x350")
root.title("Passato Remoto")
root.configure(bg="#000000")
root.resizable(False, False)
# Find Verb
verbi = ['Dare', 'Dire', 'Fare', 'Sapere', 'Prendere']
# Dammi Button
sample = StringVar() # Added
def give(): # Changed
sample.set( random.choice(verbi) )
print( sample.get() )
# Create Buttons
dammi = Button(root, text='Dammi un verbo',
bg='#ffffff',
fg='#000000',
borderwidth=0,
highlightthickness=0,
font=('Helvetica', 16),
height=2,
width=10,
command=give)
dammi.grid(column=0, row=2, pady=50, padx=25)
con = Button(root, text='Coniugazione',
bg='#ffffff',
fg='#000000',
borderwidth=0,
highlightthickness=0,
font=('Helvetica', 16),
height=2,
width=10)
con.grid(column=2, row=2, pady=50, padx=25)
# Put Verb On Screen
# changed here
verb = Label(root, font=('Helvetica', 40), textvariable = sample, width=10, bg="#ffffff", fg="#000000")
verb.grid(column=0, columnspan=3, row=1, pady=50, padx=80)
give()
root.mainloop()
Since some days I'll try to align these two items inside a Tkinter frame:
The pink part should be on the left and the green button on the right. With HtmlDivs and CSS a question of seconds, with TKinter a pain in the ...
Here is my python code:
import tkinter as tk
root = tk.Tk()
root.geometry("400x200")
buttons = tk.Frame(root)
buttons.pack(side="top", expand=True, fill='both')
label = tk.Label(buttons, text="Hello, world", anchor='w', background='pink')
b2 = tk.Button(buttons, text="EXIT", background='green')
label.grid(row=0, column=1, sticky='w', ipadx = '20', padx = '20')
b2.grid(row=0, column=3, sticky='e', ipadx = '20', padx = '20')
root.mainloop()
The final app will be running fullscreen on a 7" touch display.
The simplest solution is to use pack instead of grid, since you only have a single row of widgets inside of buttons. pack's strength is arranging things in a single row or a single column.
Just remove these two lines:
label.grid(row=0, column=1, sticky='w', ipadx = '20', padx = '20')
b2.grid(row=0, column=3, sticky='e', ipadx = '20', padx = '20')
... and replace them with this:
label.pack(side='left')
b2.pack(side='right')
Also, since you appear to be creating a toolbar, you want to leave expand as False and set fill to just "x", otherwise the toolbar will expand to fill the entire window:
buttons.pack(side="top", expand=False, fill='x')
Thx for your tips,
this is just a testcode to update my maincode.
Its not good to mix .pack and .grid, right ? If i do, the script crashes completely,
so ill have to re-do my mainscript i think.
This is what i need:
row: 1/2: label (it will be a real time clock) left 2/2: exit button (exit fullscreen) right
row: 1/3: image (weather), 2/3: weather data (label), 3/3: calendar
row: 4 buttons: 1. lightoff 2. light25%, 3.light50% 4.light100&
Thats it basically all is working, it just need to align it (im a coding hero g)
Since i have the frame from the code above, i thought i can easily add 2. & 3. row with another frames, but that does not seem to work ??
Preview:
https://i.stack.imgur.com/KzoqV.png
My (main)Code so far
root = Tk()
root.title('Model Definition')
root.config(background = "deepskyblue4")
root.attributes('-fullscreen',True)
root.bind('<Escape>',lambda e: root.destroy())
def currenttime():
string = strftime("%A, %d.%B.%Y %H:%M:%S")
lbl.config(text = string, background = 'deepskyblue4', fg='white', font=("colibri", 30))
lbl.after(1000, currenttime)
def light400():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 401'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
def light425():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 425'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
def light450():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 450'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
def light475():
FNULL = open(os.devnull, 'w')
subprocess.call(['gpio -g pwm 18 500'], stdout=FNULL, stderr=subprocess.STDOUT, shell=True)
# Main frames
top_frame = Frame(root, bg='deepskyblue4', width=450, height=90, pady=3)
center = Frame(root, bg='deepskyblue2', width=50, height=40, padx=3, pady=3)
btm_frame = Frame(root, bg='deepskyblue4', width=450, height=20, pady=3)
btm_frame2 = Frame(root, bg='deepskyblue4', width=450, height=60, pady=3)
# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
top_frame.grid(row=0, sticky="e", padx=(10, 0))
center.grid(row=1, sticky="nsew", pady=(10, 50))
btm_frame.grid(row=3, sticky="ew")
btm_frame2.grid(row=4, sticky="ew", padx=(10, 50))
# create the widgets for the top frame
lbl = Label(top_frame, background = 'deepskyblue4', anchor=W, justify=LEFT)
lbl.pack()
currenttime()
actionbutton = Button(top_frame, text="X", width=5, height=2, bg="deepskyblue4", fg="white", command=root.destroy)
hdr_left = Frame(top_frame, bg='deepskyblue4', width=100, height=190)
hdr_right = Frame(top_frame, bg='deepskyblue4', width=400, height=190, padx=3, pady=3)
# layout the widgets in the top frame
lbl.grid(row=0, column=1, sticky="w")
actionbutton.grid(row=0, column=2, sticky="e")
# create the center widgets
center.grid_rowconfigure(0, weight=1)
center.grid_columnconfigure(1, weight=1)
ctr_left = Frame(center, bg='deepskyblue2', width=100, height=190)
ctr_mid = Frame(center, bg='deepskyblue2', width=150, height=190, padx=3, pady=3)
ctr_right = Frame(center, bg='deepskyblue2', width=400, height=190, padx=3, pady=3)
ctr_left.grid(row=0, column=0, sticky="ns")
ctr_mid.grid(row=0, column=1, sticky="nsew")
ctr_right.grid(row=0, column=2, sticky="ns")
path = "icons/rain.png"
img = ImageTk.PhotoImage(Image.open(path))
panel = Label(ctr_left, image = img, bg="deepskyblue2")
panel.grid(row=0, columnspan=3)
#imgag = panel.pack(top_frame)
#CENTER ctr_mid
if x["cod"] != "404":
y = x["main"]
y2 = x["wind"]
currenttemp = y["temp"]
currentpressure = y["pressure"]
currenthumidiy = y["humidity"]
z = x["weather"]
weather_description = z[0]["description"]
currentwind = y2["speed"]
label1 = Label(ctr_mid,text='Karlsruhe', font = ('calibri', 30), background = 'deepskyblue2')
label2 = Label(ctr_mid,text='Temperatur: '+str(round(currenttemp-272.15))+' °C', font = ('calibri', 20), background = 'deepskyblue2')
label3 = Label(ctr_mid,text='Beschreibung: '+str(weather_description),font = ('calibri', 20), background = 'deepskyblue2')
label4 = Label(ctr_mid,text='Druck: '+str(currentpressure)+' hPa', font = ('calibri', 20), background = 'deepskyblue2')
label5 = Label(ctr_mid,text='Feuchtigkeit: '+str(currenthumidiy)+' %',font = ('calibri', 20), background = 'deepskyblue2')
label6 = Label(ctr_mid,text='Wind: '+str(currentwind)+' m/Sek',font = ('calibri', 20), background = 'deepskyblue2')
label1.grid(row=0, column=0, sticky="nw")
label2.grid(row=1, column=0, sticky="nw")
label3.grid(row=2, column=0, sticky="nw")
label4.grid(row=3, column=0, sticky="nw")
label5.grid(row=4, column=0, sticky="nw")
label6.grid(row=5, column=0, sticky="nw")
# btm_frame2 widgets
licht = Label(btm_frame2, text='Licht:', width=5, height=1, bg="deepskyblue4", fg='white', font=("colibri", 20))
button = Button(btm_frame2, command=light400, text="AUS", width=5, height=1, bg="deepskyblue2", fg="white")
button2 = Button(btm_frame2, text="25 %", command=light425, width=5, height=1, bg="deepskyblue2", fg="white")
button3 = Button(btm_frame2, text="50%", command=light450, width=5, height=1, bg="deepskyblue2", fg="white")
button4 = Button(btm_frame2, text="100%", command=light475, width=5, height=1, bg="deepskyblue2", fg="white")
licht.grid(row=0, column=0, sticky="nw")
button.grid(row=0, column=1, sticky="nw")
button2.grid(row=0, column=2, sticky="nw")
button3.grid(row=0, column=3, sticky="nw")
button4.grid(row=0, column=4, sticky="nw")
actionbutton.grid(row=0, column=6, sticky="nw")
root.mainloop()
I am trying to make a simple program using tkinter.
I was trying to change font or style of width or height.
width can be changed but when it comes to height or font - it shows mistake.
I am thinking - maybe it can be because the layout?
(The button that is changed in width is in the bottom of def initUI)
Also in case anyone can also answer this question:
I made 1 frame red because there will be error messages there but does anyone know how to make this red lie less in width?
Thank you in
from tkinter import *
from tkinter.ttk import *
class Example(Frame):
def __init__(self,master):
super().__init__()
master.minsize(width=350, height=160)
master.maxsize(width=650, height=500)
self.initUI()
def initUI(self):
self.master.title("Hank (version 3)")
self.pack(fill=BOTH, expand=True)
frame1 = Frame(self)
frame1.pack(fill=X)
#dataset
lbl1 = Label(frame1, text="Dataset file_name", width=18)
lbl1.pack(side=LEFT, padx=5, pady=5)
entryDataset= Entry(frame1)
entryDataset.pack(fill=X, padx=5, expand=True)
#row col begin
frame2 = Frame(self)
frame2.pack(fill=X)
lblRow = Label(frame2, text="Row", width=6)
lblRow.pack(side=LEFT, padx=5, pady=5)
entryRow = Entry(frame2, width=5)
entryRow.pack(side=LEFT, padx=0, expand=True)
lblCol = Label(frame2, text="Column", width=7.5)
lblCol.pack(side=LEFT, padx=5, pady=5)
entryCol = Entry(frame2, width=5)
entryCol.pack(side=LEFT, padx=5, expand=True)
lblBegin = Label(frame2, text="Start at", width=6)
lblBegin.pack(side=LEFT, padx=5, pady=5)
entryBegin = Entry(frame2, width=5)
entryBegin.pack(side=LEFT, padx=0, expand=True)
#console window
s = Style()
s.configure('My.TFrame', background='grey')
frame3 = Frame(self, style='My.TFrame')
frame3.pack(fill=BOTH, expand=True)
#button start and help
s = Style()
s.configure('My.ConsoleFrame', background='red')
frame4 = Frame(self)
frame4.pack(fill=BOTH, expand=True)
startbutton = Button(frame4, text="Start Clustering", height="100", width="100")
startbutton.pack(side=RIGHT, padx=5, pady=5)
def main():
root = Tk()
root.geometry("300x160+300+160")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
This is one of the prime examples of why global imports are bad.
You write at the top:
from tkinter import *
from tkinter.ttk import *
This means that you import everything from tkinter and tkinter.ttk into your main.py namespace. Then you write for example:
frame3 = Frame(self, bg="grey")
....
lblCol = Label(frame2, text="Column", width=7)
These are Frame/Label objects, but which ones? The one in tkinter or the one in tkinter.ttk? If it is the first, you will have to set the height with -height, else you will have to use tkinter.ttk.Style(). Same with the -bg for the frame.
Solution:
import tkinter as tk
class Example(tk.Frame):
def __init__(self,master):
super().__init__()
master.minsize(width=350, height=160)
master.maxsize(width=650, height=500)
self.initUI()
def initUI(self):
self.master.title("Hank (version 3)")
self.pack(fill=tk.BOTH, expand=True)
frame1 = tk.Frame(self)
frame1.pack(fill=tk.X)
#dataset
lbl1 = tk.Label(frame1, text="Dataset file_name", width=18)
lbl1.pack(side=tk.LEFT, padx=5, pady=5)
entryDataset= tk.Entry(frame1)
entryDataset.pack(fill=tk.X, padx=5, expand=True)
#row col begin
frame2 = tk.Frame(self)
frame2.pack(fill=tk.X)
lblRow = tk.Label(frame2, text="Row", width=6)
lblRow.pack(side=tk.LEFT, padx=5, pady=5)
entryRow = tk.Entry(frame2, width=5)
entryRow.pack(side=tk.LEFT, padx=0, expand=True)
lblCol = tk.Label(frame2, text="Column", width=7)
lblCol.pack(side=tk.LEFT, padx=5, pady=5)
entryCol = tk.Entry(frame2, width=5)
entryCol.pack(side=tk.LEFT, padx=5, expand=True)
lblBegin = tk.Label(frame2, text="Start at", width=6)
lblBegin.pack(side=tk.LEFT, padx=5, pady=5)
entryBegin = tk.Entry(frame2, width=5)
entryBegin.pack(side=tk.LEFT, padx=0, expand=True)
frame3 = tk.Frame(self, bg="grey")
frame3.pack(fill=tk.BOTH, expand=True)
frame4 = tk.Frame(self)
frame4.pack(fill=tk.BOTH, expand=True)
startbutton = tk.Button(frame4, text="Start Clustering", height="100", width="100")
startbutton.pack(side=tk.RIGHT, padx=5, pady=5)
def main():
root = tk.Tk()
root.geometry("300x160+300+160")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
I did it here with the tkinter widgets. You can obviously do import tkinter.ttk as ttk and rewrite the code using those, it is just a matter of taste.
The scroll don't work at all. What's wrong in the code?
I'm using Python 2.7.16
I read that listbox and text widgets are used only for text. As I want to use labels, I'm trying to insert the labels in a frame, but as a Frame didn't scroll I decided to use a canvas. But I couldn't get it to work.
from Tkinter import *
root = Tk()
frame = Frame(root, width=300, height=200)
frame.grid(row=0, column=0)
canvas=Canvas(frame, bg='#FFFFFF', width=300, height=200, scrollregion=(0,0,500,500))
vbar = Scrollbar(frame, orient=VERTICAL)
vbar.pack(side=RIGHT, fill=Y)
canvas.config(width=300, height=250)
canvas.pack(side=LEFT, expand=True, fill=BOTH)
mylist = Frame(canvas, width=100)
for x in range(10):
texto = Label(mylist, text='CODE', bd=2, width=7, relief=RIDGE)
texto.grid(row=x, column=0)
texto1 = Label(mylist, text='EQUIPAMENT', bd=2, width=20, relief=RIDGE)
texto1.grid(row=x, column=1)
mylist.place(x=0, y=0)
vbar.config(command=canvas.yview)
canvas.config(yscrollcommand=vbar.set)
mainloop()