NoN: Fortschritte

Knights of Ni - Fortschritte

Wie bereits erwähnt, bastel ich aktuell an einer GUI für Nikola, die einige Fortschritte vorzuweisen hat:

  • Titelleiste entfernt, da Headerbar benutzt wird
  • Wechseln zwischen Nikola-Instanzen (zuletzt benutzte wird gespeichert)
  • Bookmarkfunktion (bislang können nur Bookmarks hinzugefügt werden, bei Bedarf manuell aus der config entfernen)
  • Untersützung für mehrsprachige Seiten:
  • Anzeige der Standardsprache und der konfigurierten anderen Sprachen
  • Posts/Pages-Tab zeigt Vorhandensein von Übersetzungen an
  • Tab "Translations" zeigt vorhandene Dateien an
  • per Rechtsklick können neue Übersetzungen angelegt werden, dabei wird der Ausgangsbeitrag gemäß entsprechendem Dateimuster gespeichert
  • ich weiß noch nicht, wie sinnvoll dieser separate Tab ist (Redundanz) und ob ich ihn beibehalte
  • hat der Artikel keinen Titel, wird das interne Kürzel (slug) oder, falls ebenfalls nicht vorhanden, der Dateiname angezeigt
  • gesprächiges Log, um vorzutäuschen, dass ganz viel wichtiger Kram passiert
/images/non2.thumbnail.png

Das läuft aus meiner Sicht schon alles erstaunlich gut. Dummerweise habe ich bei der Verwendung von Glade (und auch Python, aber vor allem Glade) inzwischen ebenfalls einige Fortschritte gemacht, was mich ernsthaft zur Überlegung geführt hat, das GoProTool nochmal zu überarbeiten. Die Oberfläche würde ich belassen, aber viel Funktionalität könnte effizienter umgesetzt werden. Ich stelle das mal hinten an.

Geplant ist nun ein simples Nikola-unabhängiges Vorlagensystem und anschließend ist etwas Fleißarbeit bei der Lokalisation erforderlich.

Artikelübersetzungen

Sobald ich herausgefunden habe, wie Multilingualität in Nikola funktioniert, werde ich die Tutorialartikel ins Englische übersetzen.

Nachtrag: okay, war war einfach...

YouNiversity: Python Tricks

Daniel Bader zeigt auf seinem YouTube-Kanal allerlei Nützliches zum Thema Python.

Aktuell gibt es sein in Arbeit befindliches Buch "Python Tricks. The Book" gerade zum unschlagbaren Preis von 9 $ (+ 1,71 $ deutsche Umsatzsteuer): Klick

Es bestehen keine persönlichen oder/und finanziellen Verbindungen.

Dialoge

Anzeige von Dialogfenstern

Dialoge sind ergänzende Fenster zur Anwendung und dienen der Interaktion mit dem Benutzer, in denen Informationen angezeigt werden oder Eingaben vom Benutzer abgefragt werden können. Die GtkDialog-Klasse bietet einige Unterklassen für gebräuchliche Anzeigen und Abfragen, wie die im Beispiel verwendeten About- und MessageDialog (Artikel zum FileChooserDialog).

/images/13_dialoge.thumbnail.png

Glade

Dialog-Widgets findet man unter "Oberste Ebene" neben den Fenster-Widgets.

Dialoge sind ergänzende Fenster, um den Fokus des Nutzers zu lenken. Sie können direkt an ein übergeordnetes Fenster angeheftet werden, mindestens aber müssen sie unter "Allgemein > Fensterattribute > Vorübergehend für:" einem Eltern-Fenster zugeordnet werden. Sie erscheinen dadurch nicht als separates Fenster in der Übersicht und erben ein vorhandenes Icon.

AboutDialog

Das "About"-Dialogfenster bietet in der Regel Informationen zum Projekt, darunter Version, Lizenz, beteiligte Programmierer, Übersetzer etc. Dies alles lässt sich sehr einfach direkt in Glade angeben.

MessageDialog

Der MessageDialog ist ein Standarddialog zum Anzeigen oder Abfragen von Informationen. Er ist so konfiguriert, dass er keine eigene Fensterdekoration besitzt und nicht als Fenster in der Taskbar erscheint. Außerdem bietet er die Möglichkeit, Standardbuttons einzurichten.

Buttons und Responses

Dialoge besitzen bereits intern über eine GtkButtonBox, die mit beliebigen Buttons befüllt werden kann. Dieser Bereich ist als "intern action_area" gekennzeichnet.

Im Gegensatz zu Buttons in normalen Fenstern müssen in Dialogen keine Signale auf clicked angelegt werden, sondern man legt in den Button-Eigenschaften unter "Allgemein" eine Antwortkennung (Response) fest (int) und belegt das Signal response des GtkDialog.

Standardbuttons wie im MessageDialog auswählbar besitzen eine vorgegebene Response (siehe Python GI API Reference):

  • Ok -5
  • Abbrechen -6
  • Schließen -7
  • Ja -8
  • Nein -9
  • [X] -4

Der große Vorteil der Responses besteht darin, dass sie sich direkt auf das Dialog-Objekt beziehen; man kann die Responses in einer Funktion verarbeiten und muss dies nicht für jeden einzelnen Button vornehmen.

Wiederherstellbare Dialoge

Das Problem von per destroy-Signal geschlossenen Fenstern besteht darin, dass sie sich nicht wieder aufrufen lassen. Deshalb wird stattdessen das Signal delete-event belegt.

Python

Responses

Beim Auslösen des response-Signals wird die Antwortkennung als Parameter übergeben, so kann wie bereits erwähnt, jede innerhalb einer einzelnen Funktion verarbeitet werden:

def on_dialog_response(self,widget,response):
    if response == 0:
        widget.hide_on_delete()
    elif response == 1:
        do.something()
    elif response == (2 or 3):
        do.something.different()

Delete-event

Mit der Funktion hide_on_delete() ausgeblendete Dialoge oder reguläre Fenster lassen sich mit show_all() wieder anzeigen:

def on_dialog_delete_event(self,widget,event):
    widget.hide_on_delete()
    return True

Mehrere Glade-Dateien

Wie bereits erwähnt, können mehrere Dateien für Fenster und Dialoge innerhalb eines Projektes verwendet werden. Allerdings ist es nicht möglich, diese dateiübergreifend aneinanderzubinden, es wird die set_transient_for-Funktion von GtkWindow benötigt:

dialog.set_transient_for(mainwindow)

Weiterlesen…

Ansichtssache

Daten anzeigen mit TreeStore

(Fortsetzung zum ListStore-Artikel)

/images/12_treestore.thumbnail.png

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 GtkTreeSelection-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()

Weiterlesen…