Tkinter. Виджет Treeview

Класс ttk.Treeview  – пример принципиально нового элемента, который входит в библиотеку tkinter.ttk. С его помощью информация может быть представлена в иерархической или табличной форме. Это позволит более удобно ее считывать. 

Каждый элемент, который добавляется к классу ttk.Treeview, состоит из нескольких колонок (одной – также возможный вариант). С помощью первой отображаются текст и иконка, показывающие, возможно ли раскрытие элемента. А все остальные колонки показывают сами значения.

Первая строка этого класса содержит заголовки, которые можно спрятать. Также этот класс может работать с CSV-файлами. И мы наглядно это продемонстрируем.

Практика использования виджета Treeview

Давайте попробуем создать такое приложение. Оно получает список контактов, которые содержатся в CSV-файле и представляет его в виде таблицы. Выглядеть приложение будет так.Tkinter. Виджет Treeview

Давайте создадим объект класса ttk.Treeview, который будет содержать три колонки, в которых будут содержаться имя, фамилия и адрес электронной почты. 

Эти данные будут загружаться из файла формата CSV, а потом будет осуществляться связывание виртуального элемента <<TreeviewSelect>>. Отсюда исходит вопрос – откуда он берется? Он появляется, если выбирается хотя бы один элемент.

Нагляднее будет с примером кода. 

import csv

import tkinter as tk

import tkinter.ttk as ttk




class App(tk.Tk):

    def __init__(self, path):

        super().__init__()

        self.title("Ttk Treeview")




        columns = ("#1", "#2", "#3")

        self.tree = ttk.Treeview(self, show="headings", columns=columns)

        self.tree.heading("#1", text="Фамилия")

        self.tree.heading("#2", text="Имя")

        self.tree.heading("#3", text="Почта")

        ysb = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.tree.yview)

        self.tree.configure(yscroll=ysb.set)




        with open("../lesson_13/contacts.csv", newline="") as f:

            for contact in csv.reader(f):

                self.tree.insert("", tk.END, values=contact)

        self.tree.bind("<<TreeviewSelect>>", self.print_selection)




        self.tree.grid(row=0, column=0)

        ysb.grid(row=0, column=1, sticky=tk.N + tk.S)

        self.rowconfigure(0, weight=1)

        self.columnconfigure(0, weight=1)




    def print_selection(self, event):

        for selection in self.tree.selection():

            item = self.tree.item(selection)

            last_name, first_name, email = item["values"][0:3]

            text = "Выбор: {}, {} <{}>"

            print(text.format(last_name, first_name, email))




if __name__ == "__main__":

    app = App(path=".")

    app.mainloop()

При запуске этого приложения после выбора контакта информация о нем будет выводиться в стандартный вывод. 

Принцип использования виджета Treeview

Чтобы создать экземпляр класса ttk.Treeview, в котором есть несколько колонок, необходимо задать идентификатор каждого столбца с использованием параметра columns. После этого уже осуществляется настройка текста заголовка, для чего используется функция heading(), которая вызывается из объекта tree(проще говоря, это – метод).

В нашем примере мы используем идентификаторы #1, #2, #3. Все дело в том, что первая колонка всегда идентифицируется, как #0.

Кроме этого, необходимо передать значение headings параметру show. Это делается с целью обозначить, что нужно спрятать нулевую колонку. Ведь в нашем случае вложенных элементов не предусматривается.

Для параметра show следующие значения могут использоваться:

  • tree. Показывает нулевую колонку.
  • headings. Показывает строку заголовка.
  • tree headings. Показывает и нулевую колонку, и строку заголовка. Это стандартное значение. То есть, если не задать другое, то будет использоваться это.
  1. “». Не показывает ни строку заголовка, ни нулевую колонку.

Затем к виджету мы добавляем вертикальную прокрутку. 

        columns = ("#1", "#2", "#3")

        self.tree = ttk.Treeview(self, show="headings", columns=columns)

        self.tree.heading("#1", text="Фамилия")

        self.tree.heading("#2", text="Имя")

        self.tree.heading("#3", text="Почта")

        ysb = ttk.Scrollbar(self, orient=tk.VERTICAL, command=self.tree.yview)

        self.tree.configure(yscroll=ysb.set)

Чтобы осуществить загрузку контактов в таблицу, необходимо воспользоваться функцией render(), которая находится в модуле CSV, чтобы обработать ее. В процессе этого, строки на каждой из итераций, добавляются к дереву.

Как это делается? Используется метод insert(), получающий родительский узел и положение для размещения элемента. 

Так, как все контакты отображаются, как объекты верхнего уровня, передаем в качестве первого параметра пустую строку, а также константу END. Это делается для того, чтобы добавлять новые контакты на последнюю позицию.

