Search code examples
pythontkinterlistboxalignment

How to align text in a tkinter Listbox


I want to align text within a tkinter listbox. I have a list of dictionaries with reg. no., name, and email as keys in each dictionary. I have looped over the list and want the three attributes to be aligned in such a way, that there is equal distance between these words. So every word in every row has to start at the same position than the word in the row before / afterwards. But due to different name lengths, the alignment is disturbed. In the code above, for simplicity i have just created 4 dictionaries for 4 students, but actually there are more than 50 students that I have to manage. Also is there another simple way to display this data other than the list box, with the same condition stated above?

from tkinter import *

root = Tk()

students_Box = LabelFrame(root,
                    text = 'Registered Students', bd = 4,
                    relief = GROOVE, labelanchor = 'n',
                    font = 'Arial 10 bold', fg = 'navy blue',
                    width = 850, height = 180)
                            
students_Box.grid_propagate(0)
students_Box.pack(pady = 15)

scrollbar = Scrollbar(students_Box)
scrollbar.pack(side = RIGHT, fill = Y)

listbox = Listbox(students_Box, width = 90, bg = 'azure', font = 'TkDefaultFont 11')
listbox.pack(padx = 5, pady = 10)

allStudents = [{'Reg': '2018-MC-01', 'Name': 'Usman Khan', 'Email': '[email protected]'},
            {'Reg': '2018-MC-02', 'Name': 'Muhammad Ehtisham Zafar', 'Email': '[email protected]'},
            {'Reg': '2018-MC-03', 'Name': 'Ali Khan', 'Email': '[email protected]'},
            {'Reg': '2018-MC-04', 'Name': 'Abdullah Akram', 'Email': '[email protected]'}]   # A List of Dictionaries

for i in range(len(allStudents)):
        listbox.insert(END, f"{allStudents[i]['Reg']}     {allStudents[i]['Name']}{' '*20}{allStudents[i]['Email']}")

listbox.configure(yscrollcommand = scrollbar.set)
scrollbar.configure(command = listbox.yview)

mainloop()

Solution

  • You can use string formatting and fixed/monospaced font:

    listbox = Listbox(students_Box, width=90, bg='azure', font='Courier 11') # use a fixed/monospaced font
    ...
    for rec in allStudents:
        listbox.insert(END, f"{rec['Reg']:15}{rec['Name']:30}{rec['Email']}")
    

    If you do not prefer hard-coded widths, you can calculate the maximum width of each column:

    widths = {key:0 for key in allStudents[0]}
    for rec in allStudents:
        for key in rec:
            widths[key] = max(widths[key], len(rec[key]))
    
    for rec in allStudents:
        listbox.insert(END, f"{rec['Reg']:{widths['Reg']}}  {rec['Name']:{widths['Name']}}  {rec['Email']}")