gtk-rs
Tasks
Development environment
-
Red Hat
dnf install gtk4-devel gcc
Ubuntuapt install libgtk-4-dev build-essential
Boilerplate
-
Interface
<?xml version="1.0" encoding="UTF-8"?> <interface> <requires lib="gtk+" version="3.40"/> <object class="GtkApplicationWindow" id="window"> <property name="title">My GTK App</property> <property name="default-width">300</property> <property name="default-height">300</property> </object> </interface>
use gtk4::{Application, ApplicationWindow}; fn main() { let app = Application::builder() .application_id("com.example.learning-gtk") .build(); app.connect_activate(build_ui); app.run(); } fn build_ui(app: &Application) { let window = ApplicationWindow::builder() .application(app) .default_width(300) .default_height(300) .title("My GTK App") .build(); window.present(); }
Clicker
-
This appears to be a common demonstration of data binding in various GUI frameworks, the code below is taken from here.
use gtk4::prelude::*; use gtk4::{glib, Application, ApplicationWindow, Box, Button, Orientation}; use std::{cell::Cell, rc::Rc}; fn main() { // Create a new application let app = Application::builder() .application_id("org.gtk-rs.example") .build(); // Connect to "activate" signal of `app` app.connect_activate(build_ui); // Run the application app.run(); } fn build_ui(app: &Application) { // Create two buttons let button_increase = Button::builder() .label("Increase") .margin_top(12) .margin_bottom(12) .margin_start(12) .margin_end(12) .build(); let button_decrease = Button::builder() .label("Decrease") .margin_top(12) .margin_bottom(12) .margin_start(12) .margin_end(12) .build(); // Reference-counted object with inner mutability let number = Rc::new(Cell::new(0)); // (1) // Connect callbacks // When a button is clicked, `number` and label of the other button will be changed button_increase.connect_clicked(glib::clone!(@weak number, @weak button_decrease => // (2) move |_| { number.set(number.get() + 1); button_decrease.set_label(&number.get().to_string()); })); button_decrease.connect_clicked(glib::clone!(@weak button_increase => // (3) move |_| { number.set(number.get() - 1); button_increase.set_label(&number.get().to_string()); })); // Add buttons to `gtk_box` let gtk_box = Box::builder().orientation(Orientation::Vertical).build(); gtk_box.append(&button_increase); gtk_box.append(&button_decrease); // Create a window let window = ApplicationWindow::builder() .application(app) .title("My GTK App") .child(>k_box) .build(); // Present the window window.present(); }
- It appears number must be an Rc<Cell>. Changing it to a raw i8 causes compilation errors within glib::clone.
- Removing the weak reference to number causes a compilation error.
- Adding a weak reference to number here also causes a compilation error.
Hello, World!
Window frame
-
TODO
At the moment, this example is broken because I don't know how to pass the string into the Application struct for string interpolation.
use gtk4::prelude::*; use gtk4::{Application, ApplicationWindow}; fn main() { let name = String::new(); if let Some(s) = 42std::env::args().nth(1) { name = s; } else { name = String::from("World"); }; let app = Application::builder() .application_id("com.example.learning-gtk") .build(); app.connect_activate(build_ui); println!("{}", app.name); app.run(); } fn build_ui(app: &Application) { let window = ApplicationWindow::builder() .application(app) .title("Hello, World!") .default_height(300) .default_width(300) .build(); window.present(); }
Button reveal
-
Interface
<?xml version="1.0" encoding="UTF-8"?> <interface> <requires lib="gtk+" version="3.40"> <object class="GtkApplicationWindow" id="window"> <property name="title">My GTK App</property> <property name="default-width">300</property> <property name="default-height">300</property> <child> <object class="GtkButton" id="button"> <property name="label">Press me!</property> <property name="margin-top">12</property> <property name="margin-bottom">12</property> <property name="margin-start">12</property> <property name="margin-end">12</property> </object> </child> </object> </interface>
use gtk::prelude::*; use gtk::{Application, ApplicationWindow, Button}; fn main() { let app = Application::builder() .application_id("org.gtk-rs.example") .build(); app.connect_activate(build_ui); app.run(); } fn build_ui(app: &Application) { let builder = gtk::Builder::from_string(include_str!("window.ui")); let window: ApplicationWindow = builder .object("window") .expect("Could not get object `window` from builder."); let button: Button = builder .object("button") .expect("Could not get object `button` from builder."); window.set_application(Some(app)); button.connect_clicked(move |button| { // (1) button.set_label("Hello World!"); }); window.set_child(Some(&button)); window.show_all(); window.present(); }
- This
move
keyword appears to be unnecessary.
- This
API
glib::clone
-
glib::clone! is used to create closures using strong or weak references.
use glib; use glib_macros::clone; use std::rc::Rc; let v = Rc::new(1); let closure = clone!(@strong v => move |x| { println!("v: {}, x: {}", v, x); }); closure(2);
use glib; use glib_macros::clone; use std::rc::Rc; let u = Rc::new(2); let closure = clone!(@weak u => move |x| { println!("u: {}, x: {}", u, x); }); closure(3);
glib::wrapper
-
glib::wrapper is used to wrap GObjects and figures prominently in the To-Do App. Parent classes must be provided after @extends and any interfaces implemented must be provided after @implements
wrapper! { pub struct $name($kind<$foreign>); // (2) match fn { $fn_name => /* (1) */, ... } }
- Closure-like expressions in the match fn block allow copying, freeing, referencing, and dereferencing the value that is being wrapped.
- There are three possible values for $kind: Boxed (heap allocated types), Shared (records with reference-counted, shared ownership), or Object (classes)
wrapper! { pub struct Button(Object<ffi::GtkButton>) @extends Bin, Container, Widget, @implements Buildable, Actionable; match fn { type_ => || ffi::gtk_button_get_type(), // (1) } }
Action
-
Gio.Action is a way to expose any single task an application or widget does by a name. Classes like Gio.MenuItem and Gtk.ModelButton support properties to set an action name. These actions can be collected into a Gio.ActionGroup.
- Gio.ActionMap are interfaces implemented by Gtk.ApplicationWindow
ActionGroup
Adjustment
-
PyGobject gtk-rs gtk Gtk.Adjustment is not a widget per se but is used in many widgets, including spin buttons, view ports, and children of Gtk.Range.
- page increment and page size refer to actions taken when the user presses PgUp or PgDn
Gtk.Adjustment.new(initial_value, lower_range, upper_range, step_increment, page_increment, page_size)
- page increment and page size refer to actions taken when the user presses PgUp or PgDn
Alignment
-
PyGobject gtk-rs gtk Gtk.Alignment controls the alignment and size of its child widget.
Application
-
PyGobject gtk-rs gtk Gtk.Application gtk4::Application GtkApplication Subclasses of Gtk.Application encapsulate application behavior, including application startup and CLI processing. In practice it is simply a wrapper for the ApplicationWindow class which is instantiated in the
do_activate()
hook. Notably, the Application subclass provides the value for theapplication_id
kwarg passed to the Gtk.Application constructor. This value is validated, and any simple string is not silently accepted.Application must expose several important methods:
do_activate()
def do_activate(self): self.window = ApplicationWindow(application=self, title="Hello, World!") self.window.show_all() self.window.present()
do_startup()
ApplicationWindow
-
PyGobject gtk-rs gtk Gtk.ApplicationWindow gtk4::ApplicationWindow GtkApplicationWindow The Gtk.ApplicationWindow class is the main visible window for the application, and the only window for "single-instance" applications (which is the default). The ApplicationWindow class was introduced in GTK 3.4.
When an action has the prefix
win.
it specifies that the ApplicationWindow subclass will process the signal.
Assistant
-
PyGobject gtk-rs gtk Gtk.Assistant gtk4::Assistant GtkAssistant Gtk.Assistant widgets are used to implement the wizard pattern.
Box
Builder
-
PyGobject gtk-rs gtk Gtk.Builder gtk4::Builder GtkBuilder Gtk.Builder allows the use of interfaces to define widget layouts. Individual UI elements can be bound if they have an id attribute assigned.
fn main() { let app = gtk::Application::builder() .application_id("org.example.gtk-app") .build(); app.connect_activate(build_ui); app.run(); } fn build_ui(app: &Application):{ let builder = gtk::Builder::from_string(include_str!("window.ui")); let window: ApplicationWindow = builder.object("window") .expect("Error loading ApplicationWindow!"); window.set_application(Some(app)); window.show_all(); window.present(); }
class Application(Gtk.Application): def __init__(self, *args, **kwargs): super().__init__(application_id = "org.example.gtk-app") def do_activate(self): builder = Gtk.Builder.new_from_file("window.ui") self.window = builder.get_object("window") self.window.show_all() self.window.present() def run(self): super().run() Gtk.main()
CheckButton
-
PyGobject gtk-rs gtk Gtk.CheckButton gtk4::CheckButton GtkCheckButton Gtk.CheckButtons include checkboxes and (when placed into groups) radio buttons.
Container
-
PyGobject gtk-rs gtk Gtk.Container gtk::Container GtkContainer (3.0) Both Gtk.ApplicationWindow and Gtk.Window classes indirectly derive from the abstract class Gtk.Container. The main purpose of a container subclass is to allow a parent widget to contain one or more child widgets, and there are two types:
Dialog
-
PyGobject gtk-rs gtk Gtk.Dialog provides a convenient way to prompt the user for a small amount of input. It is a widget that can be instantiated and customized in its own right as well as a parent to various subclasses.
dialog = Gtk.Dialog(title="Hello, World!", parent=parent)
Dialogs are split into two parts:
- Content area containing interactive widgets
- Action area containing buttons
These areas are both combined in a vertical Box that is assigned to the
vbox
field. The action area is packed to the end of this vbox, so thepack_start()
method is used to add widgets to the content area.Dialog boxes can be modal, meaning they prevent interaction with the main window while open, or nonmodal.
dialog = Gtk.Dialog(title="Hello, World!", parent=parent, modal=True)
dialog = Gtk.Dialog(title="Hello, World!", parent=parent, modal=False)
Gtk.MessageDialog is a subtype of Dialog meant to simplify the process of creating simple dialogs.
Buttons are added procedurally using
add_button()
, passing a display string (with support for mnemonics using_
) and a ResponseType enum (they once could be added on instantiation by passing a tuple to thebuttons
keyword argument).dialog.add_button("_OK", Gtk.ResponseType.OK)
Methods:
Entry
-
PyGobject gtk-rs gtk Unlike other widgets, Gtk.Entry can be instantiated without using a specific constructor.
entry = Gtk.Entry()
Default text can be provided by passing a string to the text keyword argument or with the
set_text()
setter method:entry = Gtk.Entry(text="Hello, World!")
entry.set_text("Hello, World!")
A password field can be made by concealing text by passing False to visibility or with the
set_visibility()
setter:password = Gtk.Entry(visibility=False)
password.set_visibility(False)
EventBox
-
PyGobject gtk-rs gtk Gtk.EventBox is a container widget that allows event handling for widgets like Gtk.Label that do not have an associated GDK window. The event box can be positioned above or below the windows of its child with
set_above_child()
(False by default.) An EventBox must also have a Gtk.EventMask enum set to specify the type of events the widget may receive. This enum is passed as a value toset_events()
.In the following example, an event handler is connected to the EventBox to handle
button_press_event
. This event handler changes the text of the Label after a double-click.import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk class AppWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.set_border_width(10) self.set_size_request(200, 50) eventbox = Gtk.EventBox.new() label = Gtk.Label.new("Double-Click Me!") eventbox.set_above_child(False) eventbox.connect("button_press_event", self.on_button_pressed, label) eventbox.add(label) self.add(eventbox) eventbox.set_events(Gdk.EventMask.BUTTON_PRESS_MASK) eventbox.realize() def on_button_pressed(self, eventbox, event, label): if event.type == Gdk.EventType._2BUTTON_PRESS: text = label.get_text() if text[0] == 'D': label.set_text("I Was Double-Clicked!") else: label.set_text("Double-Click Me Again!") return False class Application(Gtk.Application): def __init__(self, *args, **kwargs): super().__init__(*args, application_id="org.example.myapp", **kwargs) self.window = None def do_activate(self): if not self.window: self.window = AppWindow(application=self, title="Hello World!") self.window.show_all() self.window.present() if __name__ == "__main__": app = Application() app.run()
FileChooserDialog
-
PyGobject gtk-rs gtk Gtk.FileChooserDialog is one of the important subtypes of Gtk.Dialog. Like other dialogs, it is provided a title and parent window on instantiation. Additionally a FileChooserAction enum must be specified.
FileChooserActions include:
- Gtk.FileChooserAction.SAVE
- Gtk.FileChooserAction.OPEN
- Gtk.FileChooserAction.SELECT_FOLDER
- Gtk.FileChooserAction.CREATE_FOLDER
dialog = Gtk.FileChooserDialog( title="Save file as ...", parent=parent, action=FileChooserAction.SAVE )
Selected files are then retrieved using
dialog.get_filenames()
| Setter | Property | Description | | --------------------------------------------------------------------------------------------------------------------------------- | ----------------- | |
set_current_folder
| | Specify directory in filesystem where FileChooser will start | |set_current_name
| | For FileChooserAction.SAVE, suggest a filename | |set_select_multiple
|select_multiple
| For FileChooserAction.OPEN or SELECT_FOLDER, allow multiple file or folder selections |
Grid
-
PyGobject gtk-rs gtk Gtk.Grid allows children to be packed in a two-dimensional grid. Grids are instantiated with
new()
and widgets are laid out by callingattach()
(see Login for an example).attach()
lay out a widget providing column and row numbers followed by column and row spansgrid.attach(label, 0, 0, 1, 1)
HeaderBar
-
PyGobject gtk-rs gtk Gtk.HeaderBar allows the titlebar to be customized. Like other widgets, it can be configured on instantiation by providing values to keyword arguments or by using setters.
Adding to a window
HeaderBars are added with
set_titlebar()
. This is unlike other widgets which are assigned to an ApplicationWindow or Window usingpack_start()
,pack_end()
, oradd()
,class ApplicationWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) headerbar = Gtk.HeaderBar(title=f"Hello, World!", subtitle="HeaderBar example", show_close_button=True) self.set_titlebar(headerbar)
class ApplicationWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) headerbar = Gtk.HeaderBar() headerbar.set_title(f"Hello, World!") headerbar.set_subtitle("HeaderBar example") headerbar.set_show_close_button(True) self.set_titlebar(headerbar)
Label
-
PyGobject gtk-rs gtk Note that Gtk.Label sets its text with "label" and not "text" as you may expect from the corresponding setter.
label = Gtk.Label(label="Hello, World!")
label.set_text("Hello, World!")
ListBox
-
PyGobject gtk-rs gtk Gtk.ListBox is a vertical container of Gtk.ListBoxRow children used as an alternative to TreeView when the children need to be interactive, as in a list of settings. ListBox
ListStore
-
PyGobject gtk-rs gtk Gtk.ListStore is one of the two major classes that serves as combination schema and database backing Gtk.TreeView, the other being Gtk.TreeStore.
It is instantiated with a sequence of data types, similar to a database schema. These can be standard Python types or GObjects (which are mapped to the Python types anyway):
import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk liststore = Gtk.ListStore((str, int, str))
import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk, GObject liststore = Gtk.ListStore((GObject.TYPE_STRING, GOBject).TYPE_INT, GObject.TYPE_STRING))
This object then exposes an
append
method which is used to add records:liststore.append(["Socrates", 350, "Athens"])
The store is then associated with the treeview with
set_model
treeview.set_model(liststore)
MenuBar
-
PyGobject gtk-rs gtk Gtk.MenuBar is populated with Gtk.MenuItems, corresponding to the expandable menu items (i.e. "File", "Edit", and "Help"). Gtk.Menu is actually used for the submenu, which like MenuBar is also populared with MenuItems. A Menu is attached to the MenuItem of a MenuBar by using the
set_submenu()
method on the Menu object. This setter does not have a corresponding kwarg, so all menus have to be constructed procedurally.import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk class AppWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.set_size_request(250, -1) menubar = Gtk.MenuBar.new() self.add(menubar) file = Gtk.MenuItem.new_with_label("File") menubar.append(file) filemenu = Gtk.Menu.new() file.set_submenu(filemenu) new = Gtk.MenuItem.new_with_label("New") open = Gtk.MenuItem.new_with_label("Open") filemenu.append(new) filemenu.append(open) edit = Gtk.MenuItem.new_with_label("Edit") menubar.append(edit) editmenu = Gtk.Menu.new() edit.set_submenu(editmenu) cut = Gtk.MenuItem.new_with_label("Cut") copy = Gtk.MenuItem.new_with_label("Copy") paste = Gtk.MenuItem.new_with_label("Paste") editmenu.append(cut) editmenu.append(copy) editmenu.append(paste) help = Gtk.MenuItem.new_with_label("Help") menubar.append(help) helpmenu = Gtk.Menu.new() help.set_submenu(helpmenu) contents = Gtk.MenuItem.new_with_label("Help") about = Gtk.MenuItem.new_with_label("About") helpmenu.append(contents) helpmenu.append(about) class Application(Gtk.Application): def __init__(self, *args, **kwargs): super().__init__(*args, application_id="org.example.myapp", **kwargs) self.window = None def do_activate(self): if not self.window: self.window = AppWindow(application=self, title="Menu Bars") self.window.show_all() self.window.present() if __name__ == "__main__": app = Application() app.run()
Notebook
-
PyGobject gtk-rs gtk Gtk.Notebook is a layout container that organizes content into tabbed pages. It is instantiated with the
new()
method and pages are appended with theappend_page()
method, passing content and label widgets as arguments.The tab bar can be placed using
set_tab_pos()
, passing a Gtk.PositionType enumnotebook = Gtk.Notebook.new() # notebook.set_tab_pos(Gtk.PositionType.TOP)
notebook = Gtk.Notebook.new() notebook.set_tab_pos(Gtk.PositionType.RIGHT)
notebook = Gtk.Notebook.new() notebook.set_tab_pos(Gtk.PositionType.BOTTOM)
notebook = Gtk.Notebook.new() notebook.set_tab_pos(Gtk.PositionType.LEFT)
notebook = Gtk.Notebook.new() label = Gtk.Label.new("Tab title") child = Gtk.Label.new("Tab content") notebook.append_page(child, label)
The label widget is commonly Gtk.Label but can also be a Gtk.Box.
The tab bar can be made scrollable using
set_scrollable()
, passing a bool.
Scale
-
PyGobject gtk-rs gtk Gtk.Scale widgets are sliders, and they can be instantiated in one of two ways:
new()
passing an Adjustment objectnew_with_range(min, max, step)
passing values for minimum, maximum, and step
Scale values are stored as doubles, so integers have to be simulated by reducing the number of digits to 0 using
set_digits()
. By default, the number of digits is set to that of the step value.
ScrolledWindow
-
PyGobject gtk-rs gtk Gtk.ScrolledWindow is a decorator container that accepts a single child widget. Widgets that implement the Gtk.Scrollable interface have native scrolling suppport, like Gtk.TreeView, Gtk.TextView, and Gtk.Layout. Other widgets have to use Gtk.Viewport as an adaptor, and must be added to a Viewport which is then added to the ScrolledWindow.
It is instantiated with the
new()
method, optionally passing two Adjustment objects that affect horizontal and vertical scrolling behavior when stepping or paging.scrolled_win = Gtk.ScrolledWindow.new(None,None)
Statusbar
-
PyGobject gtk-rs gtk Gtk.Statusbar gtk4::Statusbar GtkStatusbar (4.0) Gtk.Statusbar (note the lowercase b ) stores a stack of messages, the topmost of which is displayed. Before adding messages, a context identifier, a unique unsigned integer associated with a context description string, must be retrieved from the newly created Statusbar by passing a string value to
get_context_id()
. This allows messages to be categorized and pushed to separate stacks.statusbar.push(context_id, message)
Switch
-
PyGobject gtk-rs gtk Gtk.Switch gtk4::Switch GtkSwitch (4.0) Gtk.Switch allows a user to toggle a boolean value. Switch exposes getters and setters for both state (which is represented by the trough color) and active (switch position) properties. State is the backend to activ, and they are kept in sync.
import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk class ApplicationWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.set_border_width(10) box_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) listbox = Gtk.ListBox(selection_mode=Gtk.SelectionMode.NONE) row = Gtk.ListBoxRow() hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) label1 = Gtk.Label(label="Automatic Date & Time", xalign=0) hbox.add(label1) self.switch = Gtk.Switch(valign=Gtk.Align.CENTER, state=False) hbox.add(self.switch) row.add(hbox) listbox.add(row) box_outer.add(listbox) self.add(box_outer) button = Gtk.Button(label="Click") button.connect("clicked", self.on_button_clicked) box_outer.add(button) def on_button_clicked(self, button): print(f"Value of get_active(): {self.switch.get_active()}") print(f"Value of get_state(): {self.switch.get_state()}") class Application(Gtk.Application): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.window = None def do_activate(self): if not self.window: self.window=ApplicationWindow(application=self) self.window.show_all() self.window.present() if __name__ == "__main__": app = Application() app.run()
TreeView
-
PyGobject gtk-rs gtk Gtk.TreeView gtk4::TreeView GtkTreeView (4.0) GtkTreeView (3.0) In order to create a tree or list in GTK, the Gtk.TreeView widget is paired with a Gtk.TreeModel interface, the most typical implementation of which is Gtk.ListStore or Gtk.TreeStore. TreeView is a complicated widget that must be constructed procedurally:
- Gtk.TreeView is instantiated. A ListStore is specified as data model and passed in as the value of the model kwarg.
The ListStore specifies the schema of the data as a collection of types.
Alternatively, the ListStore can be specified after instantiation.
treeview = Gtk.TreeView(model=Gtk.ListStore.new((str)))
treeview = Gtk.TreeView.new() treeview.set_model(Gtk.ListStore.new([str]))
- A Gtk.TreeViewColumn is created for every column in the model. These require a Gtk.CellRenderer to be defined. The TreeViewColumn is added to the treeview by calling the
append_column()
method on the treeview. The text kwarg appears to refer to the column of the data store to use for the column's values.treeview.append_column(Gtk.TreeViewColumn("Greeks", Gtk.CellRendererText.new(), text=0))
- Items are added to the ListStore procedurally using the
append()
method. Note that the method takes only a single argument, so collections like lists or tuples must be used.liststore.append(("Socrates",)) liststore.append(("Plato",)) liststore.append(("Aristotle",))
Changing the number of columns affects the types used to define the ListStore, the appended records, as well as the number of columns added to the TreeView itself.
import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk class ApplicationWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.gen_treeview() scrolled_win = Gtk.ScrolledWindow.new(None,None) scrolled_win.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scrolled_win.add(self.treeview) self.add(scrolled_win) self.set_size_request(200,200) def get_liststore(self): store = Gtk.ListStore.new((str,)) store.append(("Socrates",)) store.append(("Plato",)) store.append(("Aristotle",)) return store def gen_treeview(self): self.treeview = Gtk.TreeView.new() self.treeview.set_model(self.get_liststore()) self.treeview.append_column(Gtk.TreeViewColumn("Greeks", Gtk.CellRendererText.new(), text=0)) class Application(Gtk.Application): def __init__(self): super().__init__(application_id='org.example.myapp') def do_activate(self): self.window = ApplicationWindow(application=self, title="Greeks") self.window.show_all() self.window.present() if __name__ == '__main__': app = Application() app.run()
import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk class ApplicationWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.gen_treeview() scrolled_win = Gtk.ScrolledWindow.new(None,None) scrolled_win.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scrolled_win.add(self.treeview) self.add(scrolled_win) self.set_size_request(200,200) def get_liststore(self): store = Gtk.ListStore.new((str, str)) store.append(["Socrates", "Athens"]) store.append(["Plato", "Athens"]) store.append(["Aristotle", "Athens"]) return store def gen_treeview(self): self.treeview = Gtk.TreeView.new() self.treeview.set_model(self.get_liststore()) self.treeview.append_column(Gtk.TreeViewColumn("Greeks", Gtk.CellRendererText.new(), text=0)) self.treeview.append_column(Gtk.TreeViewColumn("Place of birth", Gtk.CellRendererText.new(), text=1)) class Application(Gtk.Application): def __init__(self): super().__init__(application_id='org.example.myapp') def do_activate(self): self.window = ApplicationWindow(application=self, title="Greeks") self.window.show_all() self.window.present() if __name__ == '__main__': app = Application() app.run()
The model backing a TreeView (usually a ListStore), can be retrieved with the
get_model()
method.treeview.get_model().append(('foo','bar'))
TreeView emits several signals:
row_activated
when a row is double-clicked, with the following implicit argumentwidget
refering to the emitting TreeView widget itselfpath
is a TreePath.column
is of type TreeViewcolumntreeview.connect("row_activated", self.on_row_activated, widget, path, column)
def on_row_activated(self, widget, path, column): row = path.get_indices()[0] print(f"row={path.get_indices()[0]},col={column.props.title}") print(widget.get_model()[row][:])
- Gtk.TreeView is instantiated. A ListStore is specified as data model and passed in as the value of the model kwarg.
The ListStore specifies the schema of the data as a collection of types.
TreePath
-
PyGobject gtk-rs gtk Gtk.TreePath is a type used to implement the rows of a TreeView. Although it prints to an integer with the print statement, it cannot be treated as one.
A path object can be passed as the index to a TreeModel like ListStore, as can an integer. The row number of a TreePath from a normal list-style TreeView can be retrieved with the
get_indices()
method.row = path.get_indices()[0] # Using TreePath object as index to model model[path][:] # Using row integer as index to model model[row][:]
Another method on TreePath,
get_depth()
always returns 1 for list-style TreeViews, but may be more useful for tree-style TreeViews.
TreeSelection
-
PyGobject gtk-rs gtk Gtk.TreeSelection objects represent selection information for each tree view.
TreeViewColumn
-
PyGobject gtk-rs gtk Gtk.TreekViewColumn gtk4::TreeViewColumn GtkTreeViewColumn (4.0) GtkTreeViewColumn (3.0) Gtk.TreeViewColumn represents a visible column in a Treeview. Its props property exposes many associated values, including title.
A column is made sortable by callingprint(column.props.title)
set_sort_column_id()
, passing the column of the model to sort by.column.set_sort_column_id(0)
Window
-
PyGobject gtk-rs gtk Gtk.Window gtk4::Window GtkWindow (4.0) GtkWindow (3.0)