Кроме этого, возможно использование и других ключевых слов для этого метода. Тут применяется параметр values, принимающий последовательность значений, которые и показываются в колонках нашего дерева.

        with open("../lesson_13/contacts.csv", newline="") as f:

            for contact in csv.reader(f):

                self.tree.insert("", tk.END, values=contact)

        self.tree.bind("<<TreeviewSelect>>", self.print_selection)

<<TreeviewSelect>> – это виртуальное событие, генерация которого осуществляется при выборе элементов таблицы. Далее используем метод selection для того, чтобы получить текущее выделение. Эта команда исполняется в обработчике print_selection()

Далее для каждого результата выполняется следующая последовательность действий:

  1. Используется метод item(), который помогает нам получить параметры и значения выбранного объекта в виде словаря.
  2. Получаем имя, фамилию и адрес электронной почты. Для этого необходимо получить первые три значения этого словаря. 
  3. После этого значения выводятся в стандартный вывод. Предварительно осуществляется их форматирование.
    def print_selection(self, event):

        for selection in self.tree.selection():

            item = self.tree.item(selection)

            last_name, first_name, email = item["values"][0:3]

            text = "Выбор: {}, {} <{}>"

            print(text.format(last_name, first_name, email))

Мы рассмотрели основные особенности класса ttk.Treeview, так как мы работали со стандартной таблицей. Тем не менее, она поддерживает значительно больше функций. 

Как использовать теги в элементах Treeview?

С помощью тегов разработчик может связать последовательности события с конкретными строками таблицы. Допустим, появилась потребность открывать новое окно, чтобы добавить информацию об электронной почте по двойному клику. Правда, это должно работать исключительно для тех записей, в которых поле email уже содержит какую-то информацию.

Чтобы это реализовать, необходимо добавить тег с условием во время вставки. Затем необходимо осуществить вызов tag_bind() на элементе виджета, содержащего последовательность <Double-Button-1>. Тут просто возможна ссылка на функцию-обработчика send_email_to_contact() по имени.

columns = ("Фамилия", "Имя", "Почта")

tree = ttk.Treeview(self, show="headings", columns=columns)




for contact in csv.reader(f):

    email = contact[2]

    tags = ("dbl-click",) if email else ()

    self.tree.insert("", tk.END, values=contact, tags=tags)




tree.tag_bind("dbl-click", "<Double-Button-1>", send_email_to_contact)

Аналогично процессам, которые осуществляются при связывании событий с элементами Canvas, необходимо помнить о том, что нужно добавлять элементы с тегами к ttk.Treeview до того, как будет осуществлен вызов tag_bind(), поскольку добавление связываний осуществляется исключительно к имеющимся совпадениям в элементах.

Как осуществлять заполнение вложенных элементов?

ttk.Treeview нередко используется в качестве обычной таблицы. Тем не менее, намного интереснее использовать его по своему основному назначению – для отображения иерархической структуры. 

Давайте попробуем создать такое приложение.Tkinter. Виджет Treeview

Для заполнения дерева будет использоваться метод populate_node().

При раскрытии узла осуществляется еще один вызов этого метода, после чего туда записываются вложенные элементы.  

import os

import tkinter as tk

import tkinter.ttk as ttk




class App(tk.Tk):

    def __init__(self, path):

        super().__init__()

        self.title("Ttk Treeview")




        abspath = os.path.abspath(path)

        self.nodes = {}

        self.tree = ttk.Treeview(self)

        self.tree.heading("#0", text=abspath, anchor=tk.W)

        ysb = ttk.Scrollbar(self, orient=tk.VERTICAL,

                            command=self.tree.yview)

        xsb = ttk.Scrollbar(self, orient=tk.HORIZONTAL,

                            command=self.tree.xview)

        self.tree.configure(yscroll=ysb.set, xscroll=xsb.set)




        self.tree.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W)

        ysb.grid(row=0, column=1, sticky=tk.N + tk.S)

        xsb.grid(row=1, column=0, sticky=tk.E + tk.W)

        self.rowconfigure(0, weight=1)

        self.columnconfigure(0, weight=1)




        self.tree.bind("<<TreeviewOpen>>", self.open_node)

        self.populate_node("", abspath)




    def populate_node(self, parent, abspath):

        for entry in os.listdir(abspath):

            entry_path = os.path.join(abspath, entry)

            node = self.tree.insert(parent, tk.END, text=entry, open=False)

            if os.path.isdir(entry_path):

                self.nodes[node] = entry_path

                self.tree.insert(node, tk.END)




    def open_node(self, event):

        item = self.tree.focus()

        abspath = self.nodes.pop(item, False)

        if abspath:

            children = self.tree.get_children(item)

            self.tree.delete(children)

            self.populate_node(item, abspath)




if __name__ == "__main__":

    app = App(path="../")

    app.mainloop()

Как видим, ничего нет сложного. Все просто и интуитивно понятно. Достаточно выполнять инструкции, которые приводятся здесь, и можно создавать самые сложные иерархические структуры и таблицы.

ОфисГуру
Adblock
detector