1

Dear All I have been trying to insert a treeview in a child window using Tkinter but it has been quite complicated since I don't know how to put them together. Thank you very much in advance! Héctor

This is what I have done so far:

import Tkinter
from Tkinter import *
import tkFont
import ttk 
root= Tk()

class McListBox(object):

    def __init__(self):
        self.tree = None
        self._setup_widgets()
        self._build_tree()

    def _setup_widgets(self):
        s = """
        """
        msg = ttk.Label(wraplength="4i", justify="right", anchor="n",
            padding=(6, 6, 6, 6, 6 ,6), text=s)
        msg.pack(fill='x')
        container = ttk.Frame()
        container.pack(fill='both', expand=True)
        self.tree = ttk.Treeview(columns=element_header, show="headings")
        vsb = ttk.Scrollbar(orient="vertical", command=self.tree.yview)
        hsb = ttk.Scrollbar(orient="horizontal", command=self.tree.xview)
        self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
        self.tree.grid(column=0, row=0, sticky='nsew', in_=container)
        vsb.grid(column=1, row=0, sticky='ns', in_=container)
        hsb.grid(column=0, row=1, sticky='ew', in_=container)
        container.grid_columnconfigure(0, weight=1)
        container.grid_rowconfigure(0, weight=1)

    def _build_tree(self):
        for col in element_header:
            self.tree.heading(col, text=col.title(),
                command=lambda c=col: sortby(self.tree, c, 0))
            self.tree.column(col, width=tkFont.Font().measure(col.title()))
        for item in element_list:
            self.tree.insert('', 'end', values=item)
            for ix, val in enumerate(item):
                col_w = tkFont.Font().measure(val)
                if self.tree.column(element_header[ix], width=None) < col_w:
                    self.tree.column(element_header[ix], width=col_w)
def isnumeric(s):
    for c in s:
        if c in "0000123456789000-.":
            numeric = True
        else:
            return False
    return numeric

def change_numeric(data):
    new_data = []
    if isnumeric(data[0][0]):
        for child, col in data:
            new_data.append((float(child), col))
        return new_data
    return data
def sortby(tree, col, descending):
    data = [(tree.set(child, col), child) for child in tree.get_children('')]
    data =  change_numeric(data)
    data.sort(reverse=descending)
    for ix, item in enumerate(data):
        tree.move(item[1], '', ix)
    tree.heading(col,
        command=lambda col=col: sortby(tree, col, int(not descending)))
element_header = ["Device", "Type", "LETs Threshold (L0)"]
element_list =  [('93L422', 'Bipolar', '0.6')]

mc_listbox = McListBox()

def Child_Window():
    win2 = Toplevel()
    message = "This is the child window"
    Label(win2, text=message).pack()
    Button(win2, text='OK', command=win2.destroy).pack()
Button(root, text='Bring up Message', command=Child_Window).pack()
root.mainloop()
Hector
  • 275
  • 6
  • 16
  • The formatting of your code is all messed up. Could you please take a few minutes to fix it? – Bryan Oakley May 17 '13 at 15:40
  • Hi Bryan, Now I think the formatting of the code is already organized. I hope you can understand it. Thank you very much. – Hector May 18 '13 at 10:14
  • there are still problems in the formatting (for exapmle, `def open_child`, near the end). It would also help to remove the blank line between every line of code. – Bryan Oakley May 18 '13 at 11:28
  • Hi Bryan, I think the formatting is fine. Thak you very much! – Hector May 18 '13 at 17:33
  • no, it's not. In python, indentation is critical; if this is your actual code, then you have many indentation errors that have nothing to do with inserting a treeview in a child widget. – Bryan Oakley May 18 '13 at 18:23
  • Hi bryan, now the formatting is correct, I have test in my pc and it doesn't show any problem regarding to indentation. Thanks in advance – Hector May 18 '13 at 19:48

2 Answers2

2

Treeview should be constructed with parent window as a first argument. I changed Child_Window method so that it displays very simple tree. You can now easily adapt your tree to my example. I would also suggest refactoring code in a way that all methods are contained in McListBox class. I used pack geometry manager instead of grid manager. Here is my example:

def Child_Window():
    win2 = Toplevel()
    message = "This is the child window"
    Label(win2, text=message).pack()
    element_header=['1st','2nd','3rd']
    treeScroll = ttk.Scrollbar(win2)
    treeScroll.pack(side=RIGHT, fill=Y)
    tree = ttk.Treeview(win2,columns=element_header, show="headings", yscrollcommand = treeScroll)
    tree.heading("1st", text="1st")
    tree.pack(side=LEFT, fill=BOTH)
    treeScroll.config(command=tree.yview)

After discussion with Hector I decided to paste all modified class which should work like required. By the way I refactored it so that all functions and variables are members of a class. Works fine with Python 2.7.5.

import Tkinter 
from Tkinter import *
import tkFont
import ttk

