Previous Post | Top | Next Post |
TOC
Example: Special button widgets into GUI
To put more widgets,“Number of items” on the left panel of GtkBox was incremented. Some box are further subdivided again with GtkBox with their “Orientation” settings set to “Horizontal” instead.
Then I placed several additional simple “Control” widgets:
- GtkSpinButton under the “Control” button
- GtkToggleButton under the “Control” button
- GtkCheckButton under the “Control” button
- GtkRadioButton under the “Control” button
- GtkFileChooserButton under the “Control” button
Please note I created multiple widgets to learn how they work together with the object.
I set IDs for these widgets basically by dropping “Gtk” from the GTk class names with optional number as suffix to distinguish them. Then set up signal handlers in the right panel.
ID/Class name | Widget | Signal | Signal handler |
---|---|---|---|
simple | GtkWindow | destroy | onDestroy |
button | GtkButton | pressed | onButtonPressed |
entry | GtkEntry | changed | onEntryChanged |
spinbutton? | GtkSpinButton | changed | onSpinButtonChanged? |
togglebutton? | GtkToggleButton | toggled | onToggleButtonToggled? |
checkbutton? | GtkCheckButton | toggled | onCheckButtonToggled? |
radiobutton? | GtkRadioButton | toggled | onRadioButtonToggled |
filechooserbutton | GtkFileChooserButton | selection-changed | onFileChooserButtonChanged |
label | GtkLabel | — | — |
There are some non-obvious extra works other with Glade usage.
GtkSpinButton widget needs to click on the pen-icon in the “Adjustment” entry box to open dialog and create a new Adjustment object “adjustment1” for spinbutton1. Although normally each spinbutton? has its own adjustment?", just for learning, let me set the same Adjustment object “adjustment1” for spinbutton2. These 2 spin buttons now function in parallel since they share the same Adjustment object “adjustment1”.
GtkToggleButton widget can display icon instead of just a text label by clicking “Always show image” checkbox and clicking on the pen-icon in the “Image” entry box to open dialog and create a new GtkImage object “image1” for togglebutton1. When setting “Image”, somehow my Glade focus on deprecated “Stock ID”. Just click radio button for “Icon name” and select one you like. Do the same for another to create a new GtkImage object “image2”. If you put null string to the text label, this becomes a clean small icon button.
GtkCheckButton widget is very much like GtkToggleButton except for presentation of its state and area to click.
GtkRadioButton widget with round icon is visually very much like GtkCheckButton with square icon but has quite unique feature of exclusivity. This is realized by grouping these controls. Click on the pen-icon in the “Group” entry box for RadioButton2 and RadioButton3 widgets and select RadioButton1 as their Group choice.
GtkFileChooserButton
widget has 2 modes of operations determined by “FileChooserAttribute” to be
either “Open” or “Select Folder”. Let’s set this to “Select Folder”. (Somehow
my Glade version 3.38.2 tends to skip updating menu. So I end up setting it
multiple times and checking the resulting XML file for <property name="action">select-folder</property>
by a text editor.)
How to create GUI program
Now we are ready to use this from simple2.py
:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
@Gtk.Template(filename="simple2.ui")
class SimpleWindow(Gtk.Window):
# corresponding name in XML 'class' attribute for this class
__gtype_name__ = "simple2"
# corresponding name in XML 'id' attribute sets this class member variable
label = Gtk.Template.Child()
# class member variables
entry_text = "(null as init)"
spin1_text = "0 (init)"
spin2_text = "0 (init)"
toggle1_text = "___ off ___ (init)"
toggle2_text = "___ off ___ (init)"
check1_text = "___ off ___ (init)"
check2_text = "___ off ___ (init)"
radio_text = "radiobutton1 (init)"
folder = "(null as init)"
@Gtk.Template.Callback()
def onDestroy(self, *args):
Gtk.main_quit()
@Gtk.Template.Callback()
def onButtonPressed(self, widget):
print("=" * 80)
print("Button label: " + widget.get_label())
print("Entered text: " + self.entry_text)
print("Spin1 value : " + self.spin1_text)
print("Spin2 value : " + self.spin2_text)
print("Toggle1 text: " + self.toggle1_text)
print("Toggle2 text: " + self.toggle2_text)
print("Check1 text : " + self.check1_text)
print("Check2 text : " + self.check2_text)
print("Radio text : " + self.radio_text)
print("Folder : " + self.folder)
# This is right, I think.
self.label.set_label(self.entry_text)
@Gtk.Template.Callback()
def onEntryChanged(self, widget):
self.entry_text = widget.get_text()
@Gtk.Template.Callback()
def onSpinButton1Changed(self, widget):
self.spin1_text = str(widget.get_value_as_int())
@Gtk.Template.Callback()
def onSpinButton2Changed(self, widget):
self.spin2_text = str(widget.get_value_as_int())
@Gtk.Template.Callback()
def onToggleButton1Toggled(self, widget):
if widget.get_active():
self.toggle1_text = "@@@ ON @@@"
else:
self.toggle1_text = "___ off ___"
@Gtk.Template.Callback()
def onToggleButton2Toggled(self, widget):
if widget.get_active():
self.toggle2_text = "@@@ ON @@@"
else:
self.toggle2_text = "___ off ___"
@Gtk.Template.Callback()
def onCheckButton1Toggled(self, widget):
if widget.get_active():
self.check1_text = "@@@ ON @@@"
else:
self.check1_text = "___ off ___"
@Gtk.Template.Callback()
def onCheckButton2Toggled(self, widget):
if widget.get_active():
self.check2_text = "@@@ ON @@@"
else:
self.check2_text = "___ off ___"
@Gtk.Template.Callback()
def onRadioButtonToggled(self, widget):
if widget.get_active():
self.radio_text = widget.get_label()
@Gtk.Template.Callback()
def onFileChooserButtonSet(self, widget):
self.folder = widget.get_filename()
window = SimpleWindow()
window.show()
Gtk.main()
Running this with python3 simple2.py
will start the GUI as:
Please play with this GUI while looking at your terminal outputs.
How Glade generated XML looks
Just in case I forget which items were selected via Glade session, here is the
Glade generated XML simple2.ui
:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkAdjustment" id="adjustment1">
<property name="upper">100</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">format-justify-left</property>
</object>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">format-justify-fill</property>
</object>
<template class="simple2" parent="GtkWindow">
<property name="can-focus">False</property>
<signal name="destroy" handler="onDestroy" swapped="no"/>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkButton" id="button">
<property name="label" translatable="yes">Press this to update</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="pressed" handler="onButtonPressed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<signal name="changed" handler="onEntryChanged" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkSpinButton" id="spinbutton1">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="adjustment">adjustment1</property>
<signal name="changed" handler="onSpinButton1Changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spinbutton2">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="adjustment">adjustment1</property>
<signal name="changed" handler="onSpinButton2Changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkToggleButton" id="togglebutton1">
<property name="label" translatable="yes">togglebutton1</property>
<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="toggled" handler="onToggleButton1Toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="togglebutton2">
<property name="label" translatable="yes">togglebutton2</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="image">image2</property>
<property name="always-show-image">True</property>
<signal name="toggled" handler="onToggleButton2Toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkCheckButton" id="checkbutton1">
<property name="label" translatable="yes">checkbutton1</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
<signal name="toggled" handler="onCheckButton1Toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="checkbutton2">
<property name="label" translatable="yes">checkbutton2</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
<signal name="toggled" handler="onCheckButton2Toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkRadioButton" id="radiobutton1">
<property name="label" translatable="yes">radiobutton1</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<signal name="toggled" handler="onRadioButtonToggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="radiobutton2">
<property name="label" translatable="yes">radiobutton2</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<property name="group">radiobutton1</property>
<signal name="toggled" handler="onRadioButtonToggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="radiobutton3">
<property name="label" translatable="yes">radiobutton3</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<property name="group">radiobutton1</property>
<signal name="toggled" handler="onRadioButtonToggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkFileChooserButton" id="filechooserbutton">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="action">select-folder</property>
<property name="title" translatable="yes"/>
<signal name="file-set" handler="onFileChooserButtonSet" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
</object>
</child>
</template>
</interface>
Previous Post | Top | Next Post |