How to dynamically resize window with Tkinter? - python

root= tk.Tk()
root.title('Quick Googling')
canvas1 = tk.Canvas(root, width = 400, height = 300)
canvas1.pack()
entry1 = tk.Entry (root)
canvas1.create_window(200, 140, window=entry1)
canvas1.config(background="#8FB1CC"
button1 = tk.Button(text='Search Google', bg = "blue")
canvas1.create_window(200, 180, window=button1)
I want the colour of my window and the entry and button to utilise all the space when the window's size is changed.

If you use a frame the geometry mangers of tkinter is doing the job for you see:
import tkinter as tk
root= tk.Tk()
root.title('Quick Googling')
myframe = tk.Frame(root)
myframe.pack(fill='both',expand=True)
entry1 = tk.Entry (myframe,background="#8FB1CC")
entry1.pack(fill='x')
button1 = tk.Button(myframe,text='Search Google', bg = "blue")
button1.pack(fill='both',expand=1)
root.mainloop()
Look on a small overview I wrote over the basics.
fill stretch the slave horizontally, vertically or both expand The
slaves should be expanded to consume extra space in their master.
So what the above code does is to create a frame in its natrual size, this means it shrinks itself to the minimum space that it needs to arrange the children.
After this we use for the first time the geometry manager pack and give the options fill, which tells the frame to stretch and using the optional argument expand to consume extra space. Together they resize your frame with the window, since there is nothing else in it.
After that we create an Entry and using once again the method pack to arrange it with this geometry manager. We are using again the optional argument fill and give the value 'x', which tells the geometry manager to stretch the slave/entry vertically.
So the entry streches vertically if the frame is expandes.
At least we create a Button and using the known keywords, to let it resize with the frame.

Related

How to get all the buttons to be automatically the same size depending on the largest one in tkinter using canvas?

How are you supposed to go around sizing all the buttons to be the same size regardless of the text you insert inside, they should all size according to the biggest one.
There is an answer to a similar question like mine already, but it is done using grid and I am using a canvas to place a background image in the window and to place the buttons.
Is it even worth the hassle to get your buttons to the same size according to text automatically, since my text will always be around the same...
I tried getting the size of the buttons using cget() but that returns 0. Where does it store its width then since it has to size itself somehow even if it does it according to text? Can access that in any way? I was thinking of using that value to adjust the value of other buttons somehow, but it turned out as a fail.
If you are wondering why am I making it into a class, idk either, wanted to try it.
I had it working by putting all the buttons in a frame and telling them to fill=x but using a frame destroys the point of using a canvas since the background can't be seen because the frame covers it. Is there a way to make the frame transparent in the canvas, that could also potentially solve my problem.
from tkinter import *
class ThreeButtonMenu():
def __init__(self, button1_text, button2_text, button3_text, image_height = 600, image_width = 500, bg_input = 'space_background.png'):
self.root = Tk()
HxW = str(image_height)+'x'+str(image_width)
self.root.geometry(HxW)
self.root.maxsize(image_height,image_width)
self.root.minsize(image_height,image_width)
self.root.title('Guess')
bg = PhotoImage(file=bg_input)
background_canvas = Canvas(self.root, width = 600, height=500)
background_canvas.pack(fill="both", expand=True)
background_canvas.create_image(0,0, image=bg, anchor='nw')
button1 = Button(self.root, text=button1_text, font = ('Lato',28))
button2 = Button(self.root, text=button2_text, font = ('Lato',28))
button3 = Button(self.root, text=button3_text, font = ('Lato',28), command = self.root.destroy)
button1_window = background_canvas.create_window(300,45, anchor=N, window=button1)
button2_window = background_canvas.create_window(300,160, anchor=N, window=button2)
button3_window = background_canvas.create_window(300,275, anchor=N, window=button3)
print(button1.cget('width'))
print(button2.cget('width'))
print(button3.cget('width'))
self.root.mainloop()
start_menu = ThreeButtonMenu('Start Game', 'Leaderboard', 'Quit')
Thank you for your answers.
You would typically do this when you use a geometry manager (pack, place, or grid).
For example, you need to call pack on each of the buttons. See example of pack below.
import tkinter as tk
root = tk.Tk()
for text in (
"Hello", "short", "All the buttons are not the same size",
"Options", "Test2", "ABC", "This button is so much larger"):
button = tk.Button(root, text=text)
button.pack(side="top", fill="x")
root.mainloop()

Is it possible to reduce a button size in tkinter?

I'm working on a little text editor and currently making the buttons, on the picture bellow the 'B' button for bold. I would like to reduce his size in order to make him fit his true size, like a square box, and get rid of the extra-height.
How could I go below this size that seems to be the default minimum? Both the frame and button height are set to 1 and expecting an integer, so I'm not allowed to go below with something like 0.5.
top_menu = tk.Frame(root)
bold_button = tk.Button(top_menu, text='B', font=('EB Garamond ExtraBold',)) #here a tuple because tkinter needs it when the font name have multiple spaces
bold_button.pack(side='left', padx=4)
The width and height attributes are in units of characters (eg: 1 means the size of one average character). You can specify the width and height in units of pixels if the button has an image.
A button can have both an image and text, so a simple trick is to add a one-pixel transparent pixel as an image, which will then allow you to specify the size in pixels.
The padx and pady options also contributes to the size of the button. If you are trying to get a precise size, you need to set those to zero.
Here is a simple example:
import tkinter as tk
root = tk.Tk()
root.geometry("200x100")
pixel = tk.PhotoImage(width=1, height=1)
toolbar = tk.Frame(root)
toolbar.pack(side="top")
for size in (12, 16, 24, 32):
button = tk.Button(toolbar, text=str(size), width=size, height=size,
image=pixel, compound="center", padx=0, pady=0)
button.pack(side="left")
root.mainloop()
I think you could try to use a ttk.Button and give it a ttk.Style and set the font size:
s = ttk.Style()
s.configure('my_button', font=('Helvetica', 12))
b = ttk.Button(..., style='my_button')
Configuring a button (or any widget) in Tkinter is done by calling a configure method "config"
To change the size of a button called button1 you simple call
button1.config( height = WHATEVER, width = WHATEVER2 )
If you know what size you want at initialization these options can be added to the constructor.
button1 = Button(self, text = "Send", command = self.response1, height = 100, width = 100)

Tkinter fix size of Frame to not overlap Canvas border with scrollbar

I'm working on a GUI with tkinter and i have a problem.
When i add a scrollbar to my app, the frame on my canvas overlaps the outlines (see image)
Here is the code:
from tkinter import *
window = Tk()
window.geometry("400x225")
scrollbar1 = Scrollbar(window, orient=VERTICAL)
canvas1 = Canvas(window, bg="#003333", yscrollcommand=scrollbar1.set)
frame1 = Frame(canvas1, bg="#003333")
scrollbar1.config(command=canvas1.yview)
scrollbar1.pack(side=RIGHT, fill=Y)
canvas1.pack(fill=BOTH, expand=True)
canvas1.create_window((0, 0), window=frame1, anchor="nw")
for x in range(20):
string = "line " + str(x)
label1 = Label(frame1, fg="white", bg="#003333", text=string, font=("Calibri Bold", 14))
label1.pack(pady=5)
window.update()
canvas1.config(scrollregion=canvas1.bbox("all"))
window.mainloop()
I don't know if it's possible but i want the frame to fit within the canvas and keeping the outlines as well.
I hope you get my problem and can probably help me out! Thanks in advance.
The highlightthickness
Specifies a non-negative value indicating the width of the highlight rectangle to draw around the outside of the widget when it has the input focus.
So, this is not really the "border" that you want. It is a part of the drawing space within the canvas, when you use window_create to draw a window, the parent of that window is the canvas, which begins before the highlight and so the window slides over it.
A solution, as also suggested by #martineau would be to make this 0 by specifying highlightthickness=0 and as you suggested that you need the "border" around the whole thing, you can either create a container frame and specify the bd parameter, or just set the bd of the window window.config(bd=2).

How can I set 3 or more Frames using tkinter?

I am trying this so I can place buttons in the medFrame, but they appear in the topFrame. When using topFrame, the button is against the top of the screen, which looks bad, so I figured this could be solved by using a third frame.
from tkinter import *
root = Tk()
root.title('BulletHead')
root.attributes('-fullscreen', True)
root.resizable(width = NO, height=NO)
topFrame=Frame(root)
topFrame.pack(side=TOP)
medFrame=Frame(root)
medFrame.pack()
botFrame = Frame(root)
botFrame.pack(side=BOTTOM)
botonJugar = Button(medFrame, text = 'Jugar')
botonJugar.bind("<Button-1>",jugar)
botonJugar.pack()
botonTabla = Button(medFrame, text = 'Tabla de puntajes')
botonTabla.bind("<Button-1>",tabla)
botonTabla.pack()
root.mainloop()
The reason the widgets appear at the top is because topFrame is empty. Since it has no height or width, and no children, it is only one pixel in size. If you give it a width and height or put some widgets in it, you'll see that the button is in fact in the middle frame.
Here is the image I get when I give the frames an artificial width and height, and force the frames to fill in the "x" direction (and also shrink the window down for illustrative purposes):
Here is what I changed (note that I also added color to make the frames easier to see):
topFrame = Frame(root, bg="pink", height=100)
medFrame = Frame(root, bg="bisque")
botFrame = Frame(root, bg="yellow", height=100)
topFrame.pack(side=TOP, fill="x")
medFrame.pack(fill="x")
botFrame.pack(side=BOTTOM, fill="x")
If you want the medium frame to take up all of the extra space, add the expand option and have it fill in both directions:
medFrame.pack(fill="both", expand=True)
Once you add widgets to the top and bottom frames, they will shrink in height to fit their contents, making it really easy top create tool bars and status bars.
The elements have successfully been added to the middle frame however it appears as though they are in the top frame because the topFrame and botFrame have no dimensions so they don't appear (unless you can perceive one pixel). To get some spacing for the middle frame you want to supply some dimensions to the other frames. try this to give the middle frame some spacing:
topFrame=Frame(root, height=200, width=200)
botFrame = Frame(root, height=200, width=200)
An alternative to this is to check out some other options for using the pack geometry manager with only one frame to get the desired results. Particularly the expand= option is helpful for centering objects in a window.
from tkinter import *
root = Tk()
root.title('BulletHead')
root.attributes('-fullscreen', True)
root.resizable(width = NO, height=NO)
medFrame=Frame(root)
medFrame.pack(expand=True)
botonJugar = Button(medFrame, text = 'Jugar')
botonJugar.bind("<Button-1>",jugar)
botonJugar.pack()
botonTabla = Button(medFrame, text = 'Tabla de puntajes')
botonTabla.bind("<Button-1>",tabla)
botonTabla.pack()
root.mainloop()

How to set a tkinter window to a constant size

I'm programming a little game with tkinter and briefly, I'm stuck.
I have a kind od starting menu, in which are two buttons and one label.
If I just create the frame everything is fine, it has the size 500x500 pixels
I want the background not to change when I create the buttons and the labe, but it adapts the size whatever I do. Here is my code:
import tkinter as tk
def startgame():
pass
mw = tk.Tk() #Here I tried (1)
mw.title('The game')
back = tk.Frame(master=mw, width=500, height=500, bg='black')
back.pack()
go = tk.Button(master=back, text='Start Game', bg='black', fg='red',
command=lambda:startgame()).pack()
close = tk.Button(master=back, text='Quit', bg='black', fg='red',
command=lambda:quit()).pack()
info = tk.Label(master=back, text='Made by me!', bg='red',
fg='black').pack()
mw.mainloop()
I've searched around on stackoverflow and didn't get anything useful!
I've found just one question a bit similar to mine but the answer didn't work. I tried this:
(1) mw.resizable(width=False, height=False)
I can't imagine what is the problem, I'm really desperate.
You turn off pack_propagate by setting pack_propagate(0)
Turning off pack_propagate here basically says don't let the widgets inside the frame control it's size. So you've set it's width and height to be 500. Turning off propagate stills allows it to be this size without the widgets changing the size of the frame to fill their respective width / heights which is what would happen normally
To turn off resizing the root window, you can set root.resizable(0, 0), where resizing is allowed in the x and y directions respectively.
To set a maxsize to window, as noted in the other answer you can set the maxsize attribute or minsize although you could just set the geometry of the root window and then turn off resizing. A bit more flexible imo.
Whenever you set grid or pack on a widget it will return None. So, if you want to be able to keep a reference to the widget object you shouldn't be setting a variabe to a widget where you're calling grid or pack on it. You should instead set the variable to be the widget Widget(master, ....) and then call pack or grid on the widget instead.
import tkinter as tk
def startgame():
pass
mw = tk.Tk()
#If you have a large number of widgets, like it looks like you will for your
#game you can specify the attributes for all widgets simply like this.
mw.option_add("*Button.Background", "black")
mw.option_add("*Button.Foreground", "red")
mw.title('The game')
#You can set the geometry attribute to change the root windows size
mw.geometry("500x500") #You want the size of the app to be 500x500
mw.resizable(0, 0) #Don't allow resizing in the x or y direction
back = tk.Frame(master=mw,bg='black')
back.pack_propagate(0) #Don't allow the widgets inside to determine the frame's width / height
back.pack(fill=tk.BOTH, expand=1) #Expand the frame to fill the root window
#Changed variables so you don't have these set to None from .pack()
go = tk.Button(master=back, text='Start Game', command=startgame)
go.pack()
close = tk.Button(master=back, text='Quit', command=mw.destroy)
close.pack()
info = tk.Label(master=back, text='Made by me!', bg='red', fg='black')
info.pack()
mw.mainloop()
If you want a window as a whole to have a specific size, you can just give it the size you want with the geometry command. That's really all you need to do.
For example:
mw.geometry("500x500")
Though, you'll also want to make sure that the widgets inside the window resize properly, so change how you add the frame to this:
back.pack(fill="both", expand=True)
Try parent_window.maxsize(x,x); to set the maximum size. It shouldn't get larger even if you set the background, etc.
Edit: use parent_window.minsize(x,x) also to set it to a constant size!
Here is the most simple way.
import tkinter as tk
root = tk.Tk()
root.geometry('200x200')
root.resizable(width=0, height=0)
root.mainloop()
I don't think there is anything to specify.
It's pretty straight forward.
There are 2 solutions for your problem:
Either you set a fixed size of the Tkinter window; mw.geometry('500x500')
OR
Make the Frame adjust to the size of the window automatically;back.place(x = 0, y = 0, relwidth = 1, relheight = 1)
*The second option should be used in place of back.pack()
from tkinter import *
root = Tk()
width = root.winfo_screenwidth() #get your Windows width size
height = root.winfo_screenheight() #get your Windows height size
root.geometry("%dx%d" % (width, height))
root.resizable(False,False)
root.mainloop()
#full size Tkinter

Categories

Resources