I am creating a Calculator application with Tkinter, and I've included all the useful buttons there. But the problem is whenever I resize my Tkinter window to a custom size using geometry() method, all buttons don't scale up in the same ratio. To be precise, the buttons in the first column strech a lot leaving other buttons the same size they were. Is there a way to fix all this because it has become harder to include more things in the default size.
Here are some images:
Without custom geometry-
With custom geometry (800x800)-
Here's the useful bit of code:
root = Tk()
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.resizable(False, False)
segoe_font = tkFont.Font(family='Segoe UI', size=16)
segoe_font_ac = tkFont.Font(family='Segoe UI', size=8)
entry_text = StringVar()
inout = Entry(root, textvariable=entry_text)
inout.grid(row=0, column=0, columnspan=4, sticky="nsew")
button18 = Button(root, text="AC", command=allclear, font=segoe_font_ac).grid(row=1, column=0, sticky="nsew")
button1 = Button(root, text="C", command=clear, font=segoe_font).grid(row=1, column=1, sticky="nsew")
button2 = Button(root, text="/", command=divide, font=segoe_font).grid(row=1, column=2, sticky="nsew")
button3 = Button(root, text="×", command=multiply, font=segoe_font).grid(row=1, column=3, sticky="nsew")
button5 = Button(root, text="7", command=tsev, font=segoe_font).grid(row=2, column=0, sticky="nsew")
button6 = Button(root, text="8", command=teig, font=segoe_font).grid(row=2, column=1, sticky="nsew")
button7 = Button(root, text="9", command=tnin, font=segoe_font).grid(row=2, column=2, sticky="nsew")
button4 = Button(root, text="-", command=minus, font=segoe_font).grid(row=2, column=3, sticky="nsew")
button9 = Button(root, text="4", command=tfou, font=segoe_font).grid(row=3, column=0, sticky="nsew")
button10 = Button(root, text="5", command=tfiv, font=segoe_font).grid(row=3, column=1, sticky="nsew")
button11 = Button(root, text="6", command=tsix, font=segoe_font).grid(row=3, column=2, sticky="nsew")
button8 = Button(root, text="+", command=plus, font=segoe_font).grid(row=3, column=3, sticky="nsew")
button12 = Button(root, text="1", command=tone, font=segoe_font).grid(row=4, column=0, sticky="nsew")
button13 = Button(root, text="2", command=ttwo, font=segoe_font).grid(row=4, column=1, sticky="nsew")
button14 = Button(root, text="3", command=tthr, font=segoe_font).grid(row=4, column=2, sticky="nsew")
button15 = Button(root, text="=", command=equals, font=segoe_font).grid(row=4, column=3, rowspan=2, sticky="nsew")
button16 = Button(root, text="0", command=tzer, font=segoe_font).grid(row=5, column=0, columnspan=2, sticky="nsew")
button17 = Button(root, text=".", command=decimal, font=segoe_font).grid(row=5, column=2, sticky="nsew")
entry_text.trace("w", lambda *args: character_limit_and_check_entered_value(entry_text))
root.mainloop()
Can anyone help?
When you resize a window, the grid geometry manager will allocate extra space to every row and every column that has a non-zero weight. The weight is proportional, so a column with a weight of 2 will get twice as many of the extra pixels as a column with a weight of 1. By default, all columns have a weight of zero.
If you want every column or row to be given a percentage of extra available space, you need to give them a non-zero weight. If you want the columns or rows to have an identical width or height you can use the uniform option. All rows or columns with the same uniform value will be of a uniform height or width.
Since you explicitly gave a non-zero weight to only the first row and the first column, that row and column is going to be allocated all extra space. This is why the top entry widget grows in width and height, and all of the buttons in the first column grow in width.
In your case I'm guessing you want the top entry widget to stay the same height, while all of the buttons expand equally. To do that, remove your existing calls to rowconfigure and columnconfigure and replace them with the following:
root.grid_rowconfigure((1,2,3,4,5), weight=1, uniform="row")
root.grid_columnconfigure((0,1,2,3), weight=1, uniform="column")
I think this will help you. I made simple example with 6 buttons but I think you will manage to do it for your case. So I think best option is to use Grid.rowconfigure and Grid.columnconfigure funcitons.
Example code:
from tkinter import *
root = Tk()
root.title("resize button")
root.geometry("500x500")
# here you need to put on what do you want to use row configure, index(row) and weight
Grid.rowconfigure(root, 0, weight=1) # we use on root, row=0 weight=1
Grid.columnconfigure(root, 0, weight=1)
#configure 2nd row
Grid.rowconfigure(root, 1, weight=1)
#configure 3rd row
Grid.rowconfigure(root, 2, weight=1)
#configure 2nd column
Grid.columnconfigure(root, 1, weight=1)
button1 = Button(root, text="Button1")
button2 = Button(root, text="Button2")
button3 = Button(root, text="Button3")
button1.grid(row=0, column=0, sticky="nsew")
button2.grid(row=1, column=0, sticky="nsew")
button3.grid(row=2, column=0, sticky="nsew")
button1_1 = Button(root, text="Button1_1")
button2_1 = Button(root, text="Button2_1")
button3_1 = Button(root, text="Button3_1")
button1_1.grid(row=0, column=1, sticky="nsew")
button2_1.grid(row=1, column=1, sticky="nsew")
button3_1.grid(row=2, column=1, sticky="nsew")
root.mainloop()
Now buttons are resizing with canvas.
Related
I'm making a game based off of the periodic table with tkinter. I made the particle frame just fine, so I decided to copy the code and reuse it for the element frame, changing only the variable names. But for some reason, even though the particle frame works just fine, nothing shows up for the element frame. Here is my full code:
# Boilerplate
import random
import periodictable as pt
from tkinter import *
root = Tk()
root.title('Periodic Table Game')
root.geometry('350x250')
LightBlue = "#b3c7d6"
Menu = Frame(root)
elementFrame = Frame(root)
particleFrame = Frame(root)
settingsFrame = Frame(root)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
for AllFrames in (Menu, elementFrame, particleFrame, settingsFrame):
AllFrames.grid(row=0, column=0, sticky='nsew')
AllFrames.configure(bg=LightBlue)
def show_frame(frame):
frame.tkraise()
show_frame(Menu)
# Menu Frame
Menu.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
MenuTitle = Label(Menu, text="Periodic Table Game", font=("Arial", 15), bg=LightBlue)
MenuTitle.grid(row=0, column=0, pady=25)
MenuTitle.grid_rowconfigure(1, weight=1)
MenuTitle.grid_columnconfigure(1, weight=1)
MenuButton1 = Button(Menu, width=25, text="Guess The Particles", command=lambda: show_frame(particleFrame))
MenuButton1.grid(row=1, column=0)
MenuButton2 = Button(Menu, width=25, text="Guess The Element Name", command=lambda: show_frame(elementFrame))
MenuButton2.grid(row=2, column=0, pady=5)
SettingsButton = Button(Menu, width=25, text="Settings", command=lambda: show_frame(settingsFrame))
SettingsButton.grid(row=3, column=0)
# Particle Frame
particleFrame.grid_columnconfigure(0, weight=1)
BackButtonF2 = Button(particleFrame, text='Back', command=lambda: show_frame(Menu))
BackButtonF2.grid(row=0, column=0, sticky=W)
ParticleLabel = Label(particleFrame, text='testing', bg=LightBlue)
ParticleLabel.grid(row=1, column=0, pady=15)
ParticleEntry = Entry(particleFrame)
ParticleEntry.grid(row=2, column=0, pady=10)
ParticleEnter = Button(particleFrame, text='Enter', width=10)
ParticleEnter.grid(row=3, column=0, pady=10)
# Element Frame
elementFrame.grid_columnconfigure(0, weight=1)
BackButtonF3 = Button(particleFrame, text='Back', command=lambda: show_frame(Menu))
BackButtonF3.grid(row=0, column=0, sticky=W)
ElementLabel = Label(particleFrame, text='testing', bg=LightBlue)
ElementLabel.grid(row=1, column=0, pady=15)
ElementEntry = Entry(particleFrame)
ElementEntry.grid(row=2, column=0, pady=10)
ElementEnter = Button(particleFrame, text='Enter', width=10)
ElementEnter.grid(row=3, column=0, pady=10)
root.mainloop()
Why does identical code work only with one frame?
Precisely, because you copied the code you don't spot where the issue is.
When you are defining the element frame widgets you are placing them all into particleFrame.
Example:
BackButtonF3 = Button(particleFrame, text='Back', command=lambda: show_frame(Menu))
should be
BackButtonF3 = Button(elementFrame, text='Back', command=lambda: show_frame(Menu))
Your problem will be solved.
Change this particleFrame, to elementFrame
snippet code:
BackButtonF3 = Button(elementFrame, text='Back', command=lambda: show_frame(Menu))
BackButtonF3.grid(row=0, column=0, sticky=W)
ElementLabel = Label(elementFrame, text='testing', bg=LightBlue)
ElementLabel.grid(row=1, column=0, pady=15)
ElementEntry = Entry(elementFrame)
ElementEntry.grid(row=2, column=0, pady=10)
ElementEnter = Button(elementFrame, text='Enter', width=10)
ElementEnter.grid(row=3, column=0, pady=10)
Screenshot before:
Screenshot after same as elementFrame and particleFrame:
I tried to use sticky to make b_frame take half of a_frame , and c_frame also take half of a_frame. Each frame use half of a_frame. Sum of c_frame and b_frame will use the whole width of a_frame. But it does not work as I expected.
a_frame=tk.Frame(frame, highlightbackground="red",
highlightthickness=2)
a_frame.grid(row=3, column=0, sticky="nsew", columnspan=2)
b_frame = tk.LabelFrame(a_frame, text="b")
b_frame.grid(row=0, column=0, sticky="nsw")
c_frame = tk.LabelFrame(a_frame, text="c")
c_frame.grid(row=0, column=0, sticky="nse")
d = tk.Entry(b_frame)
d.grid(row=0, column=0)
e = tk.Entry(e_frame)
d.grid(row=0, column=0)
You need to add a_frame.columnconfigure((0,1), weight=1) to make b_frame (in column 0) and c_frame (in column 1) to share the horizontal space of a_frame equally:
a_frame=tk.Frame(frame, highlightbackground="red", highlightthickness=2)
a_frame.grid(row=3, column=0, sticky="nsew", columnspan=2)
# make column 0 and 1 to share horizontal space of a_frame equally
a_frame.columnconfigure((0,1), weight=1)
b_frame = tk.LabelFrame(a_frame, text="b")
b_frame.grid(row=0, column=0, sticky="ew")
c_frame = tk.LabelFrame(a_frame, text="c")
c_frame.grid(row=0, column=1, sticky="ew") # changed column=0 to column=1
d = tk.Entry(b_frame)
d.grid(row=0, column=0)
e = tk.Entry(c_frame)
e.grid(row=0, column=0)
You had some bad type error.
Try this:
import tkinter as tk
root= tk.Tk()
a_frame=tk.Frame(root, highlightbackground="red",
highlightthickness=2)
a_frame.grid(row=0, column=0, sticky="nw", columnspan=3)
b_frame = tk.LabelFrame(a_frame, text="b")
b_frame.grid(row=0, column=0, sticky="nw")
c_frame = tk.LabelFrame(a_frame, text="c")
c_frame.grid(row=0, column=1,sticky="nw")
d = tk.Entry(b_frame)
d.grid(row=0, column=0, sticky="nw")
e = tk.Entry(c_frame)
e.grid(row=0, column=1, sticky="nw")
root.mainloop()
Result:
I am using Tkinter to make a graphical calculator in Python. My aim is to make my calculator look similar to this - http://prntscr.com/k6exeu
I am currently still building my calculator so there's a lot of stuff missing, but I decided to do the design first. When I execute my code, I get this - http://prntscr.com/k6eyhm
I need help fixing this. I'll paste the code so far so you can spot any errors.
import sys
try:
from Tkinter import *
import tkMessageBox
except ImportError:
from tkinter import *
from tkinter import messagebox
window = Tk()
window.title("PyCalc")
window.geometry("500x500")
user_output = Entry(width=50, state='readonly', justify=CENTER)
zero = Button(text="0", height=3, width=3, justify=LEFT)
one = Button(text="1", height=3, width=3, justify=LEFT)
two = Button(text="2", height=3, width=3, justify=LEFT)
three = Button(text="3", height=3, width=3, justify=LEFT)
four = Button(text="4", height=3, width=3, justify=LEFT)
five = Button(text="5", height=3, width=3, justify=LEFT)
six = Button(text="6", height=3, width=3, justify=LEFT)
seven = Button(text="7", height=3, width=3, justify=LEFT)
eight = Button(text="8", height=3, width=3, justify=LEFT)
nine = Button(text="9", height=3, width=3, justify=LEFT)
user_output.grid(row=0)
zero.grid(row=4, column=3, sticky=N+S+E+W)
one.grid(row=1, column=1, sticky=N+S+E+W)
two.grid(row=1, column=2, sticky=N+S+E+W)
three.grid(row=1, column=3, sticky=N+S+E+W)
four.grid(row=2, column=1, sticky=N+S+E+W)
five.grid(row=2, column=2, sticky=N+S+E+W)
six.grid(row=2, column=3, sticky=N+S+E+W)
seven.grid(row=3, column=1, sticky=N+S+E+W)
eight.grid(row=3, column=2, sticky=N+S+E+W)
nine.grid(row=3, column=3, sticky=N+S+E+W)
window.mainloop()
If someone would help me, I'd be very happy :)
-CodeExecution
To get the layout you want, your entry user_output has to span all buttons columns. This can be achieved with the columnspan grid option:
user_output.grid(row=0, columnspan=3)
Moreover, you didn't specified the column in user_output.grid so by default it is put in column 0 while your leftmost buttons are in column 1.
user_output.grid(row=0, columnspan=3)
zero.grid(row=4, column=2, sticky=N+S+E+W)
one.grid(row=1, column=0, sticky=N+S+E+W)
two.grid(row=1, column=1, sticky=N+S+E+W)
three.grid(row=1, column=2, sticky=N+S+E+W)
four.grid(row=2, column=0, sticky=N+S+E+W)
five.grid(row=2, column=1, sticky=N+S+E+W)
six.grid(row=2, column=2, sticky=N+S+E+W)
seven.grid(row=3, column=0, sticky=N+S+E+W)
eight.grid(row=3, column=1, sticky=N+S+E+W)
nine.grid(row=3, column=2, sticky=N+S+E+W)
gives
i am writing a GUI for a RAW image converter in Python using Tkinter. The GUI is divide in three part. The part A has a button to import the RAW file, the part B has four Checkbuttons, and the part C has Checkbuttons with two Entry spaces.
The length of the columns 0 (= the first) is given by the label "correct chromatic aberration" (the longest element). This mean if i change the name for example in correct chromatic aberration for white balance" all elements are shifted as the image below, and the part A, B, and C are related each other.
I wish to make independent the part A to the part B, and so on, in order to have the below image. In other words i wish to place each block of buttons into their own frame, and the frames in the main window.
the original code is:
from __future__ import division
from Tkinter import *
import tkMessageBox
import tkFileDialog
class MainWindow(Frame):
def __init__(self):
Frame.__init__(self)
self.master.title("FOO converter")
self.master.minsize(350, 150)
self.grid(sticky=E+W+N+S)
self.save_dir = None
self.filename_open = None
top = self.winfo_toplevel()
top.rowconfigure(0, weight=1)
top.columnconfigure(0, weight=1)
self.CHART_FILE_TYPES = [('Pentax Electronic Format', '*.pef'),
('Sony Alpha Raw', '*.arw'),
('Minolta Raw', '*.mrw'),
('Camera Image File Format', '*.crw'),
('Canon Raw', '*.cr2'),
('Epson Raw', '*.erw'),
('Samsung Raw', '*.srw'),
('Fujifilm Raw', '*.raf'),
('Kodak Digital Camera Raw', '*.dcr'),
('Nikon Electronic Format', '*.nef'),
('Olympus Raw', '*.orf'),
('All files', '.*')]
for i in range(10): self.rowconfigure(i, weight=1)
self.columnconfigure(1, weight=1)
self.open = Button(self, text='Input raw image file', command=self.open, activeforeground="red")
self.open.grid(row=0, column=0, pady=2, padx=2, sticky=E+W+N+S)
self.sep = Frame(self, height=2, width=450, bd=1, relief=SUNKEN)
self.sep.grid(row=1, column=0, columnspan=4, padx=5, pady=5)
self.CheckVar_camera_white_balance = IntVar()
self.CheckVar_camera_white_balance = Checkbutton(self,
text="Camera white balance",
variable=self.CheckVar_camera_white_balance,
onvalue=1,
offvalue=0)
self.CheckVar_camera_white_balance.grid(row=2, column=0, pady=0, padx=0, sticky=W)
self.CheckVar_average_whole_image_white_balance = IntVar()
self.CheckVar_average_whole_image_white_balance = Checkbutton(self,
text="Average the whole image for white balance",
variable=self.CheckVar_average_whole_image_white_balance,
onvalue=1,
offvalue=0)
self.CheckVar_average_whole_image_white_balance.grid(row=3, column=0, pady=0, padx=0, sticky=W)
self.CheckVar_correct_chromatic_aberration = IntVar()
self.CheckVar_correct_chromatic_aberration = Checkbutton(self,
text="Correct chromatic aberration",
variable=self.CheckVar_correct_chromatic_aberration,
onvalue=1,
offvalue=0)
self.CheckVar_correct_chromatic_aberration.grid(row=4, column=0, pady=0, padx=0, sticky=W)
self.CheckVar_fix_dead_pixels = IntVar()
self.CheckVar_fix_dead_pixels = Checkbutton(self,
text="Fix dead pixels",
variable=self.CheckVar_fix_dead_pixels,
onvalue=1,
offvalue=0)
self.CheckVar_fix_dead_pixels.grid(row=5, column=0, pady=0, padx=0, sticky=W)
self.sep = Frame(self, height=2, width=450, bd=1, relief=SUNKEN)
self.sep.grid(row=6, column=0, columnspan=4, padx=5, pady=5)
self.CheckVar_brightness = IntVar()
self.CheckVar_brightness = Checkbutton(self, text="Brightness",
command=self.switch_brightness,
variable=self.CheckVar_brightness,
onvalue=1,
offvalue=0)
self.CheckVar_brightness.grid(row=7, column=0, pady=0, padx=2, sticky=W)
self.label_level_brightness = Label(self, text="Brightness level:", state=DISABLED)
self.label_level_brightness.grid(row=8, column=0, pady=0, padx=0, sticky=W)
self.entry_level_brightness = Entry(self, state=DISABLED)
self.entry_level_brightness.grid(row=8, column=1, pady=0, padx=0, sticky=W)
self.label_gamma_curve = Label(self, text="Gamma curve:", state=DISABLED)
self.label_gamma_curve.grid(row=9, column=0, pady=0, padx=0, sticky=W)
self.entry_gamma_curve_1 = Entry(self, state=DISABLED)
self.entry_gamma_curve_1.grid(row=9, column=1, pady=0, padx=0, sticky=W)
self.entry_gamma_curve_2 = Entry(self, state=DISABLED)
self.entry_gamma_curve_2.grid(row=9, column=2, pady=0, padx=0, sticky=E+W+N+S)
# functions
def open(self):
self.filename_open = tkFileDialog.askopenfilename(filetypes=self.CHART_FILE_TYPES, defaultextension='.*')
def switch_brightness(self):
pass
if __name__ == "__main__":
d = MainWindow()
d.mainloop()
If you want the regions to be independent, use a frame for each region. For example:
top_frame = Frame(self, ...)
middle_frame = Frame(self, ...)
bottom_frame = Frame(self, ...)
top_frame.pack(side="top", fill="x")
middle_frame.pack(side="top", fill="x")
bottom_frame.pack(side="top", fill="x")
With that, you can now treat each region independently. This now affords you the luxury of using different geometry managers for different sections. You may want to use pack in the top and middle frame, and grid in the lower frame.
# Top frame
self.open = Button(top_frame, ...)
self.open.pack(side="left")
...
# Middle frame
self.CheckVar_camera_white_balance = Checkbutton(middle_frame, ...)
self.CheckVar_camera_white_balance.pack(side="top", fill="x")
...
# Bottom frame
self.CheckVar_brightness = Checkbutton(bottom_frame, ...)
self.CheckVar_brightness.grid(row=0, column=0, pady=0, padx=2, sticky=W)
...
I have this code, which should work, but for some reason actionFrame and infoFrame are put underneath each other...
from tkinter import *
root = Tk()
root.title("TNT Manager")
root.configure(background='grey')
root.grid_rowconfigure(0,weight=1)
root.grid_columnconfigure(0,weight=1)
plannerFrame = Frame(root, bg='grey')
plannerFrame.grid(row=0, column=0, sticky='NSEW')
plannerFrame.grid_rowconfigure(0, weight=15)
plannerFrame.grid_rowconfigure(1, weight=1)
plannerFrame.grid_columnconfigure(0, weight=5)
plannerFrame.grid_columnconfigure(1, weight=2)
actionFrame = Frame(plannerFrame, width=500, height=400)
actionFrame.grid_propagate(0)
actionFrame.grid(row=0, column=0, sticky="NSEW", padx=1,pady=1)
infoFrameWid(actionFrame) #for now just adds text widget inside frame
infoFrame = Frame(plannerFrame, width=200, height=400)
infoFrame.grid_propagate(0)
infoFrame.grid(row=0, column=1, sticky="NSEW", padx=1, pady=1)
infoFrameWid(infoFrame)
saveFrame = Frame(plannerFrame)
infoFrame.grid(row=1, column=0, padx=1, pady=1)
The problem I have is the infoFrame widget is going above the actionframe widget. They are on the same row. If you take away the saveframe widget it works fine.
you have to change atlast
saveFrame = Frame(plannerFrame)
infoFrame.grid(row=1, column=0, padx=1, pady=1)
to
saveFrame = Frame(plannerFrame,width=700, height=400)
saveFrame.grid(row=1, column=0, padx=1, pady=1)