5

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?

Martin Tournoij
  • 26,737
  • 24
  • 105
  • 146
Hilal
  • 902
  • 2
  • 22
  • 47

3 Answers3

4

The issue is not with your code, it's with the font. You are using a non-unit length, non-monospace font where the characters do not occupy equal space. To resolve this, switch to a monospace font such as Consolas.

import tkFont

my_font = tkFont.Font(family='Consolas', size=15, weight='bold')
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))
AlanSTACK
  • 5,525
  • 3
  • 40
  • 99
  • Excellent it works! Thanks a lot. For python 3, import tkFont does not work. It needs import tkinter.font. But without it, if I use the font name directly (without using tkFont.Font(Family='Consolas' bla bla)) it works. Thanks again ! – Hilal Mar 21 '16 at 11:21
4

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.

Martin Tournoij
  • 26,737
  • 24
  • 105
  • 146
  • I have an application with a grid of buttons using python2.66. The width (if I understand it) is given in number of characters when the text is characters, and pixels when an image is used. How does it work when the characters are not fixed width? – Marichyasana Mar 21 '16 at 11:52
  • @Marichyasana The width of the `Label` is indeed in text units; I'm not entirely sure what Tk uses as a "text unit" internally, but it doesn't really matter One "text unit" is a fixed number of pixels, even if you use a proportional font. This size is proportional to the font size, which can be considered useful (since the spacing will grow if you change the text size)... It's like `em` in CSS. – Martin Tournoij Mar 21 '16 at 12:00
  • Thanks this is also works well. And thanks for the explanation and useful informations. – Hilal Mar 21 '16 at 12:04
3

You need a fixed width font for that approach to work.

For each platform, TkInter provides Standard Fonts, including "TkFixedFont". This should correspond to a decent (and available) fixed width font for the current platform, so the following is a simple and portable way to get a fixed width font:

label_id = tkinter.Label(f, anchor=tkinter.W, text=sector_id, font='TkFixedFont')