Pygobject
Tasks
Development environment
-
dnf install python3-venv python3-wheel dnf install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel git python3-cairo-devel cairo-gobject-devel gobject-introspection-devel pip install pygobject
apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0 libgirepository1.0-dev pip install pygobject
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>
import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # (1) class ApplicationWindow(Gtk.ApplicationWindow): # (2) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # (3) self.set_size_request(300,300) self.set_title("My GTK App") self.show_all() self.present() class Application(Gtk.Application): def __init__(self): super().__init__(application_id='org.example.learning-gtk') # (4) def do_activate(self): self.window = ApplicationWindow(application=self) if __name__ == '__main__': app = Application() # (5) app.run() # (6)
- Note that the gi module's
require_version()
function must be called before importing Gtk. - The recommended way of using the PyGTK API is to subclass and modify the Application and ApplicationWindow classes. These were introduced in GTK+ versions 3.0 and 3.4 respectively and are meant to be used as base classes. PyGTK also offers an alternative Gtk.Window class, which like ApplicationWindow is a subclass of Gtk.Container, and which still appears in many tutorials.
- The ApplicationWindow subclass calls the superclass's constructor. The UI is composed by adding widgets to this subclass by calling
self.add()
. Typically a single Box container is added to the top-level container and controls are added to that container. - The Application subclass also calls its superclass's constructor and exposes a
do_activate()
method that instantiates the ApplicationWindow subclass and assigns that object toself.window
before callingself.window.present()
. The Application subclass essentially acts as a wrapper around ApplicationWindow. - At the script's entrypoint, the Application subclass itself is instantiated and its
run
method is called. - In online tutorials that use Window, typically the Application wrapper class does not appear. The
Gtk.main()
method must be called somewhere in the script in order for the UI to appear.
- Note that the gi module's
Dice roller
-
import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk import random from math import floor class ApplicationWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) scale_adj = Gtk.Adjustment.new(1, 0, 6, 1, 2, 0) self.scale = Gtk.Scale.new(Gtk.Orientation.HORIZONTAL, scale_adj) self.scale.set_digits(0) button = Gtk.Button.new_with_label("Throw") button.connect("clicked", self.on_button_clicked) self.label = Gtk.Label.new() box = Gtk.Box.new(Gtk.Orientation.VERTICAL,5) box.pack_start(self.scale, False, True, 0) box.pack_start(button, False, True, 0) box.pack_start(self.label, False, True, 0) self.add(box) self.set_size_request(200,200) def on_button_clicked(self, button): dice = floor(self.scale.get_value()) results = [random.randrange(6) for i in range(dice)] self.label.set_text(str(results)) class Application(Gtk.Application): def __init__(self): super().__init__(application_id='org.example.myapp') def do_activate(self): self.window = ApplicationWindow(application=self) self.window.show_all() self.window.present() if __name__ == '__main__': app = Application() app.run()
MenuBar
-
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()
Login
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_size_request(300,300) grid = Gtk.Grid.new() image = Gtk.Image.new_from_icon_name("dialog-password", Gtk.IconSize.DIALOG) grid.attach(image, 0, 0, 1, 1) grid.attach(Gtk.Label(label="Enter your credentials."), 0, 1, 2, 1) grid.attach(Gtk.Label(label="User name:"), 0, 2, 1, 1) grid.attach(Gtk.Entry(), 1, 2, 1, 1) grid.attach(Gtk.Label(label="Password:"), 0, 3, 1, 1) grid.attach(Gtk.Entry(visibility=False), 1, 3, 1, 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="Hello, World!") self.window.show_all() self.window.present() if __name__ == "__main__": app = Application() app.run()
Hello, World!
import sys
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self, *args, name, **kwargs):
super().__init__(*args, **kwargs)
self.set_default_size(300,300)
self.set_title(f"Hello, {name}!")
self.show_all()
class Application(Gtk.Application):
def __init__(self, name):
super().__init__(application_id="com.example.learning-gtk")
self.name = name
def do_activate(self):
self.window = ApplicationWindow(application=self, name=self.name)
if __name__ == '__main__':
if len(sys.argv) > 1:
app = Application(sys.argv[-1])
else:
app = Application("World")
app.run()
import sys
import gi
gi.require_version("Gtk","3.0")
from gi.repository import Gtk
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self, *args, name, **kwargs):
super().__init__(*args, **kwargs)
self.set_size_request(300, 300)
self.add(Gtk.Label(label=f"Hello, {name}!"))
class Application(Gtk.Application):
def __init__(self, name = "World", *args, **kwargs):
self.name = name
super().__init__(*args, application_id="org.example.myapp", **kwargs)
def do_activate(self):
self.window = ApplicationWindow(application=self, name = self.name, title = "Hello, World!")
self.window.show_all()
self.window.present()
if __name__ == '__main__':
if len(sys.argv) > 1:
app = Application(sys.argv[-1])
else:
app = Application("World")
app.run()
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>
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='org.example.myapp')
def do_activate(self):
builder = Gtk.Builder.new_from_file('hw-button.ui')
self.window = builder.get_object('window')
self.button = builder.get_object('button')
self.button.connect('clicked', self.on_button_clicked)
self.window.connect('destroy', Gtk.main_quit)
self.window.show_all()
self.window.present()
def on_button_clicked(self, button):
self.button.set_label('Hello, World!')
def run(self):
super().run()
Gtk.main()
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)
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
self.add(box)
question = Gtk.Label.new("What is your name?")
box.add(question)
self.entry = Gtk.Entry(text="World")
box.add(self.entry)
button = Gtk.Button.new_with_mnemonic("Greet")
button.connect("clicked", self.on_button_clicked, self)
box.add(button)
def on_button_clicked(self, button, parent):
dialog = Gtk.MessageDialog(
message_type=Gtk.MessageType.INFO,
text=f"Hello, {parent.entry.get_text()}",
parent=parent,
)
dialog.add_button("OK", Gtk.ResponseType.OK)
dialog.run()
dialog.destroy()
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='org.example.myapp')
def do_activate(self):
self.window = ApplicationWindow(application=self)
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
import sys
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_default_size(-1, -1)
# headerbar = Gtk.HeaderBar(title=f"Hello, {name}!", subtitle="HeaderBar example", show_close_button=True)
headerbar = Gtk.HeaderBar()
headerbar.set_title(f"Hello, World!")
headerbar.set_subtitle("HeaderBar example")
headerbar.set_show_close_button(True)
self.set_titlebar(headerbar)
button = Gtk.Button(label="Greet")
button.connect("clicked", self.on_button_clicked, self)
headerbar.add(button)
self.entry = Gtk.Entry(text="World", name="entry")
headerbar.add(self.entry)
def on_button_clicked(self, button, parent):
dialog = Gtk.MessageDialog(
message_type=Gtk.MessageType.INFO,
text=f"Hello, {parent.entry.get_text()}!",
parent=parent,
)
dialog.add_button("O_K", Gtk.ResponseType.OK)
dialog.run()
dialog.destroy()
class HeaderBar(Gtk.Application):
def __init__(self):
super().__init__(application_id="org.example.headerbar")
def do_activate(self):
self.window = ApplicationWindow(application=self)
self.window.show_all()
self.window.present()
if __name__ == '__main__':
app = HeaderBar()
app.run()
Starships
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)
ships = ['USS Enterprise', 'USS Defiant', 'USS Voyager']
self.treeview = Gtk.TreeView(model=Gtk.ListStore.new((str,)))
column = Gtk.TreeViewColumn("Ship", Gtk.CellRendererText(), text=0)
self.treeview.append_column(column)
for s in ships:
self.treeview.get_model().append((s,))
self.add(self.treeview)
self.set_size_request(-1,-1)
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='org.example.myapp')
def do_activate(self):
self.window = ApplicationWindow(application=self)
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
import csv
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
with open('/home/jasper/dogfood/csv/starships.csv',mode='r') as f:
reader = csv.reader(f)
self.headers = [h.title() for h in next(reader)]
self.data = [r for r in reader]
self.treeview = Gtk.TreeView(model=Gtk.ListStore.new((str,str,str,str)))
for h in self.headers:
column = Gtk.TreeViewColumn(h, Gtk.CellRendererText(), text=self.headers.index(h))
self.treeview.append_column(column)
for r in self.data:
self.treeview.get_model().append(r)
self.treeview.connect('row-activated', self.on_row_activated)
self.add(self.treeview)
self.set_size_request(-1,-1)
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='org.example.myapp')
def do_activate(self):
self.window = ApplicationWindow(application=self)
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
import csv
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
with open('/home/jasper/dogfood/csv/starships.csv',mode='r') as f:
reader = csv.reader(f)
self.headers = [h.title() for h in next(reader)]
self.data = [r for r in reader]
self.treeview = Gtk.TreeView(model=Gtk.ListStore.new((str,str,str,str)))
for h in self.headers:
column = Gtk.TreeViewColumn(h, Gtk.CellRendererText(), text=self.headers.index(h))
column.set_sort_column_id(self.headers.index(h))
self.treeview.append_column(column)
for r in self.data:
self.treeview.get_model().append(r)
self.treeview.connect('row-activated', self.on_row_activated)
self.add(self.treeview)
self.set_size_request(-1,-1)
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='org.example.myapp')
def do_activate(self):
self.window = ApplicationWindow(application=self)
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
import csv
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
with open('/home/jasper/dogfood/csv/starships.csv',mode='r') as f:
reader = csv.reader(f)
self.headers = [h.title() for h in next(reader)]
self.data = [r for r in reader]
self.treeview = Gtk.TreeView(model=Gtk.ListStore.new((str,str,str,str)))
for h in self.headers:
column = Gtk.TreeViewColumn(h, Gtk.CellRendererText(), text=self.headers.index(h))
column.set_sort_column_id(self.headers.index(h))
self.treeview.append_column(column)
for r in self.data:
self.treeview.get_model().append(r)
self.treeview.connect('row-activated', self.on_row_activated)
self.add(self.treeview)
self.set_size_request(-1,-1)
def on_row_activated(self, treeview, path, col):
model = treeview.get_model()
print(f'Using path object as index to model: {model[path][:]}')
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='org.example.myapp')
def do_activate(self):
self.window = ApplicationWindow(application=self)
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
import csv
class ApplicationWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
with open('/home/jasper/dogfood/csv/starships.csv',mode='r') as f:
reader = csv.reader(f)
self.headers = [h.title() for h in next(reader)]
self.data = [r for r in reader]
self.treeview = Gtk.TreeView(model=Gtk.ListStore.new((str,str,str,str)))
for h in self.headers:
column = Gtk.TreeViewColumn(h, Gtk.CellRendererText(), text=self.headers.index(h))
column.set_sort_column_id(self.headers.index(h))
self.treeview.append_column(column)
for r in self.data:
self.treeview.get_model().append(r)
self.treeview.connect('row-activated', self.on_row_activated)
self.add(self.treeview)
self.set_size_request(-1,-1)
def on_row_activated(self, treeview, path, col):
model = treeview.get_model()
dialog = Gtk.MessageDialog(
message_type=Gtk.MessageType.INFO,
text=model[path][:],
parent = self
)
dialog.add_button("OK", Gtk.ResponseType.OK)
dialog.run()
dialog.destroy()
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='org.example.myapp')
def do_activate(self):
self.window = ApplicationWindow(application=self)
self.window.show_all()
self.window.present()
if __name__ == '__main__':
app = Application()
app.run()