3

I am trying to build a small window in tkinter, but I observed that different widgets take on different widths even when set with the same width. Here's the output that I can see on running the code:

output

The black widget in first row is an Entry widget declared as below (width=30):

entry=Entry(root,width=30,font=('arial',14,'bold'),bd=0,bg='black',fg='white')
entry.grid(row=0,column=0,padx=0,pady=0,ipadx=0,ipady=0,columnspan=10)

The colorful widgets in second row are Label(s) widgets defined as below (width=3 * 10 widgets = 30):

label=Label(root,width=3,font=('arial',14,'bold'),bg=<different_colors>)
label.grid(row=1,column=<increasing columns>,padx=0,pady=0ipadx=0ipady=0)

The purple widget in the third row is again a Label widget defined as below (width=30):

biglabel=(root,width=30,font=('arial',14,'bold'),bg='purple')
biglabel.grid(row=2,column=0,padx=0,pady=0ipadx=0ipady=0,columnspan=10)

As per the widths mentioned, shouldn't all 3 rows be of same width? But as seen in the output image, all 3 rows are of different width.

Questions:

  1. Can someone please explain the reason for this behavior?
  2. How to make different widgets to follow the grids throughout the app/what to use instead of width to make them of the same size deterministically? As I need to add widgets based on what is typed in the entry and don't want it to have different sizes. Right now the window expands to accommodate the second row when that row is added after typing something in the entry. Interactive output can be seen by executing my code online here: https://replit.com/@KCKotak/TKinter-experiment#main.py

Full code example to test:

from tkinter import *

root=Tk()

def add_text_label(r=0,c=0,bgcolor='white'):
    text_label=Label(root, width=3, font=('arial',14,'bold'), bg=bgcolor)
    text_label.grid(row=r,column=c,padx=0,pady=0,ipadx=0,ipady=0)

root.geometry('-15-35')
root.title('experiment')
root.config(bg='white')

# first row: black entry as seen in output image. **width=30**
text_entry=Entry(root,width=30,font=('arial',14,'bold'),bd=0,bg='black',fg='white')
text_entry.grid(row=0,column=0,padx=0, pady=0,ipadx=0,ipady=0,columnspan=10)

# second row: colorful labels. **width=3 x 10 = 30**
add_text_label(1,0,'red')
add_text_label(1,1,'blue')
add_text_label(1,2,'yellow')
add_text_label(1,3,'orange')
add_text_label(1,4,'green')
add_text_label(1,5,'red')
add_text_label(1,6,'blue')
add_text_label(1,7,'yellow')
add_text_label(1,8,'orange')
add_text_label(1,9,'green')

# third row: purple label. **width=30**
big_label=Label(root, width=30, font=('arial',14,'bold'), bg='purple')
big_label.grid(row=2,column=0,padx=0, pady=0,ipadx=0,ipady=0,columnspan=10)

root.mainloop()
KCK
  • 2,015
  • 2
  • 17
  • 35
  • Don't give the Entry and the single Label a width at all; instead use `.grid(sticky="ew")` to make them take up the full width of the grid. – jasonharper Apr 20 '23 at 13:15
  • that can be a solution, but as I mentioned I need to add different widgets as and when something is typed in the entry. So initially there will only be an entry and then the label will be added (which will be multiple labels as in second row). in that case, I am worried if the size of the window may increase or if the labels may overflow. – KCK Apr 20 '23 at 13:19
  • just confirmed the above behavior. So when I add labels after sometime of starting the program, the window size changes which I don't want to be. – KCK Apr 20 '23 at 13:52

1 Answers1

3

Can someone please explain the reason for this behavior?

The short answer is that Entry and Label widgets aren't the same, and may have different values for some of the options. For example, an Entry widget by default has a highlightthickness of 1, but that same option for the Label is likely zero. Also, labels have a padx and pady option that might by default be non-zero. The Entry widget does not have this option.

If you set borderwidth and highlightthickness to 0 (zero) for both the Entry and Label widgets, and also set padx to zero on the Label widgets, then everything may line up. On my machine I still get a 2 pixel difference between the top row and the other two rows. There might be another option I'm forgetting about, or it might just be that an Entry widget is naturally going to be just slightly larger than a Label.

How to make different widgets to follow the grids throughout the app

Use the sticky attribute so that the widgets fill the space allocated to them. You can also use the uniform and weight options on all columns to force them to be exactly the same width. For example:

entry.grid(..., sticky="nsew")
...
label.grid(...,sticky="nsew")
...
biglabel.grid(..., sticky="nsew")
...
root.grid_columnconfigure((0,1,2,3,4,5,6,7,8,9), weight=1, uniform="a")

Note: the specific value for uniform ("a") is irrelevant. The only thing that matters is that all columns use the same value.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • tried the said changes (borderwidth, highlightthickness & columnconfigure), but still not the same... Entry still being the smallest (similar to the output image, slight larger entry and big_label). Upvoting for explanation of question 1. – KCK Apr 20 '23 at 15:35
  • as mentioned in question, I want to dynamically add second row when something is input in entry. will try the sticky option to see if the window size doesn't change. (it does when sticky is used for entry, but will try for small lables of row 1) – KCK Apr 20 '23 at 15:36
  • @KCK: `sticky` should have absolutely no effect on the size of the window. `grid` will allocate space for a widget. If the widget is too small, the widget will be expanded to fit the space, but the space itself won't grow or shrink. – Bryan Oakley Apr 20 '23 at 15:50
  • @KCK: yes, on my machine the entry widget is exactly 2 pixels wider than the widgets on the other rows. This might be an immutable fact of how the widgets are drawn. – Bryan Oakley Apr 20 '23 at 15:52
  • I tried all your suggestions, but still the window does expand when I try to add the small label row on some event as mentioned in question. Here is fiddle to check the output on some event: https://replit.com/@KCKotak/TKinter-experiment#main.py Added a textvariable in entry with a callback which adds the small labels when something is typed in the entry. adding the link in question too. – KCK Apr 21 '23 at 06:44
  • @KCK: the code in your question doesn't have that behavior. – Bryan Oakley Apr 21 '23 at 17:26
  • As mentioned previously, had added a link in the question where you can run the interactive code which behaves exactly as I mentioned... – KCK Apr 27 '23 at 13:32