Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String alignment in Tkinter

Tags:

python

tkinter

I want a message box in Python which shows the concatenated string text. I want the text is left aligned but it doesn't. I tried ljust() and {:<14} etc. But it still not aligned.

It seems like this:

enter image description here

The code piece is below,

for todo_item in resp.json()['SectorList']:
    sector_id +='Sector Id: {:<14}'.format(todo_item['SectorId']) + '\n'
    sector_name += 'Sector Name: {:<40}'.format(todo_item['SectorName']) + '\n'

After the loop I add those texts into my message box.

label_id = tkinter.Label(f, anchor = tkinter.W, text = sector_id)
label_name= tkinter.Label(f,anchor = tkinter.W, text = sector_name)

label_id.grid(row= 2, column = 1, sticky = tkinter.W)
label_name.grid(row= 2, column = 2, sticky = tkinter.W)

Sector id part is fine but sector name is not left aligned. Any idea?

like image 270
Hilal Avatar asked Mar 21 '16 10:03

Hilal


2 Answers

There is no problem with your code.

The problem lies in the fact that you are using non-unit length non-monospace font, where the characters do not take up the same amount of space.

This can be fixed by changing to a monospace font like consolas

import tkFont

my_font = tkFont.Font(family='Consolas', size=15, weight='bold')

# then plug in the font to your widget ...

so in your code it would be something like

label_id = tkinter.Label(f, anchor=tkinter.W, text=sector_id, font=('Consolas', 15))
label_name = tkinter.Label(f, anchor=tkinter.W, text=sector_name, font=('Consolas', 15))
like image 189
AlanSTACK Avatar answered Sep 20 '22 22:09

AlanSTACK


Relying on fonts for alignment is bad practice; as mentioned it only works with monospaces fonts, but do you really want to use monospaces fonts in your entire application only for alignment? I sure don't. And what if you want to change a Label to a Input or something else later on? Do we now have to add new Labels just for alignment?

So while changing to a monospaced font "works", a (much) better way would be to use the tools Tk provides us.

For example, you can set the Label() in the first column to a fixed width:

import tkinter

# Just some random strings of different sizes from my dictionary
names = ['Algol', 'American', 'Americanises', 'Americanising', 'Americanism',
    'Argentine', 'Argentinian', 'Ariz', 'Arizona', 'Armstrong']

root = tkinter.Tk()
tkinter.Label(root, text='Lists:', anchor=tkinter.W).grid(row=0, column=0, sticky=tkinter.W)
for i in range(0, 10):
    label_id = tkinter.Label(root, width=30, anchor=tkinter.W, text='Sector %s' % i)
    label_name = tkinter.Label(root, anchor=tkinter.W, text=names[i])

    label_id.grid(row=i+1, column=0, sticky=tkinter.W)
    label_name.grid(row=i+1, column=1, sticky=tkinter.W)

root.mainloop()

There are more ways to do this, though. For example by setting a width using columnconfigure:

import tkinter

# Just some random strings of different sizes from my dictionary
names = ['Algol', 'American', 'Americanises', 'Americanising', 'Americanism',
    'Argentine', 'Argentinian', 'Ariz', 'Arizona', 'Armstrong']

root = tkinter.Tk()
root.columnconfigure(0, minsize=150)
tkinter.Label(root, text='Lists:', anchor=tkinter.W).grid(row=0, column=0, sticky=tkinter.W)
for i in range(0, 10):
    label_id = tkinter.Label(root, anchor=tkinter.W, text='Sector %s' % i)
    label_name = tkinter.Label(root, anchor=tkinter.W, text=names[i])

    label_id.grid(row=i+1, column=0, sticky=tkinter.W)
    label_name.grid(row=i+1, column=1, sticky=tkinter.W)

root.mainloop()

The advantage of using columnconfigure() is that the minimum width is independent of the column's contents. So if you change the Label() to something else later, the layout should still work, and it's probably a bit more obvious that you explicitly want to set a width for this column.

like image 43
Martin Tournoij Avatar answered Sep 20 '22 22:09

Martin Tournoij