NoN: progress
Knights of Ni - progress
As said before I am currently working on a GUI for Nikola doing some progress:
removed titlebar, using headerbar instead
switch between multiple Nikola instances
bookmark local Nikola instances (only adding for now)
- support for multilinual sites:
display of configured languages
show existent translations in posts/pages tab
"Translation" tab: show files, generate new translation file for post/page (this is somehow redundant to the posts/pages tab, I still think about it...)
if there is no title the "Title" column will show the slug or (if this does not exist neither) filename
some mor log messages to pretent important things happen
Translating articles
As soon as I figured out multilinguality in Nikola I will translate the tutorial series into English.
...
Well, that was kinda easy...(but I will need some time for translation and writing new stuff and improving the new project).
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.
Dialogues
Contents
Handle dialogue windows
Dialogues are complementary windows which are useful in interaction with the user, to show some relevant information or demand input. The GtkDialog class provides subclasses for common dialogue use cases like the AboutDialog and MessageDialog used in the example file. (FileChooserDialog article).
Glade
In the widget sidebar dialog widgets are integrated to the "Toplevel" section next to window widgets.
Dialogs are complementary windows to grab the user's focus. They can fixed to a superordinated window but at least be configured transient to a parent window via General > Window Attributes Transient For:".
AboutDialog
The "About" dialog window in general gives information about the project, its version, license, participating programmers, translators etc. All this can be directly typed into Glade.
MessageDialog
The MessageDialog is a standard dialog to show information or call for input. It is configurated to be drawn without window decoration or showing up seperately in the taskbar. Furthermore there is the possibility to add standard buttons.
Buttons and responses
Dialogs already own an intern GtkButtonBox to place any buttons in.
In constrast to regular windows the clicked signals of the buttons do not have to be assigned in these Buttonboxes (it's still possible to do so, of course). Instead in the "General" button properties you define a response answer (int) and assign the response signal of the GtkDialog.
Standard buttons available for example in MessageDialogs have a fixed response (see also Python GI API Reference):
Ok -5
Abort -6
Close -7
Yes -8
No -9
[X] -4
The huge advantage of that procedure is that the response refers to the dialog object so the responses can be processed by a single function.
Reestablish dialogues
The problem of windows closed via destroy signal is that they cannot be reactivated therefore the delete-event signal is used here.
Python
Responses
When emitting the response signal the response is passed as parameter. As said before this offers the option to process all responses in one function:
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
The hide_on_delete()
function removes a window but can be reestablished by show_all()
:
def on_dialog_delete_event(self,widget,event): widget.hide_on_delete() return True
Several Glade files
As mentioned before several Glade files can be used within a project. It is not possible though to associate dialogs with their parent window if separated into different files. So the set_transient_for
function of GtkWindow is required:
dialog.set_transient_for(mainwindow)
Data view
Contents
Display TreeStore data
(Continuation of the ListStore article)
TreeStore vs. ListStore
In contrast to ListStores TreeStore rows can possess child rows. That's why the append
function requires another parameter that specifies the parent row reference:
#append row to liststore store.append([value1,value2,value3]) #append row to treestore store.append(parent,[value1,value2,value3])
The parent value is either
None if the current row is not a child row of another, or
TreeIter pointing to the superordinate row.
The TreeIter value is generated when creating a row, subordinate rows are created by
row1 = store.append(None,[value1,value2,value3]) row2 = store.append(row1,[value1,value2,value3])
The TreeIter of a cell is obtained by calling the get_selection
function of the automatically generated GtkTreeSelection widget.
Glade
In the example there are two TreeStores with some columns and the coresponding TreeView widgets to display the data columns.
TreeModelSort
Sorting a column is set by calling set_sort_column_id
. If this is applied to the TreeStore all TreeView widgets using this store are equally sorted.
If this behaviour is not diesired TreeModelSort elements come into play and which are "interposed" between store and view widgets. First the TreeModelSort is created via "Miscellaneous > Tree Model Sort" from the widget sidebar. Then you choose a source TreeView to use data from. After that the model in the TreeView widget is replaced by the newly created TreeModelSort.
The sort function is now simply applied to the TreeModelSort object instead to the TreeView object.
TreeModelFilter
TreeModelFilter allows to only show data that matches the specified filter criteria. Handling this object is analogue to TreeModelSort.
In the example the varieties can be filtered according to fruit colour so there is a GtkButtonBox required to put the corresponding buttons into.
Load formatting values from the model
Besides the columns containing displayed data there is a "weight" column in the first TreeStore. This value is used to show the cell in bold text. It is realized by setting the CellRenderer's property of "Font weight" to the column containing the corresponding value (normal font is 400). In this way the appearance of cells can be defined, for example colours or font formating.
Python
TreeModelSort
Requesting a position by calling GtkTreeSelection.get_selected()
returns a tuple (model, pos), pos of model points to TreeModelSort (or TreeModelFilter) and requires conversion to the TreeStore position:
model,pos = selection.get_selected() converted_iter = treesort.convert_iter_to_child_iter(pos) store.set_value(converted_iter,column,value)
TreeModelFilter
First of all a filter function is required defining the visibility of cells, in the example it's the variable self.color:
def color_filter_func(self,model,iter,data): if model[iter][2] == self.color: return True else: return False
This function has to be assigned to TreeFilter
treefilter.set_visible_func(filter_func)
A filter process is then executed by calling the refilter()
function on the TreeFilter object:
def on_button_clicked(self,widget): x.color = widget.get_label() x.obj("treefilter").refilter()
New project: Knights of Ni
Knights of Ni - small managing tool for the static website generator Nikola
New little project made of Glade and Python on GitHub: Knights of Ni.
Exterminate!
The VTE terminal widget
Glade
The widget can be found in the lower part of the widget side bar and provides a complete terminal emulator. To close the window on the exit
command the child-exited signal has to be assigned.
A button click shall open a Python prompt within the terminal window, so we need the familiar clicked signal.
Python
Elements used in Glade that are not part of the Gtk module have to be registered as a GObject object (this is also required when using a GtkSourceView widget as the functionality is provided by the GtkSource module):
GObject.type_register(Vte.Terminal)
The terminal emulator is initiated by calling spawn_sync
expecting 7 parameters. Detailed information on the parameters are available in the documentation but for a common start a lot of defaults and Nones will do:
terminal.spawn_sync( Vte.PtyFlags.DEFAULT, None, ["/bin/bash"], None, GLib.SpawnFlags.DEFAULT, None, None, )
The feed_child
function must be called to send a command to the console. The expected parameters are the string including a newline and the length of the string:
command = "python\n" x.terminal.feed_child(command,len(command))
YouNiversity: Transforming Code into Beautiful, Idiomatic Python
Romani ite domum
Contents
Localization with gettext and locale
Glade
Strings in widgets are by default configurated as translatable so there are no preparations required. GetText directly provercesses Glade project files.
Python
Translatable strings
Approved translatable strings are recognized by xgettext
by brackets with a leading underscore:
_ = gettext.gettext translatable_string = _("translate me")
configure (bind)textdomain
Now name and location of the MO files have to be configured in the source code:
locale.bindtextdomain(appname,locales_dir) locale.textdomain(locales_dir) gettext.bindtextdomain(appname,locales_dir) gettext.textdomain(appname) builder.set_translation_domain(appname)
set_translation_domain
has to be called before loading Glade files.
GetText
POT
POT is the abbrevation for Portable Object Template. This file contains all original translatable strings. After generating an empty POT file, xgettext
is executed for all source files containing translatable strings:
$ xgettext --options -o output.pot sourcefile.ext
The identified strings are added to the POT file.
#: sourcefile.ext:line number msgid "translatable string" msgstr ""
The file number reference comment can be avoided by passting the option --no-location
.
In this article's example it is required to run xgettext once for the Glade file and once for the Python source code; the -j
(--join-existing
) option adds new found strings to an existing file:
$ xgettext --sort-output --keyword=translatable --language=Glade -j -o 10_localization/TUT.pot 10_lokalisation.glade $ xgettext --language=Python -j -o 10_localization/TUT.pot 10_lokalisation.py
PO
Translated strings are stored in a PO file per language. A new translation ist invoked by
$ msginit --input=source.pot --locale=xx # xx=language code
that generates a file after the pattern xx.po (p.e. de.po). This file can be edited in any text editor or dedicated tools such like PoEdit. A German localization for example is created by the command
$ msginit --input=TUT.pot --locale=de
If the POT file is altered the PO files are updated with the new strings by executing msgmerge
:
$ msgmerge lang.po template.pot > new_lang.po
MO
MO files are (machine readable) binary files and mandatory for gettext to work. Localization files are located below the bindtextdomain following the file structure path/to/bindtextdomain)/locale/language code/LC_MESSAGES/appname.po
.
In the example the bindtextdomain is created in the local directory, the generated de.po translation text file then transformed into the corresponding MO file:
$ msgfmt --output locale/de/LC_MESSAGES/TUT.mo de.po
Tipps
xgettext options
--no-location
-
Oppress writing line number(s) and file name as comment
--omit-header
-
Avoid overwriting header information
Remove obsolete strings
Strings that are removed from the template remain in the translation files. You can get rid of these by executing this command:
$ msgattrib --set-obsolete --ignore-file=PRJ.pot -o xx.po xx.po
ListStore
Store data sets in ListStores and use ComboBox and TreeView to display the data
There are a bunch of elements required to store and display tables of data in GTK+ applications:
- The model to administrate data. There are two types:
ListStore: flat table, besides string and numerical values the rows also can be of GTK+ element type (like buttons or checkboxes), input of data sets in Glade possible
TreeStore: just like ListStore but rows can possess child rows, input of data sets in Glade is not possible (see also TreeStore article)
- Widgets:
TreeView: show, sort and edit data; used by both store model types; a data store can be used my multiple TreeView widgets
ComboBox: comboboxes are used to limit input to given list items, this list can be stored in a List/TreeStore (see also spinbutton and combobox article)
CellRenderers: Subwidgets to specify source, layout and other properties (like being editable) of displayed data rows
Glade
ListStore
In the example there is one ListStore created via "Miscellaneous > List Store" which will be later used by three Widgets.
First there are some rows created. ListStore data sets can be inserted in Glade but this in practise is only convenient for typing in few data sets.
Content changes in the ListStore are simultaneously updated in the Widgets using the ListStore. For individual sorting of the same List/TreeStore it is needed to create Gtk.TreeModelSort elements (this element is used in the example of the TreeStore article).
Widgets
- ComboBox
-
Creating the widget you are prompted to choose as "TreeView Model". In the edit mode accessible via "Edit > Hierarchy" there is created a CellRendererText. In the first field ("Text") the column to load the items of the dropdown menu from is set. To process the selection you will need the changed signal.
- TreeView #1
-
The first TreeView widget is placed within a Gtk.ScrolledWindow container. Like in a ComboBox there are created CellRenderers representing a column to show in the TreeView table. If the sort indicator is activated columns can be sorted on a column table click. Columns do not have to be sorted according to the columns they show.
- TreeView #2
-
The second TreeView widget is created within a Gtk.ViewPort. This container widget does not provide scroll bars but the automatically adapts the necessary size to display the whole content. So for larger tables you will need the Gtk.ScrolledWindow. The sort indicator is deactivated and the middle column ("Description") is made editible with the signal "edited" allocated.
- Button
-
The button's function is appending a row to the ListStore, so the clicked signal is required.
Python
TreeStore
The ListStore's row can be iterated over via for row in store
. New rows are added by append
, other options are insert
or remove
to add or delete rows at specific positions.
ComboBox
For accessing a data row you need a Gtk.TreeIter object which points to the position in the model (this can also be achieved by a Gtk.TreePath object).
iter,model = widget.get_active_iter(),widget.get_model() row = model[iter] print("Selection:",row[0])
Edit cells
The edited signal passes the position and content of the edited cell. The new content of the CellRendererText has to explicitly be committed to the data store otherwise the content will return to the pre edit state. This can be accomplished by using the passed TreePath position.
def on_cellrenderer_descr_edited(self,widget,pos,edit): x.store[int(pos)][1] = edit