4

Recently, I use tkinter TreeView to show many columns in Python. Specifically, 49 columns data in a treeview. I use grid to manage my widgets.

I found out the width of the treeview only depends on the width of columns.

My question is, How can I set the width of the Treeview. (The default width is the summation of all columns' width)

When all my column width is set as 20. This is 49 columns. :) enter image description here

Here is my main code :

frame = Frame(self.master, width = 1845, height = 670)
frame.place(x = 20, y = 310)
tree_view = Treeview(frame, height = 33, selectmode = "extended")
for i in range(len(id_list)):
    tree_view.column(id_list[i], width = width_list[i], anchor = CENTER)
    tree_view.heading(id_list[i] , text = text_list[i])
tree_view["show"] = "headings"
# Omit the declaration of scrollbar    
tree_view['yscroll'] = self.y_scollbar.set
tree_view['xscroll'] = self.x_scollbar.set
tree_view.grid(row = 0, column = 0, sticky = NSEW)
for item in detail_info_list:
    tree_view.insert("",0, text = str(item.id), value=(...))

id_list,width_list,text_list is used to store columns information. detail_info_list is to store the data showed in the Treeview.

My target is when I define a large width(for example: 3000) of some column, my treeview could show the data as I expected. But the treeview is across my screen and the horizontal scrollbar also can't slide.

When 17th column is set as 1500: enter image description here

I can't see my buttons, and I can't slide the horizontal scrollbar.

Also, I have tried some solution.

  • Define a frame to be the Treeview parent. And define the width and height to constraint the Treeview. But it didn't work.
  • I looked up some documents and search for this question. I don't find any solution to set the width as a constant number.
4
  • 1
    If the number of columns and their width is fixed (which defines the width of the Treeview), what is the problem exactly ? Commented Sep 21, 2016 at 7:23
  • 1
    Please post the code, and tell what is the result you'd like. Then an answer can be concrete. Commented Sep 21, 2016 at 7:33
  • Could you post the complete (working) code? Commented Sep 21, 2016 at 8:13
  • I added the main code about Treeview @JacobVlijm Commented Sep 21, 2016 at 8:16

3 Answers 3

3

After searching for over a week now, I stumbled upon a very easy way to do the 'magic'.

  1. I read the current size of my mainWindow
  2. Add the data to the treeView
  3. Set the width of each column depending on the max length of an entry (by using measure)
  4. Calling the update function on my mainWindow (not sure if this is needed)
  5. Setting the size of the mainWindow to the stored values

And here is my code:

def reloadTreeViewData(self):
    # get current size of main window
    curMainWindowHeight = self.parent.winfo_height()
    curMainWindowWidth = self.parent.winfo_width()

    #delete all
    for child in self.tree.get_children():
        self.dicData = {}
        self.tree.delete(child)

    # reload all
    count = 0
    for row in self.data:
        adding_string = []
        for element in self.indexlist:
            adding_string.append(str(row[element]))
        insert_ID = self.tree.insert('', 'end', text=count, values=adding_string)
        # save the data in it's original types in a dictionary
        self.dicData[insert_ID] = [row[x] for x in self.indexlist]
        count += 1

    # reset column width
    max_colum_widths = [0] * len(self.indexlist)
    for child in self.tree.get_children():
        rowData = self.dicData[child]
        for idx, rowIdx in enumerate(self.indexlist):
            item = rowData[idx]
            new_length = self.myFont.measure(str(item))
            if new_length > max_colum_widths[idx]:
                max_colum_widths[idx] = new_length
    for idx, item in enumerate(self.attributeList):
        if int(max_colum_widths[idx]) < 50:
            self.tree.column(item, width=50)
        else:
            self.tree.column(item, width=int(max_colum_widths[idx]))

    # restore the size of the mainWindow
    self.parent.update()
    self.parent.geometry("" + str(curMainWindowWidth) + "x" + str(curMainWindowHeight))

My headings for the treeView are stored in self.attributeList but the data comes from a database, which has way more columns I want to show. So I use a mapping list which is stored as self.indexlist.

self.myFont is defined as follows:

    import tkinter.font as tkFont
    self.myFont = tkFont.Font(self, "Calibri", 12)

I use the treeview just to show the data and a seperate dictionary to save the data, by using the child-id (returned by insert) as key. This way I keep the real data I inserted into the treeView. This is important for strings like '0005' which will return as 5 (integer) when you recall it from the treeview and you lose the leading zeros.

I hope this solution helps others. If there is a more convenient solution feel free to comment.

If you have any questions about my code, feel free to ask.

Sign up to request clarification or add additional context in comments.

Comments

1

After trying so many ways to solve this problem, I find out a simple but silly solution. After initializing the width of the Treeview, you just need to resize the with of the column and the width of the Treeview will NOT change.

Perhaps, this is the constraint of Tcl/Tk.

4 Comments

Could you please explain this with a bit more of detail? I have seen that the initial column size defines the widget size of the tree... but how do you resize the columns after? Did you mean you resize them by hand, or by code, somehow after the widgets have already been laid out?
Nevermind, just figured it out! You can just call update() on the root Tk object first (which will do all the layout) and then resize the columns as you wish (in my case I use the measure method of tkinter.font.Font).
@jdehesa Can you please post the code how you did it, i cant figure it out?
@AleksandarBeat I have sth like this view = ttk.Treeview(frame, columns=cols, show="headings"), so first I do for col in cols: view.column(col, width=0) to have the "minimal width" tree, after that I run root.update() (root is the root Tk object), forcing a layout of the tree and fixing its width in the window, and then I set the heading and actual width with for col in cols: view.heading(col, text=col); view.column(col, width=col_width), where col_width is the desired column width (in my case font.measure(col), font being defined as tk.font.Font(root)).
0

It's possible to achieve this using the place geometry manager. Although not highly recommended, the place manager lets you specify the width of the widget:

tree_view = ttk.Treeview(root)
tree_view.place(relx=0.01, rely=0.1, width=500, height=500)

Reference: https://www.youtube.com/watch?v=m061SFifdi8&ab_channel=SenGideons

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.