I am trying to write a small simon says game using tkinter in python, but am having some spacing issues. In my code I create four buttons, one for each colour, and space them in different columns. Then, I create two labels, for borders to seperate the buttons. There is a horizontal label, and a vertical label. The code for the two labels is similar, with switches for height versus width, etc. Yet, I am finding the horizontal label displays as taller than the vertical label displays wide.
My code is as follows:
from Tkinter import *
var = 100
def colour(col):
print col
root = Tk()
for x in range(2 * var + 1):
Grid.columnconfigure(root, x, weight=1, minsize=2)
Grid.rowconfigure(root, x, weight=1, minsize=2)
red = Button(root, bg="RED", bd=0, relief=FLAT, command=lambda: colour("RED"))
red.grid(row=0, column=0, rowspan=var, columnspan=var, sticky=N+W+E+S)
blue = Button(root, bg="BLUE", bd=0, relief=FLAT, command=lambda: colour("BLUE"))
blue.grid(row=0, column=var+1, rowspan=var, columnspan=var, sticky=N+W+E+S)
green = Button(root, bg="GREEN", bd=0, relief=FLAT, command=lambda: colour("GREEN"))
green.grid(row=var+1, column=0, rowspan=var, columnspan=var, sticky=N+W+E+S)
yellow = Button(root, bg="YELLOW", bd=0, relief=FLAT, command=lambda: colour("YELLOW"))
yellow.grid(row=var+1, column=var+1, rowspan=var, columnspan=var, sticky=N+W+E+S)
border_vertical = Label(root, bg="BLACK")
border_vertical.grid(row=0, column=var, rowspan=2*var+1, columnspan=1, sticky=N+W+E+S)
border_horizontal = Label(root, bg="BLACK")
border_horizontal.grid(row=var, column=0, rowspan=1, columnspan=2*var+1, sticky=N+W+E+S)
# It seems that the horizontal line is starting and expanding thicker than the vertical line.
# The reason for this is unknown, as they are identical in code.
root.mainloop()
And here is how it displays.
In the code I used a variable var, but that was just so I could figure out how large I wanted the window to be.
I've tried padding, which seemed to make the vertical border more like the horizontal border, but I would prefer if the horizontal border were more like the vertical border in attributes, because the vertical border scales similarly to the buttons, whereas the horizontal border seems to scale separately.
Thanks for any and all help!
Using a Label as a divider means it's going to have a height sufficient for text (even if there isn't any text in it). You can get the effect you want if you use a Frame instead.
border_vertical = Frame(root, bg="BLACK")
border_vertical.grid(row=0, column=var, rowspan=2*var+1, columnspan=1, sticky=N+W+E+S)
border_horizontal = Frame(root, bg = 'BLACK')
border_horizontal.grid(row=var, column=0, rowspan=1, columnspan=2*var+1, sticky=N+W+E+S)
Related
It's a little complicated, but I'll try my best to explain:
let's say that for example, I have a grid with 4 labels when I have 2 rows and 2 columns (see image below). I'm trying to make the vertical line between columns 1 and 2 (red line in the image) to be the line that splits the window into two equal halves.
You can see a sample of my initial code below.
Edit: note that the elements are labels just for example, but in my original code they are actually all different (some are frames, some images, some buttons, etc)
import tkinter as tk
root = tk.Tk()
label1 = tk.Label(root, text=1, width=8, height=2, bg="red")
label1.grid(row=0, column=0)
label2 = tk.Label(root, text=2, width=10, height=3, bg="green")
label2.grid(row=0, column=1)
label3 = tk.Label(root, text=3, width=5, height=4, bg="blue")
label3.grid(row=1, column=0)
label4 = tk.Label(root, text=4, width=6, height=2, bg="yellow")
label4.grid(row=1, column=1)
root.mainloop()
This code makes the vertical and horizontal center lines of each label perfect as I wanted, but the vertical line between columns 1 and 2 (red line in image) is nowhere near to be the center of the window.
Then, I have tried adding the grid_columnconfigure function to my code:
import tkinter as tk
root = tk.Tk()
root.grid_columnconfigure(0, weight=1) # the line I've added
label1 = tk.Label(root, text=1, width=8, height=2, bg="red")
label1.grid(row=0, column=0)
label2 = tk.Label(root, text=2, width=10, height=3, bg="green")
label2.grid(row=0, column=1)
label3 = tk.Label(root, text=3, width=5, height=4, bg="blue")
label3.grid(row=1, column=0)
label4 = tk.Label(root, text=4, width=6, height=2, bg="yellow")
label4.grid(row=1, column=1)
root.mainloop()
But now I have a different problem, where the columns don't touch each other.
I've also tried to fix the issue by adding the sticky arguments when I'm placing the elements in the grid, and also tried putting every row and every column in their own frame, but all of the solutions did not work out for me.
How can I get this to work? Hope my explanation was clear, and thanks in advance (;
You could just put the four images/labels together into a Frame (or any other container element) and then have that frame horizontally and vertically centered in your root frame with place.
c = tk.Frame(root, bg='white')
c.place(relx=0.5, rely=0.5, anchor='center')
Don't forget to change the parent of the labels from root to c, i.e. Label(c, ...).
Update: But this does not center the line between the red and the green block to the frame. You could combine this with uniform to make the columns equal width, but then there will be some padding between the center and the thinner column...
for n in (0, 1):
c.grid_columnconfigure(n, uniform="foo")
You can use a ttk.Separator widget.
You should use the following code part:
import tkinter.ttk
import tkinter as tk
root = tk.Tk()
---etc---
---etc---
---etc---
tkinter.ttk.Separator(master, orient=VERTICAL).grid(column=1, row=0, rowspan=2, sticky='ns')
root.mainloop()
You can get the grid info of a widget with "grid_info" method.
row = widget.grid_info()['row'] # Row of the widget
column = widget.grid_info()['column'] # Column of the widget
Since there are 2 columns, root.grid_columnconfigure(0, weight=1) only affects the first column.
Try
for n in range(2):
root.grid_columnconfigure(n, weight=1)
or
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)
So i have some tkinter checkboxes in a frame widget, which should be aligned to each other. I thought with grid and then using sticky='w' should align them to most east as possible of the column. So to say, to have the checkbox-squares aligned. Instead this happens (the relief is just to see the boundaries of the checkbutton widgets):
Image of GUI
The documentation of the widget - in my opinion - does not provide a function to set this. With the sticky of grid i am not sure whether it should even be the function. Actually the relief shows its sticky in that column...
Here is my code example:
def init_checkboxes(self):
"""
Creates all checkboxes for this particular frame subclass.
"""
self.bvar_cbx_showplots = tk.BooleanVar(value=False)
self.cbx_showplots = tk.Checkbutton(self.lblframe, width=20,
text='Show Plots after run',
variable=self.bvar_cbx_showplots,
relief='groove')
self.cbx_showplots.grid(row=1, column=2, sticky='W')
self.bvar_cbx_saveres = tk.BooleanVar(value=True)
self.cbx_saveres = tk.Checkbutton(self.lblframe, width=20,
text='Save simulation results',
variable=self.bvar_cbx_saveres,
relief='groove')
self.cbx_saveres.grid(row=2, column=2, sticky='W')
edit: Second attempt from Reblochon
Use anchor.
anchor=
Controls where in the button the text (or image) should be located. Use one of N, NE, E, SE, S, SW, W, NW, or CENTER. Default is CENTER. If you change this, it is probably a good idea to add some padding as well, using the padx and/or pady options. (anchor/Anchor)
import tkinter as tk
root = tk.Tk()
bvar_cbx_showplots = tk.BooleanVar(value=False)
cbx_showplots = tk.Checkbutton(root, width=20,
text='Show Plots after run',
variable=bvar_cbx_showplots,
relief='groove', anchor='w')
cbx_showplots.grid(row=1, column=2, sticky='W')
bvar_cbx_saveres = tk.BooleanVar(value=True)
cbx_saveres = tk.Checkbutton(root, width=20,
text='Save simulation results',
variable=bvar_cbx_saveres,
relief='groove', anchor='w')
cbx_saveres.grid(row=2, column=2, sticky='W')
root.mainloop()
I have a Labelframe and inside that LabelFrame, I've placed a button. That button will always appear in the top-left corner of the LabelFrame, though I would like it to center itself within the LabelFrame. What property am I missing that will force this button to center itself inside of the LabelFrame?
self.f1_section_frame=LabelFrame(self.mass_window, text="LOCATIONS", width=300, height=998, padx=5, pady=5, bd=5)
self.f1_section_frame.grid(row=0, rowspan=6, column=1, sticky="nw", padx=(2,0))
self.f1_section_frame.grid_propagate(False)
self.button_frame1 = LabelFrame(self.f1_section_frame, width=275, height=50)
self.button_frame1.grid_propagate(False)
self.button_frame1.grid(row=1, column=0)
self.b1_scoring=Button(self.button_frame1, text="CONFIRM\nLOCATION(S)", height=2, width=10, command=self.initiate_site_scoring, justify="center")
self.b1_scoring.grid(row=0,column=0, pady=(1,0))
Thanks for the response #R4PH43L. I gave that a shot and it didn't seem to change. However, it got me thinking so I removed "grid_propagate" from the frame that encloses my buttons, which then wrapped the frame around the buttons without any space and centered the frame within the column in which IT was placed. Then I used padx=(x,0) on my leftmost button and padx=(0,x) on my rightmost button to add the space needed on the left and right side and it's working how I need it to now.
self.f1_section_frame=LabelFrame(self.mass_window, text="LOCATIONS", width=300,
height=998, padx=5, pady=5, bd=5)
self.f1_section_frame.grid(row=0, rowspan=6, column=1, sticky="nw", padx=(2,0))
self.f1_section_frame.grid_propagate(False)
self.button_frame1 = LabelFrame(self.f1_section_frame, width=275, height=50)
self.button_frame1.grid(row=1, column=0)
self.b1_scoring=Button(self.button_frame1, text="CONFIRM\nLOCATION(S)", height=2, width=10,
command=self.initiate_site_scoring, justify="center")
self.b1_scoring.grid(row=0,column=0, padx=(15,0))
self.b2_scoring=Button(self.button_frame1, text="CLEAR\nSELECTION(S)", height=2,
width=10, command=self.clear_selected_locations)
self.b2_scoring.grid(row=0,column=1)
self.b3_scoring=Button(self.button_frame1, text="UPDATE\nSELECTION(S)", height=2, width=10,
command=self.update_selected_location_details)
self.b3_scoring.grid(row=0,column=2, padx=(0,15))
I'm quite new to Tkinter but I have been practicing it for a bit now but whenever I try to move a label in a frame with grid geometry by specifying row and column, the label just stays in the middle.
In the code below, I try specifying the row and column for the name label which is in the top middle frame but it never moves. It just stays in the middle.
from tkinter import*
root=Tk()
frame_topleft = Frame(root, height=150, width=50, bg = "green")
frame_topmiddle = Frame(root, height=150, width=250, bg="red")
frame_topright = Frame(root, height=150, width=250, bg="green")
frame_bottomleft = Frame(root, height=300, width=50, bg="blue")
frame_bottommiddle = Frame(root, height=300, width=250, bg="yellow")
frame_bottomright = Frame(root, height=300, width=250, bg="blue")
label_name=Label(frame_topmiddle, text="Name", font="halvetica")
label_phone=Label(frame_topmiddle, text="Phone", font="halvetica")
frame_topmiddle.grid(row=0, column=1)
frame_topleft.grid(row=0, column=0)
frame_topright.grid(row=0, column=2)
frame_bottomleft.grid(row=1, column=0)
frame_bottommiddle.grid(row=1, column=1)
frame_bottomright.grid(row=1, column=2)
label_name.grid(row=0, column=0)
root.mainloop()
So, I'm just wondering how I can fix this. I want the name label at the top left of the top middle frame.
The frame_topmiddle shrinks to the size of label_name and is, by default, displayed at the center of (row 0, column 1).
If you set the sticky option of the grid method to 'nw':
frame_topmiddle.grid(row=0, column=1, sticky='nw')
then frame_topmiddle will be in the top left corner of (row 0, column 1) instead of the center.
If you want frame_topmiddle to keep its initial size, you need to do
frame_topmiddle.grid_propagate(False).
Is it possible to get a text box to have a border even when inactive?
I am not sure I know what "border when inactive" means, but you can certainly add a border to a Text in TkInter. The following code creates two outer frames and two inner frames, then adds a Text to each inner frame. The frames are given a border of 5 px on all sides.
from Tkinter import *
root = Tk()
left_outer = Frame(root, bd=1)
left_outer.pack(side=LEFT, fill=Y, pady=5, padx=5)
right_outer = Frame(root, bd=1)
right_outer.pack(side=LEFT, fill=Y, pady=5, padx=5)
left = Frame(left_outer, bd=2, relief=SUNKEN)
right = Frame(right_outer, bd=2, relief=SUNKEN)
left.pack(fill=Y)
right.pack(fill=Y)
t_start = Text(left, width=20, height=200)
t_start.pack(side=LEFT, fill=Y)
s_start = Scrollbar(left)
s_start.pack(side=RIGHT, fill=Y)
s_start.config(command=t_start.yview)
t_start.config(yscrollcommand=s_start.set)
t_end = Text(right, width=20, height=200)
t_end.pack(side=LEFT, fill=Y)
s_end = Scrollbar(right)
s_end.pack(side=RIGHT, fill=Y)
s_end.config(command=t_end.yview)
t_end.config(yscrollcommand=s_end.set)
root.geometry("400x200")
root.mainloop()
odie5533's answer covers giving a border to a frame that contains only a Text object. This is a great way to give a 2D around a text object, but adds another widget in the mix. I think the original question was related to setting both the border width and relief type of the Text object. This snippet gives a relief to the Text object without involving another frame.
from Tkinter import *
root = Tk()
text_top = Text(root, relief=GROOVE, height=5, width = 40, borderwidth=2)
text_top.pack()
text_bottom = Text(root, relief=RIDGE, height=5, width = 40, borderwidth=2)
text_bottom.pack()
root.geometry("400x200")
root.mainloop()