Spaltensortierung einer Python-Tabelle

Ergänzend zu meinem vorherigen Blog-Beitrag, in dem es um die Erstellung einer Tabelle in Python geht (Link zum Blog-Beitrag), möchte ich dieses Thema noch einmal aufgreifen und dieser Tabelle zusätzlich mit einer Sortierfunktion ausstatten.

Auch in diesem Beispiel kommen wir nicht drum herum, als Abhängigkeit Python in der Version 3, sowie das Python Modul tkinter zu installieren

sudo apt install python3
sudo apt install python3-tk

Nun folgt der Code für die reine Tabelle ohne Sortierfunktion die folgendermaßen aussieht:

#!/usr/bin/python3

from tkinter import *
from tkinter import ttk

root = Tk()
columns = ['ID', 'Name', 'Bartlänge']
treeview = ttk.Treeview(root, columns=columns, show='headings')
treeview.pack()

tree_value = []
for t in ('3 Fjell Lang', '1 Folkvar Mittellang', '2 Leif Lang', '4 Ingrid Ohne', '5 Knut Kurz', '6 Lagertha Ohne',
          '7 Wulfrik Lang', '8 Gunnhild Ohne', '9 Harald Lang', '10 Halfdan Mittellang'):
    line_list = t.split()
    tree_value.append(line_list)

for i in tree_value:
    treeview.insert('', 'end', values=(i))

treeview.heading(columns[0], text=columns[0])
treeview.heading(columns[1], text=columns[1])
treeview.heading(columns[2], text=columns[2])

mainloop()

Dieser Code erzeugt lediglich die anfängliche Tabelle (bestehend aus 3 Spalten und 10 Zeilen) die nun um die gewünschte Sortierfunktion erweitert werden soll.

Wir beginnen damit, die Spaltenköpfen jeweils mit einer Lambda-Funktion anzureichen. Betroffen davon sind die Zeilen 20-22, was schlußendlich in etwa so aussehen würde:

treeview.heading(columns[0], text=columns[0], command=lambda: treeview_sort_column(columns[0], False))
treeview.heading(columns[1], text=columns[1], command=lambda: treeview_sort_column(columns[1], False))
treeview.heading(columns[2], text=columns[2], command=lambda: treeview_sort_column(columns[2], False))

Diese Lambda-Funktion ruft die Funktion treeview_sort_column auf und gibt dieser die zwei Werte mit: Den ersten, bzw. zweiten bzw. dritten Index-Wert der Liste columns (in diesem Fall wäre das ‚ID‘, ‚Name‘ und ‚Bartlänge‘) und den boolschen Wert False.
Da diese Funktion treeview_sort_column noch gar nicht existiert, wird diese nun nachgereicht.
Nach dem importieren der tkinter Module (also ab Zeile 5) fügen wir nun folgende Funktion ein.

def treeview_sort_column(col, reverse):
    l = []
    for iid in treeview.get_children():
        value_iid = (treeview.set(iid, col), iid)
        l.append(value_iid)

    try:
        l.sort(reverse=reverse, key=lambda l: int(l[0]))
    except:
        l.sort(reverse=reverse)

    for index, (value, iid) in enumerate(l):
        treeview.move(iid, '', index)

    treeview.heading(col, command=lambda: treeview_sort_column(col, not reverse))

An dieser Stelle gehe ich für den neuen Code-Block Zeile für Zeile die einzelnen Funktionen durch und gebe eine Erklärung ab.

Zeile 2 -5:
Jede Zeile ist einer IID zugewiesen (Item identifier). Mit treeview.get_children() werden diese Zeilen IDs in die Variable k gespeichert und weiter nach Treeview und die Liste l überführt, sodass dort nun der Wert und ihre zugehörige IID gesetzt ist (z.B. (‚Lang‘, ‚I001‘), (‚Mittel‘, ‚I002‘) etc.).

Zeile 7 – 10:
Hier wird die Liste l mit der sort Funktion sortiert. Das try except-Statement hilft uns dabei festzustellen, ob es sich bei dem zu sortierendem Wert um eine Zahl, also einen Integer-Wert oder einen String handelt. Auch hier wird dafür die Lambda Funktion verwendet, die versucht den ersten Wert innerhalb des Listenelements in einen String zu verwandeln. Gelingt dies nicht, wird die Liste lediglich sortiert. Ob die Liste aufsteigend oder absteigend sortiert wird, entscheidet der Wert innerhalb der Variable ‚reverse‘, die beim ersten Durchlauf auf False steht, bei einem weiteren Durchlauf auf True und bei nochmal einem weiteren Durchlauf wieder auf False usw..

Zeile 12 – 13:
Damit die sortierten Änderungen auch in die Treeview Liste überschrieben werden, wird die move Funktion von Treeview verwendet. Damit die Daten an diese move Funktion übergeben werden wird die enumerate Funktion von Python verwendet. Über diese Funktion lässt sich der Index und die jeweiligen Werte der Liste l auslesen.

Zeile 15:
Zum Schluß wird die Funktion des treeview.heading (also die Schalftfläche der jeweiligen Spalte) überschrieben und die Variable reverse umgekehrt. Aus False würde also True und aus True würde False werden.

Wichtig an dieser Stelle zu erwähnen ist noch, dass lediglich auf- bzw. absteigend nach dem Alphabet (handelt es sich um String-Werte) oder je nach Größe der Zahl (handelt es sich um einen Integer Wert) sortiert wird. Soll nach anderen Kriterien gefiltert werden, muss der Key-Wert (Zeile 8) entsprechend gesetzt werden.

Der vollständige Code sähe dann folgendermaßen aus …

#!/usr/bin/python3

from tkinter import *
from tkinter import ttk

def treeview_sort_column(col, reverse):
    l = []
    for iid in treeview.get_children():
        value_iid = (treeview.set(iid, col), iid)
        l.append(value_iid)

    try:
        l.sort(reverse=reverse, key=lambda l: int(l[0]))
    except:
        l.sort(reverse=reverse)

    for index, (value, iid) in enumerate(l):
        treeview.move(iid, '', index)

    treeview.heading(col, command=lambda: treeview_sort_column(col, not reverse))

root = Tk()
columns = ['ID', 'Name', 'Bartlänge']
treeview = ttk.Treeview(root, columns=columns, show='headings')
treeview.pack()

tree_value = []
for t in ('3 Fjell Lang', '1 Folkvar Mittellang', '2 Leif Lang', '4 Ingrid Ohne', '5 Knut Kurz', '6 Lagertha Ohne',
          '7 Wulfrik Lang', '8 Gunnhild Ohne', '9 Harald Lang', '10 Halfdan Mittellang'):
    line_list = t.split()
    tree_value.append(line_list)

for i in tree_value:
    treeview.insert('', 'end', values=(i))

treeview.heading(columns[0], text=columns[0], command=lambda: treeview_sort_column(columns[0], False))
treeview.heading(columns[1], text=columns[1], command=lambda: treeview_sort_column(columns[1], False))
treeview.heading(columns[2], text=columns[2], command=lambda: treeview_sort_column(columns[2], False))


mainloop()

… und in bewegten Bildern:

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Nach oben scrollen