Stacks and notebooks
| Anke (encarsia) | Also available in: Deutsch
Organize contents on screen
Gtk.Stack and Gtk.Notebook are layout containers that can hold any widgets.
A notebook provides a multipage layout including a classic tab functionality. A stack also provides this basic functionality and you will able to switch between different layout pages.
The main difference is the control widget of the stack is a separate widget (Gtk.StackSwitcher). Several stack switcher widgets can be assigned to one stack. A stack switcher can be placed into the headerbar and animated transitions between stack pages are supported.
Stack subjectively fit better into the GNOME environment but notebooks provide more customization/functionality options.
In the example there is a window containing a stack including a notebook on the third page showing different websites.
Glade
Stack
Stacks can be found in the sidebar's 'Container' section. Pages are easily created and edited via Glade. Sub-widgets in the example file are Gtk.Image, Vte.Terminal and Gtk.Notebook.
The stack switcher widget can be obtained from 'Controls and Display' and is placed to the headerbar. It's also possible to put it into a regular container widget like boxes. Pages can be shown in vertical or horizontal order. In "General > Stack" a stack element must be assigned to the widget. The page name shown by the stack switcher widget can be edited via "Packing > Title" of the sub-widget. This sub-widget has to be created in the first place, a new created stack has empty pages.
Notebook
Notebook can also be found in the 'Container' section. The tab's control unit is an integrated label child widget automatically generated on page creation. Gtk.ScrolledWindows are used here as the pages' container widgets. These are also required for displaying (long) tables (see also List-/TreeStore articles No. 1 und No. 2).
The tab bar of a notebook provides reserved space for additional widgets like fixed buttons ("General > Start/End Action"). In the example there will be created a "Home" button in the start area.
Python
There are no signals required for switching between stack pages and notebook tabs. In the example only two signals are assigned, one for catching the "exit" command within the terminal and one for the button in the notebook tab bar.
WebKit2
The webpages in the example are rendered by WebKit2. The essential module to use is WebKit2.WebView
. A new WebView object itself already is a scrollable Gtk+ widget within a Gtk.Viewport element. According to the API reference it does not have to be placed in a Gtk.ScrolledWindow container widget. Having tested this that works for Gtk.Stack but not for Gtk.Notebook. That's why in the example there is used a ScrolledWindow as underlying container widget.
The following pattern is used to create a WebView widget:
#create new WebView widget webview = WebKit2.WebView() #send URL to widget webview.load_uri("http://google.com") #add webview to notebook notebook.add(webview) #add webview to stack stack.add_titled(webview, name, "StackSwitcher title") webview.show()
Listings
Python
#!/usr/bin/python # -*- coding: utf-8 -*- import sys import urllib.request import gi gi.require_version("Gtk", "3.0") gi.require_version("Vte", "2.91") gi.require_version("WebKit2", "4.0") from gi.repository import Gtk, Gio, Vte, GObject, GLib, WebKit2 class Handler: def on_term_child_exited(self, widget, event): # reset and setup terminal on exit command widget.reset(True, True) app.stack_console() def on_home_button_clicked(self, widget): # reload given URL in current tab page = app.obj("notebook").get_current_page() app.nbtabs[page][2].load_uri(app.nbtabs[page][1]) class ExampleApp: def __init__(self): self.app = Gtk.Application.new("org.application.test", Gio.ApplicationFlags(0)) self.app.connect("activate", self.on_app_activate) def on_app_activate(self, app): GObject.type_register(Vte.Terminal) builder = Gtk.Builder() builder.add_from_file("21_stacknotebook.glade") builder.connect_signals(Handler()) self.obj = builder.get_object self.obj("window").set_application(app) self.obj("window").show_all() # get window content self.stack_image() self.stack_console() self.stack_notebook() def run(self, argv): self.app.run(argv) def stack_image(self): # download and show NASA Astonomy Picture of the Day URL = "https://apod.nasa.gov" source = urllib.request.urlopen(URL).read().decode("utf-8") img_start = source.find("<IMG SRC=") img_end = source.find("alt=") img = source[img_start+10:img_end-2] IMGURL = "https://apod.nasa.gov/apod/" + img urllib.request.urlretrieve(IMGURL, "apod.jpg") self.obj("image").set_from_file("apod.jpg") def stack_console(self): # setup terminal self.obj("term").spawn_sync( Vte.PtyFlags.DEFAULT, None, ["/bin/bash"], None, GLib.SpawnFlags.DEFAULT, ) def stack_notebook(self): self.nbtabs = [ ["gi_doc", "https://lazka.github.io/pgi-docs/"], ["gtk_tut", "http://python-gtk-3-tutorial.readthedocs.io/en/latest/index.html"], ["glade_tut", "https://encarsia.github.io/posts/tutorial-reihe-glade/"] ] for tab in self.nbtabs: webview = WebKit2.WebView() tab.append(webview) webview.load_uri(tab[1]) self.obj(tab[0]).add(webview) webview.show() app = ExampleApp() app.run(sys.argv)
Glade
21_stacknotebook.glade (Source)
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.20.1 --> <interface> <requires lib="gtk+" version="3.20"/> <requires lib="vte-2.91" version="0.50"/> <object class="GtkImage" id="image1"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="icon_name">go-home</property> </object> <object class="GtkApplicationWindow" id="window"> <property name="width_request">800</property> <property name="height_request">600</property> <property name="can_focus">False</property> <child> <object class="GtkStack" id="stack"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="transition_type">crossfade</property> <child> <object class="GtkImage" id="image"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="stock">gtk-missing-image</property> </object> <packing> <property name="name">page0</property> <property name="title" translatable="yes">Astronomy Picture of the Day</property> </packing> </child> <child> <object class="VteTerminal" id="term"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="hscroll_policy">natural</property> <property name="vscroll_policy">natural</property> <property name="encoding">UTF-8</property> <property name="scroll_on_keystroke">True</property> <property name="scroll_on_output">False</property> <signal name="child-exited" handler="on_term_child_exited" swapped="no"/> </object> <packing> <property name="name">page3</property> <property name="title" translatable="yes">Terminal</property> <property name="position">1</property> </packing> </child> <child> <object class="GtkNotebook" id="notebook"> <property name="visible">True</property> <property name="can_focus">True</property> <child> <object class="GtkScrolledWindow" id="gi_doc"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="shadow_type">in</property> <child> <placeholder/> </child> </object> </child> <child type="tab"> <object class="GtkLabel"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">PyGObject API Reference </property> </object> <packing> <property name="tab_fill">False</property> </packing> </child> <child> <object class="GtkScrolledWindow" id="gtk_tut"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="shadow_type">in</property> <child> <placeholder/> </child> </object> <packing> <property name="position">1</property> </packing> </child> <child type="tab"> <object class="GtkLabel"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Python GTK+ 3 Tutorial</property> </object> <packing> <property name="position">1</property> <property name="tab_fill">False</property> </packing> </child> <child> <object class="GtkScrolledWindow" id="glade_tut"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="shadow_type">in</property> <child> <placeholder/> </child> </object> <packing> <property name="position">2</property> </packing> </child> <child type="tab"> <object class="GtkLabel"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Glade-Tutorial</property> </object> <packing> <property name="position">2</property> <property name="tab_fill">False</property> </packing> </child> <child type="action-start"> <object class="GtkButton" id="home_button"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="image">image1</property> <property name="always_show_image">True</property> <signal name="clicked" handler="on_home_button_clicked" swapped="no"/> </object> <packing> <property name="tab_fill">False</property> </packing> </child> </object> <packing> <property name="name">page1</property> <property name="title" translatable="yes">Notebook</property> <property name="position">2</property> </packing> </child> </object> </child> <child type="titlebar"> <object class="GtkHeaderBar"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="show_close_button">True</property> <child> <object class="GtkStackSwitcher"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="stack">stack</property> </object> </child> </object> </child> </object> </interface>
Comment on
Comments
Comments powered by Disqus