class ModifiedMcListBox(object):

    def __init__(self):
        self.root= Tk()
        self.tree = None
        self.element_header = ["Device", "Type", "LETs Threshold (L0)"]
        self.element_list =  [('93L422', 'Bipolar', '0.6')]
        self._setup_widgets()
        self._build_tree()
        self.root.mainloop()

    def _setup_widgets(self):
        s = """
        """
        msg = ttk.Label(wraplength="4i", justify="right", anchor="n",
            padding=(6, 6, 6, 6, 6 ,6), text=s)
        msg.pack(fill='x')
        container = ttk.Frame()
        container.pack(fill='both', expand=True)
        self.tree = ttk.Treeview(columns=self.element_header, show="headings")
        vsb = ttk.Scrollbar(orient="vertical", command=self.tree.yview)
        hsb = ttk.Scrollbar(orient="horizontal", command=self.tree.xview)
        self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
        self.tree.grid(column=0, row=0, sticky='nsew', in_=container)
        vsb.grid(column=1, row=0, sticky='ns', in_=container)
        hsb.grid(column=0, row=1, sticky='ew', in_=container)
        container.grid_columnconfigure(0, weight=1)
        container.grid_rowconfigure(0, weight=1)
        Button(self.root, text='Bring up Message', command=self.Child_Window).pack()

    def _build_tree(self):
        for col in self.element_header:
            self.tree.heading(col, text=col.title(),
                command=lambda c=col: self.sortby(self.tree, c, 0))
            self.tree.column(col, width=tkFont.Font().measure(col.title()))
        for item in self.element_list:
            self.tree.insert('', 'end', values=item)
            for ix, val in enumerate(item):
                col_w = tkFont.Font().measure(val)
                if self.tree.column(self.element_header[ix], width=None) < col_w:
                    self.tree.column(self.element_header[ix], width=col_w)

    def isnumeric(self,s):
        for c in s:
            if c in "0000123456789000-.":
                numeric = True
            else:
                return False
        return numeric

    def change_numeric(self,data):
        new_data = []
        if self.isnumeric(data[0][0]):
            for child, col in data:
                new_data.append((float(child), col))
            return new_data
        return data

    def sortby(self,tree, col, descending):
        data = [(tree.set(child, col), child) for child in tree.get_children('')]
        data = self.change_numeric(data)
        data.sort(reverse=descending)
        for ix, item in enumerate(data):
            tree.move(item[1], '', ix)
        tree.heading(col,
            command=lambda col=col: sortby(tree, col, int(not descending)))

    def Child_Window(self):
        win2 = Toplevel()
        message = "This is the child window"
        Label(win2, text=message).pack()
        new_element_header=['1st','2nd','3rd']
        treeScroll = ttk.Scrollbar(win2)
        treeScroll.pack(side=RIGHT, fill=Y)
        tree = ttk.Treeview(win2,columns=new_element_header, show="headings", yscrollcommand = treeScroll)
        tree.heading("1st", text="1st")
        tree.heading("2nd", text="2nd")
        tree.heading("3rd", text="3rd")
        tree.pack(side=LEFT, fill=BOTH)
        treeScroll.config(command=tree.yview)

mc_listbox = ModifiedMcListBox()
Marcin Kowalczyk
  • 649
  • 6
  • 17
  • Hi Marcin, thank you for your prompt response. Unfortunately I don't understand how to implement your code in mine. Can you tell me how to do that? Sorry for bothering! – Hector May 19 '13 at 08:41
  • Hi Hector, you just need to replace your implementation of Child_Window function with the one proposed by me. If you do this, treeview widget will be displayed in new window and I guess this solves your problem. Of course, behavior of a tree should be implemented by yourself according to requirements. – Marcin Kowalczyk May 19 '13 at 19:18
  • Hi Marcin, thank you for your help. I have tried what you said and it's not working. I think that probably because there is a misunderstanding. In my code there is a treeview, and at the end of the code is a child window.So, what I want to do is putting the treeview within the child window, It does have to appear when pressing one button which is called in the code "bring up the message". Now, when I try what you say it shows only the treeview without being within the childwindow I want it to be. Is there a way to do that?. Thanks for your time. – Hector May 20 '13 at 14:32
  • Ok, there is no other way to fix the problem then to modify original class. Pls check my updated answer. After running a script, you should see 2 treeview widgets. 1st one in a main window. Second one in a new window after pressing a button. Does this fix the problem ? – Marcin Kowalczyk May 20 '13 at 20:30
1

The solution is simple: every widget takes another widget as its first parameter, and this parameter defines the parent of the new widget. The new widget by default will appear in the patent widget when you use pack, grid or place. That's really all you need to know.

So, if you want self.tree to be in win2, win2 must* be given to the treeview constructor as the first argument.

Note that you cannot create a widget in one window and then move it to another (where "window" is defined as "an instance of Tk or Toplevel"). A window and its parent must share the same top-most widget as an ancestor.

* "Must" is a bit too strong, because you can have widgets appear inside widgets other than their immediate parent. I don't think that is relevant to what you are trying to do here, so I won't elaborate to avoid confusion.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685