Ansichtssache
| Anke (encarsia) | Auch verfügbar in: English
Inhalt
Daten anzeigen mit TreeStore
(Fortsetzung zum ListStore-Artikel)
TreeStore vs. ListStore
Im Gegensatz zum ListStore können Zeilen eines TreeStores ihrerseits Kind-Elemente besitzen, die append
-Funktion benötigt demzufolge ein weiteren Parameter, der einen Bezug zu einer anderen Datenzeile anzeigt:
#append row to liststore store.append([value1, value2, value3]) #append row to treestore store.append(parent, [value1, value2, value3])
Der Wert der Variable parent ist entweder
None, wenn die Zeile keine übergeordnete Zeile besitzt, oder
TreeIter, der zur übergeordneten Zeile zeigt
Der TreeIter wird beim Erstellen einer Zeile erzeugt, untergeordnete Zeilen werden nach folgendem Schema angelegt:
row1 = store.append(None, [value1, value2, value3]) row2 = store.append(row1, [value1, value2, value3])
Man erhält den TreeIter-Wert einer Zeile am einfachsten über die get_selection
-Funktion des Gtk.TreeSelection-Widgets von TreeView (wird automatisch angelegt).
Glade
Im Beispiel werden zwei TreeStores und die jeweils enthaltenen Spalten angelegt, dazu die TreeView-Widgets zur Anzeige.
TreeModelSort
Spalten lassen sich mit der Funktion set_sort_column_id
einfach sortieren. Wendet man diese Funktion direkt auf TreeStore an, werden logischerweise alle TreeView-Widgets, die darauf zurückgreifen, sortiert.
Für diese Fälle muss man TreeModelSort-Elemente "zwischenschalten", d.h. man erstellt aus der Widget-Seitenleiste unter "Sonstiges > Sortierung für Baumansichtsmodell" (4. Eintrag) ein Widget und weist ihm den gewünschten TreeStore zu (einzige Option unter "Allgemein"). Anschließend ersetzt man im TreeView das Modell mit dem eben erstellten TreeModelSort.
Die Sortierungsfunktion führt man wie zuvor, nur auf das TreeModelSort-Objekt, aus.
TreeModelFilter
TreeModelFilter ermöglicht die Darstellung bestimmter Zeilen, in Glade wird wie bei TreeModelSort verfahren, zuerst das Element anlegen (3. Eintrag unter "Sonstige"), anschließend erfolgen die Zuweisungen zum Modell und TreeView.
Im gewählten Beispiel sollen Sorten nach der Fruchtfarbe sortiert werden, es wird also noch ein Container für Buttons benötigt, also eine GtkButtonBox.
Formatierung aus dem Modell laden
Neben den anzuzeigenden Spalten gibt es im ersten TreeStore eine Spalte "weight". Der Wert in dieser Spalte wird dazu verwendet, die Zelle in Fettschrift darzustellen. Dazu wird in den Eigenschaften des CellRenderers unter Schriftgewicht die entsprechende Spalte angegeben (der Wert für normale Schrift ist 400). Analog dazu können beispielsweise auch Zellen eingefärbt oder weitere Schriftformatierungen vorgenommen werden.
Python
TreeModelSort
Durch die Positionsabfrage von GtkTreeSelection.get_selected()
erhält man ein Tupel (model,pos), pos von model zeigt dabei auf TreeModelSort (bzw. analog auf TreeModelFilter), nicht auf TreeStore und erfordert eine Konvertierung:
model, pos = selection.get_selected() converted_iter = treesort.convert_iter_to_child_iter(pos) store.set_value(converted_iter, column, value)
TreeModelFilter
Zunächst muss eine Filterfunktion erstellt werden, in der die Sichtbarkeit von Zeilen definiert wird, im Beispiel also die Variable self.color:
def color_filter_func(self, model, iter, data): if model[iter][2] == self.color: return True else: return False
Die Funktion wird zunächst nach dem Schema
treefilter.set_visible_func(filter_func)
zugewiesen, jede Filterung wird dann per refilter()
ausgelöst, also wenn das Button-Signal ausgelöst wird:
def on_button_clicked(self, widget): x.color = widget.get_label() x.obj("treefilter").refilter()
Listings
Glade
#!/usr/bin/python # -*- coding: utf-8 -*- import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk class Handler: def on_window_destroy(self, *args): Gtk.main_quit() def on_button_clicked(self, widget): x.color = widget.get_label() x.obj("treefilter").refilter() def on_cellrenderer_note_edited(self, widget, row, edit): model, pos = x.obj("selection").get_selected() conv_iter = x.obj("treesort").convert_iter_to_child_iter(pos) x.obj("store").set_value(conv_iter,3,edit) class Example: def __init__(self): self.builder = Gtk.Builder() self.builder.add_from_file("12_treestore.glade") self.builder.connect_signals(Handler()) self.obj = self.builder.get_object #read data from text file with open("12_capsicum.txt") as f: data = [line.strip("\n") for line in f] colors = set() species = set() varieties = [] for line in data: variety = line.split(";") colors.add(variety[2]) species.add(variety[1]) try: variety[3] except IndexError: variety.append("") varieties.append(variety) #append lines to 1st treestore for s in species: counter = 0 row = self.obj("store").append(None, [None, None, None, None, 800, None], ) for v in varieties: if v[1] == s: self.obj("store").append(row, [v[0], v[1], v[2], v[3], 400, None], ) counter += 1 self.obj("store").set_value(row, 0, "{} ({})".format(s, counter)) self.obj("store").set_value(row, 5, counter) #append lines to 2nd treestore [self.obj("filterstore").append(None, [v[0], v[1], v[2]]) for v in varieties] #create buttons in buttonbox for c in colors: button = Gtk.Button.new_with_label(c) button.connect("clicked",Handler().on_button_clicked) self.obj("buttonbox").add(button) self.obj("view").expand_all() self.obj("treesort").set_sort_column_id(5, Gtk.SortType.DESCENDING) self.obj("treefilter").set_visible_func(self.color_filter_func) self.obj("window").show_all() def color_filter_func(self, model, iter, data): if model[iter][2] == self.color: return True else: return False def main(self): Gtk.main() x = Example() x.main()
Python
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.20.0 --> <interface> <requires lib="gtk+" version="3.20"/> <object class="GtkTreeStore" id="filterstore"> <columns> <!-- column-name var --> <column type="gchararray"/> <!-- column-name spec --> <column type="gchararray"/> <!-- column-name color --> <column type="gchararray"/> </columns> </object> <object class="GtkTreeModelFilter" id="treefilter"> <property name="child_model">filterstore</property> </object> <object class="GtkTreeStore" id="store"> <columns> <!-- column-name name --> <column type="gchararray"/> <!-- column-name spec --> <column type="gchararray"/> <!-- column-name color --> <column type="gchararray"/> <!-- column-name note --> <column type="gchararray"/> <!-- column-name weight --> <column type="gint"/> <!-- column-name counter --> <column type="gint"/> </columns> </object> <object class="GtkTreeModelSort" id="treesort"> <property name="model">store</property> </object> <object class="GtkApplicationWindow" id="window"> <property name="width_request">600</property> <property name="height_request">500</property> <property name="can_focus">False</property> <property name="title" translatable="yes">Titel</property> <signal name="destroy" handler="on_window_destroy" swapped="no"/> <child> <object class="GtkBox" id="box"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <property name="spacing">12</property> <property name="homogeneous">True</property> <child> <object class="GtkScrolledWindow"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="shadow_type">in</property> <child> <object class="GtkTreeView" id="view"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="model">treesort</property> <property name="headers_clickable">False</property> <property name="rules_hint">True</property> <child internal-child="selection"> <object class="GtkTreeSelection" id="selection"/> </child> <child> <object class="GtkTreeViewColumn"> <property name="title" translatable="yes">Name</property> <property name="sort_order">descending</property> <property name="sort_column_id">5</property> <child> <object class="GtkCellRendererText"/> <attributes> <attribute name="text">0</attribute> <attribute name="weight">4</attribute> </attributes> </child> </object> </child> <child> <object class="GtkTreeViewColumn"> <property name="title" translatable="yes">Farbe</property> <child> <object class="GtkCellRendererText"/> <attributes> <attribute name="text">2</attribute> </attributes> </child> </object> </child> <child> <object class="GtkTreeViewColumn"> <property name="title" translatable="yes">Bemerkung</property> <child> <object class="GtkCellRendererText" id="cellrenderer_note"> <property name="editable">True</property> <signal name="edited" handler="on_cellrenderer_note_edited" swapped="no"/> </object> <attributes> <attribute name="text">3</attribute> </attributes> </child> </object> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkScrolledWindow"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="shadow_type">in</property> <property name="propagate_natural_width">True</property> <child> <object class="GtkTreeView"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="model">treefilter</property> <child internal-child="selection"> <object class="GtkTreeSelection"/> </child> <child> <object class="GtkTreeViewColumn"> <property name="title" translatable="yes">Sorte</property> <child> <object class="GtkCellRendererText"/> <attributes> <attribute name="text">0</attribute> </attributes> </child> </object> </child> <child> <object class="GtkTreeViewColumn"> <property name="title" translatable="yes">Art</property> <child> <object class="GtkCellRendererText"/> <attributes> <attribute name="text">1</attribute> </attributes> </child> </object> </child> </object> </child> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkButtonBox" id="buttonbox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <property name="layout_style">start</property> <child> <placeholder/> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="padding">5</property> <property name="pack_type">end</property> <property name="position">1</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">2</property> </packing> </child> </object> </child> <child type="titlebar"> <placeholder/> </child> </object> </interface>
Kommentare
Comments powered by Disqus