### GTK4 Label Widget Example
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/display-widgets/label.md
Demonstrates various Gtk.Label configurations including alignment, justification, line wrapping, and Pango markup. This example requires a GTK application setup.
```Python
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
class LabelWindow(Gtk.ApplicationWindow):
def __init__(self, **kargs):
super().__init__(**kargs, title="Label Demo")
box = Gtk.Box(spacing=10)
self.set_child(box)
box_left = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
spacing=10,
hexpand=True,
homogeneous=True,
)
box_right = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
box.append(box_left)
box.append(box_right)
label = Gtk.Label(label="This is a normal label")
box_left.append(label)
label = Gtk.Label(
label="This is a normal label with xalign set to 0",
xalign=0,
)
box_left.append(label)
label = Gtk.Label(
label="This is a left-justified label.\nWith multiple lines.",
justify=Gtk.Justification.LEFT,
)
box_left.append(label)
label = Gtk.Label(
label="This is a right-justified label.\nWith multiple lines.",
justify=Gtk.Justification.RIGHT,
)
box_left.append(label)
label = Gtk.Label(
label="This is an example of a line-wrapped label. It "
"should not be taking up the entire "
"width allocated to it, but automatically "
"wraps the words to fit.\n"
" It supports multiple paragraphs correctly, "
"and correctly adds "
"many extra spaces. ",
wrap=True,
max_width_chars=32,
)
box_right.append(label)
label = Gtk.Label(
label="This is an example of a line-wrapped, filled label. "
"It should be taking "
"up the entire width allocated to it. "
"Here is a sentence to prove "
"my point. Here is another sentence. "
"Here comes the sun, do de do de do.\n"
" This is a new paragraph.\n"
" This is another newer, longer, better "
"paragraph. It is coming to an end, "
"unfortunately.",
wrap=True,
justify=Gtk.Justification.FILL,
max_width_chars=32,
)
box_right.append(label)
label = Gtk.Label(wrap=True, max_width_chars=48)
label.set_markup(
"Text can be small, big, "
"bold, italic and even point to "
'somewhere in the internets.'
)
box_left.append(label)
button = Gtk.Button(label="Click at your own risk")
label = Gtk.Label(
label="_Press Alt + P to select button to the right",
use_underline=True,
selectable=True,
mnemonic_widget=button,
)
box_left.append(label)
box_right.append(button)
def on_activate(app):
win = LabelWindow(application=app)
win.present()
app = Gtk.Application(application_id="com.example.App")
app.connect("activate", on_activate)
app.run(None)
```
--------------------------------
### Menu Popover Example
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/popovers.md
Illustrates creating a Gtk.MenuButton that displays a Gtk.PopoverMenu populated from a Gio.MenuModel defined in XML. This setup is common for application menus.
```XML
```
```Python
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gio, Gtk
# This would typically be its own file
MENU_XML = """
"
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.set_default_size(300, 200)
headerbar = Gtk.HeaderBar()
self.set_titlebar(headerbar)
builder = Gtk.Builder.new_from_string(MENU_XML, -1)
menu_model = builder.get_object("app-menu")
button = Gtk.MenuButton(menu_model=menu_model)
headerbar.pack_end(button)
class Application(Gtk.Application):
def __init__(self, **kwargs):
super().__init__(application_id="com.example.App", **kwargs)
self.window = None
def do_startup(self):
Gtk.Application.do_startup(self)
action = Gio.SimpleAction(name="about")
action.connect("activate", self.on_about)
self.add_action(action)
action = Gio.SimpleAction(name="quit")
action.connect("activate", self.on_quit)
self.add_action(action)
def do_activate(self):
# We only allow a single window and raise any existing ones
if not self.window:
# Windows are associated with the application
# when the last one is closed the application shuts down
self.window = AppWindow(application=self, title="Main Window")
self.window.present()
def on_about(self, action, param):
about_dialog = Gtk.AboutDialog(transient_for=self.window, modal=True)
about_dialog.present()
def on_quit(self, action, param):
self.quit()
app = Application()
app.run(None)
```
--------------------------------
### Set Up Python Virtual Environment and Install Dependencies
Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md
Create a virtual environment and install necessary build tools and libraries for PyGObject development with Pip.
```console
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install meson-python meson ninja pycairo pytest pre-commit
```
--------------------------------
### GTK4 Layout Containers Example
Source: https://context7.com/gnome/pygobject/llms.txt
Demonstrates the use of Gtk.Box, Gtk.Grid, Gtk.Stack, and Gtk.ListBox for arranging widgets in a GTK4 application. Includes setup for application, window, header bar, and interactive elements like a stack switcher and a sortable/filterable list box.
```python
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, GObject
class LayoutDemo(Gtk.ApplicationWindow):
def __init__(self, **kwargs):
super().__init__(**kwargs, title="Layout Demo", default_width=600, default_height=400)
# Outer vertical box
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6,
margin_top=12, margin_bottom=12,
margin_start=12, margin_end=12)
self.set_child(vbox)
# --- HeaderBar as titlebar ---
header = Gtk.HeaderBar()
header.pack_start(Gtk.Button(label="Back"))
header.pack_end(Gtk.Button(icon_name="open-menu-symbolic"))
self.set_titlebar(header)
# --- Grid ---
grid = Gtk.Grid(column_spacing=6, row_spacing=6)
for col in range(3):
for row in range(2):
btn = Gtk.Button(label=f"[{col},{row}]")
grid.attach(btn, col, row, 1, 1)
vbox.append(grid)
# --- Stack + StackSwitcher ---
stack = Gtk.Stack(transition_type=Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
stack_switcher = Gtk.StackSwitcher(stack=stack)
header.set_title_widget(stack_switcher)
page_a = Gtk.Label(label="Page A content", vexpand=True)
page_b = Gtk.Label(label="Page B content", vexpand=True)
stack.add_titled(page_a, "a", "Page A")
stack.add_titled(page_b, "b", "Page B")
vbox.append(stack)
# --- ListBox with sort/filter ---
listbox = Gtk.ListBox(selection_mode=Gtk.SelectionMode.SINGLE, show_separators=True)
for word in ["Zebra", "Apple", "Mango", "Beta", "Cherry"]:
row = Gtk.ListBoxRow()
row.set_child(Gtk.Label(label=word, xalign=0))
row.data = word
listbox.append(row)
listbox.set_sort_func(lambda r1, r2: r1.data.lower() > r2.data.lower())
listbox.set_filter_func(lambda row: not row.data.startswith("B"))
listbox.connect("row-activated", lambda lb, row: print("Selected:", row.data))
vbox.append(listbox)
def on_activate(app):
LayoutDemo(application=app).present()
app = Gtk.Application(application_id="com.example.Layout")
app.connect("activate", on_activate)
app.run(None)
```
--------------------------------
### Gtk.Application Example
Source: https://context7.com/gnome/pygobject/llms.txt
Demonstrates the usage of Gtk.Application for managing application lifecycle, setting up menus, and handling command-line arguments.
```APIDOC
## Gtk.Application — Application lifecycle and window management
`Gtk.Application` is the entry point for every GTK application. It handles instance uniqueness, D-Bus activation, startup/shutdown lifecycle, menus, and command-line parsing. Override `do_startup()` to set up actions and menus, and `do_activate()` to create the first window. Use `Gio.ApplicationFlags` to control instance behavior.
```python
import sys
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import GLib, Gio, Gtk
MENU_XML = """
"""
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_default_size(400, 300)
self.props.show_menubar = True
# Window-scoped action with state ("win.maximize")
max_action = Gio.SimpleAction.new_stateful(
"maximize", None, GLib.Variant.new_boolean(False)
)
max_action.connect("change-state", self.on_maximize_toggle)
self.add_action(max_action)
self.label = Gtk.Label(label="Hello World")
self.set_child(self.label)
def on_maximize_toggle(self, action, value):
action.set_state(value)
self.maximize() if value.get_boolean() else self.unmaximize()
class Application(Gtk.Application):
def __init__(self, *args, **kwargs):
super().__init__(
*args,
application_id="org.example.App",
flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
**kwargs,
)
self.window = None
self.add_main_option(
"verbose", ord("v"),
GLib.OptionFlags.NONE, GLib.OptionArg.NONE,
"Enable verbose output", None,
)
def do_startup(self):
Gtk.Application.do_startup(self)
action = Gio.SimpleAction.new("about", None)
action.connect("activate", lambda a, p: None)
self.add_action(action)
action = Gio.SimpleAction.new("quit", None)
action.connect("activate", lambda a, p: self.quit())
self.add_action(action)
builder = Gtk.Builder.new_from_string(MENU_XML, -1)
self.set_menubar(builder.get_object("menubar"))
def do_activate(self):
if not self.window:
self.window = AppWindow(application=self, title="My App")
self.window.present()
def do_command_line(self, command_line):
options = command_line.get_options_dict().end().unpack()
if "verbose" in options:
print("Verbose mode enabled")
self.activate()
return 0
if __name__ == "__main__":
app = Application()
app.run(sys.argv)
```
```
--------------------------------
### Setup Application Startup Actions
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/application.md
Configures actions for 'about' and 'quit' during application startup. It also loads the menu bar from an XML string.
```python
action = Gio.SimpleAction.new("about", None)
action.connect("activate", self.on_about)
self.add_action(action)
```
```python
action = Gio.SimpleAction.new("quit", None)
action.connect("activate", self.on_quit)
self.add_action(action)
```
```python
builder = Gtk.Builder.new_from_string(MENU_XML, -1)
self.set_menubar(builder.get_object("menubar"))
```
--------------------------------
### Gtk.FlowBox Example
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/layout-widgets.md
Demonstrates creating a Gtk.FlowBox and populating it with color swatch buttons. This example shows how to set up the FlowBox, add children, and define custom drawing for child widgets.
```Python
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Gdk
class FlowBoxWindow(Gtk.ApplicationWindow):
def __init__(self, **kargs):
super().__init__(**kargs, title="FlowBox Demo")
self.set_default_size(300, 250)
header = Gtk.HeaderBar()
self.set_titlebar(header)
scrolled = Gtk.ScrolledWindow()
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
self.set_child(scrolled)
flowbox = Gtk.FlowBox(
valign=Gtk.Align.START,
max_children_per_line=30,
selection_mode=Gtk.SelectionMode.NONE,
)
scrolled.set_child(flowbox)
self.create_flowbox(flowbox)
def draw_button_color(self, area, cr, width, height, rgba):
cr.set_source_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha)
cr.rectangle(0, 0, width, height)
cr.fill()
def color_swatch_new(self, str_color):
rgba = Gdk.RGBA()
rgba.parse(str_color)
button = Gtk.Button(tooltip_text=str_color)
area = Gtk.DrawingArea()
area.set_size_request(24, 24)
area.set_draw_func(self.draw_button_color, rgba)
button.set_child(area)
return button
def create_flowbox(self, flowbox):
colors = [
"AliceBlue",
"AntiqueWhite",
"AntiqueWhite1",
"AntiqueWhite2",
"AntiqueWhite3",
"AntiqueWhite4",
"aqua",
"aquamarine",
"aquamarine1",
"aquamarine2",
"aquamarine3",
"aquamarine4",
"azure",
"azure1",
"azure2",
"azure3",
"azure4",
"beige",
"bisque",
"bisque1",
"bisque2",
"bisque3",
"bisque4",
"black",
"BlanchedAlmond",
"blue",
"blue1",
"blue2",
"blue3",
"blue4",
"BlueViolet",
"brown",
"brown1",
"brown2",
"brown3",
"brown4",
"burlywood",
"burlywood1",
"burlywood2",
"burlywood3",
"burlywood4",
"CadetBlue",
"CadetBlue1",
"CadetBlue2",
"CadetBlue3",
"CadetBlue4",
"chartreuse",
"chartreuse1",
"chartreuse2",
"chartreuse3",
"chartreuse4",
"chocolate",
"chocolate1",
"chocolate2",
"chocolate3",
"chocolate4",
"coral",
"coral1",
"coral2",
"coral3",
"coral4",
]
for color in colors:
button = self.color_swatch_new(color)
flowbox.append(button)
def on_activate(app):
# Create window
win = FlowBoxWindow(application=app)
win.present()
app = Gtk.Application(application_id="com.example.App")
app.connect("activate", on_activate)
app.run(None)
```
--------------------------------
### Install PyGObject on Ubuntu/Debian with pip
Source: https://context7.com/gnome/pygobject/llms.txt
Install system packages for development and then use pip to install PyGObject within a virtual environment.
```bash
sudo apt install libgirepository-2.0-dev gcc libcairo2-dev pkg-config python3-dev gir1.2-gtk-4.0
pip3 install pycairo PyGObject
```
--------------------------------
### GTK4 Entry Controls Example
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/controls/entries.md
Demonstrates the usage of Gtk.Entry, Gtk.SearchEntry, and Gtk.PasswordEntry with various configurations and interactive controls.
```Python
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, GLib
class EntryWindow(Gtk.ApplicationWindow):
def __init__(self, **kargs):
super().__init__(**kargs, title="Entry Demo")
self.set_size_request(200, 100)
self.timeout_id = None
header = Gtk.HeaderBar()
self.set_titlebar(header)
vbox = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
spacing=6,
margin_start=24,
margin_end=24,
margin_top=24,
margin_bottom=24,
)
self.set_child(vbox)
# Gtk.SearchEntry
search = Gtk.SearchEntry(
key_capture_widget=self, placeholder_text="Search Entry"
)
header.set_title_widget(search)
self.set_focus(search)
# Gtk.Entry
self.entry = Gtk.Entry(text="Hello World", progress_pulse_step=0.2)
vbox.append(self.entry)
hbox = Gtk.Box(spacing=6)
vbox.append(hbox)
self.check_editable = Gtk.CheckButton(label="Editable", active=True)
self.check_editable.connect("toggled", self.on_editable_toggled)
hbox.append(self.check_editable)
self.check_visible = Gtk.CheckButton(label="Visible", active=True)
self.check_visible.connect("toggled", self.on_visible_toggled)
hbox.append(self.check_visible)
self.pulse = Gtk.CheckButton(label="Pulse")
self.pulse.connect("toggled", self.on_pulse_toggled)
hbox.append(self.pulse)
self.icon = Gtk.CheckButton(label="Icon")
self.icon.connect("toggled", self.on_icon_toggled)
hbox.append(self.icon)
# Gtk.PasswordEntry
pass_entry = Gtk.PasswordEntry(
placeholder_text="Password Entry",
show_peek_icon=True,
margin_top=24,
)
vbox.append(pass_entry)
def on_editable_toggled(self, button):
value = button.get_active()
self.entry.set_editable(value)
def on_visible_toggled(self, button):
self.entry.props.visibility = button.props.active
def on_pulse_toggled(self, button):
if button.get_active():
# Call self.do_pulse every 100 ms
self.timeout_id = GLib.timeout_add(100, self.do_pulse)
else:
# Don't call self.do_pulse anymore
GLib.source_remove(self.timeout_id)
self.timeout_id = None
def do_pulse(self):
self.entry.progress_pulse()
return True
def on_icon_toggled(self, button):
icon_name = "system-search-symbolic" if button.props.active else None
self.entry.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY, icon_name)
def on_activate(app):
win = EntryWindow(application=app)
win.present()
app = Gtk.Application(application_id="com.example.App")
app.connect("activate", on_activate)
app.run(None)
```
--------------------------------
### Install PyGObject on openSUSE (Pip)
Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md
Install PyGObject and its dependencies from PyPI using pip on openSUSE. Ensure build dependencies are installed via Zypper before using pip.
```bash
sudo zypper install cairo-devel pkg-config python3-devel gcc gobject-introspection-devel
```
```bash
pip3 install pycairo
```
```bash
pip3 install PyGObject
```
```bash
python3 hello.py
```
--------------------------------
### Install PyGObject with Pixi
Source: https://context7.com/gnome/pygobject/llms.txt
Initialize a new project with Pixi and add PyGObject and GTK4.
```bash
pixi init .
pixi add pygobject gtk4
pixi run python hello.py
```
--------------------------------
### Build PyGObject with Meson
Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/packagingguide.md
Use these commands to set up, compile, and install PyGObject using Meson. Ensure the DESTDIR is set correctly for staging.
```bash
meson setup --prefix /usr --buildtype=plain _build -Dc_args=... -Dc_link_args=...
meson compile -C _build
meson test -C _build
DESTDIR=/path/to/staging/root meson install -C _build
```
--------------------------------
### Install PyGObject on openSUSE (System Package)
Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md
Install PyGObject and GTK4 using the Zypper package manager on openSUSE. This method uses system packages for installation.
```bash
sudo zypper install python3-gobject python3-gobject-Gdk typelib-1_0-Gtk-4_0 libgtk-4-1
```
```bash
python3 hello.py
```
--------------------------------
### Simple GTK Application with PyGObject
Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md
This is a basic GTK application that displays a 'Hello World' window. It requires PyGObject and GTK to be installed.
```python
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import GLib, Gtk
class MyApplication(Gtk.Application):
def __init__(self):
super().__init__(application_id="com.example.MyGtkApplication")
GLib.set_application_name('My Gtk Application')
def do_activate(self):
window = Gtk.ApplicationWindow(application=self, title="Hello World")
window.present()
app = MyApplication()
app.run()
```
--------------------------------
### GTK4 Drag and Drop Example
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/drag-and-drop.md
This is the main application code for the drag and drop example. It sets up the main window, including a source view (FlowBox) and a target view (Stack).
```python
import gi
gi.require_version("Gdk", "4.0")
gi.require_version("Gtk", "4.0")
from gi.repository import Gdk, GObject, Gtk
class DragDropWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kargs):
super().__init__(*args, **kargs, title="Drag and Drop Example")
self.set_default_size(500, 400)
views_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, vexpand=True)
self.set_child(views_box)
flow_box = Gtk.FlowBox(selection_mode=Gtk.SelectionMode.NONE)
views_box.append(flow_box)
flow_box.append(SourceFlowBoxChild("Item 1", "image-missing"))
flow_box.append(SourceFlowBoxChild("Item 2", "help-about"))
flow_box.append(SourceFlowBoxChild("Item 3", "edit-copy"))
views_box.append(Gtk.Separator())
self.target_view = TargetView(vexpand=True)
views_box.append(self.target_view)
class SourceFlowBoxChild(Gtk.FlowBoxChild):
def __init__(self, name, icon_name):
super().__init__()
self.name = name
self.icon_name = icon_name
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.set_child(box)
icon = Gtk.Image(icon_name=self.icon_name)
label = Gtk.Label(label=self.name)
box.append(icon)
box.append(label)
drag_controller = Gtk.DragSource()
drag_controller.connect("prepare", self.on_drag_prepare)
drag_controller.connect("drag-begin", self.on_drag_begin)
self.add_controller(drag_controller)
def on_drag_prepare(self, _ctrl, _x, _y):
item = Gdk.ContentProvider.new_for_value(self)
string = Gdk.ContentProvider.new_for_value(self.name)
return Gdk.ContentProvider.new_union([item, string])
def on_drag_begin(self, ctrl, _drag):
icon = Gtk.WidgetPaintable.new(self)
ctrl.set_icon(icon, 0, 0)
class TargetView(Gtk.Box):
def __init__(self, **kargs):
super().__init__(**kargs)
self.stack = Gtk.Stack(hexpand=True)
self.append(self.stack)
empty_label = Gtk.Label(label="Drag some item, text, or files here.")
self.stack.add_named(empty_label, "empty")
self.stack.set_visible_child_name("empty")
box = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
vexpand=True,
valign=Gtk.Align.CENTER,
)
self.stack.add_named(box, "item")
self.icon = Gtk.Image()
box.append(self.icon)
self.label = Gtk.Label()
box.append(self.label)
self.text = Gtk.Label()
self.stack.add_named(self.text, "other")
drop_controller = Gtk.DropTarget.new(
type=GObject.TYPE_NONE, actions=Gdk.DragAction.COPY
)
drop_controller.set_gtypes([SourceFlowBoxChild, Gdk.FileList, str])
drop_controller.connect("drop", self.on_drop)
self.add_controller(drop_controller)
def on_drop(self, _ctrl, value, _x, _y):
if isinstance(value, SourceFlowBoxChild):
self.label.props.label = value.name
self.icon.props.icon_name = value.icon_name
self.stack.set_visible_child_name("item")
elif isinstance(value, Gdk.FileList):
files = value.get_files()
names = ""
for file in files:
names += f"Loaded file {file.get_basename()}\n"
self.text.props.label = names
self.stack.set_visible_child_name("other")
elif isinstance(value, str):
self.text.props.label = value
self.stack.set_visible_child_name("other")
def on_activate(app):
win = DragDropWindow(application=app)
win.present()
app = Gtk.Application(application_id="com.example.App")
app.connect("activate", on_activate)
app.run(None)
```
--------------------------------
### Import and Print Gtk Module
Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/introspection_porting.md
Demonstrates how to import the Gtk module from gi.repository and print its representation. This confirms that the Gtk typelib is installed and accessible.
```console
from gi.repository import Gtk; print Gtk
```
--------------------------------
### Install Pre-commit Hook
Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/style_guide.md
Install the pre-commit hook to automatically format code before committing. Run this command in your project's root directory.
```bash
pre-commit install
```
--------------------------------
### Install PyGObject from PyPI
Source: https://github.com/gnome/pygobject/blob/main/README.rst
Install the latest version of PyGObject using pip. A C compiler is required as PyGObject is distributed as a source distribution.
```bash
pip install PyGObject
```
--------------------------------
### PyGTK 2 Hello World Message Dialog
Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/introspection_porting.md
Example of creating a simple message dialog using PyGTK 2.
```console
$ python -c 'import gtk; gtk.MessageDialog(None, 0, gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, "Hello World").run()'
```
--------------------------------
### Initialize GObject
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gobject/basics.md
GObjects are initialized like any other Python class. This example shows the basic initialization of a GTK label.
```python
label = Gtk.Label()
```
--------------------------------
### Install PyGObject on Ubuntu/Debian (System Package)
Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md
Install PyGObject and GTK4 using the system's package manager on Ubuntu or Debian. This is a straightforward method for getting started.
```bash
sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-4.0
```
```bash
python3 hello.py
```
--------------------------------
### Gtk.Application Lifecycle and Window Management
Source: https://context7.com/gnome/pygobject/llms.txt
This snippet demonstrates the structure of a GTK application, including setting up menus, actions, and handling window creation and command-line arguments. Override do_startup() for setup and do_activate() for window creation.
```python
import sys
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import GLib, Gio, Gtk
MENU_XML = """
"
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_default_size(400, 300)
self.props.show_menubar = True
# Window-scoped action with state ("win.maximize")
max_action = Gio.SimpleAction.new_stateful(
"maximize", None, GLib.Variant.new_boolean(False)
)
max_action.connect("change-state", self.on_maximize_toggle)
self.add_action(max_action)
self.label = Gtk.Label(label="Hello World")
self.set_child(self.label)
def on_maximize_toggle(self, action, value):
action.set_state(value)
self.maximize() if value.get_boolean() else self.unmaximize()
class Application(Gtk.Application):
def __init__(self, *args, **kwargs):
super().__init__(
*args,
application_id="org.example.App",
flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
**kwargs,
)
self.window = None
self.add_main_option(
"verbose", ord("v"),
GLib.OptionFlags.NONE, GLib.OptionArg.NONE,
"Enable verbose output", None,
)
def do_startup(self):
Gtk.Application.do_startup(self)
action = Gio.SimpleAction.new("about", None)
action.connect("activate", lambda a, p: None)
self.add_action(action)
action = Gio.SimpleAction.new("quit", None)
action.connect("activate", lambda a, p: self.quit())
self.add_action(action)
builder = Gtk.Builder.new_from_string(MENU_XML, -1)
self.set_menubar(builder.get_object("menubar"))
def do_activate(self):
if not self.window:
self.window = AppWindow(application=self, title="My App")
self.window.present()
def do_command_line(self, command_line):
options = command_line.get_options_dict().end().unpack()
if "verbose" in options:
print("Verbose mode enabled")
self.activate()
return 0
if __name__ == "__main__":
app = Application()
app.run(sys.argv)
```
--------------------------------
### Gtk4 Clipboard Example Application
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/clipboard.md
This example demonstrates how to copy and paste text and images using Gdk.Clipboard in a Gtk4 application. It includes setup for the application window, clipboard access, and handlers for copy/paste actions.
```Python
import gi
gi.require_version("Gdk", "4.0")
gi.require_version("Gtk", "4.0")
from gi.repository import Gdk, Gtk
class ClipboardWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kargs):
super().__init__(*args, **kargs, title="Clipboard Example")
box = Gtk.Box(spacing=12, orientation=Gtk.Orientation.VERTICAL)
self.set_child(box)
self.clipboard = Gdk.Display.get_default().get_clipboard()
text_box = Gtk.Box(spacing=6, homogeneous=True)
box.append(text_box)
self.entry = Gtk.Entry(text="Some text you can copy")
button_copy_text = Gtk.Button(label="Copy Text")
button_copy_text.connect("clicked", self.copy_text)
button_paste_text = Gtk.Button(label="Paste Text")
button_paste_text.connect("clicked", self.paste_text)
text_box.append(self.entry)
text_box.append(button_copy_text)
text_box.append(button_paste_text)
image_box = Gtk.Box(spacing=6)
box.append(image_box)
self.picture = Gtk.Picture.new_for_filename("../images/application.png")
self.picture.props.hexpand = True
button_copy_image = Gtk.Button(label="Copy Image", valign=Gtk.Align.CENTER)
button_copy_image.connect("clicked", self.copy_image)
button_paste_image = Gtk.Button(label="Paste Image", valign=Gtk.Align.CENTER)
button_paste_image.connect("clicked", self.paste_image)
image_box.append(self.picture)
image_box.append(button_copy_image)
image_box.append(button_paste_image)
def copy_text(self, _button):
self.clipboard.set(self.entry.get_text())
def paste_text(self, _button):
self.clipboard.read_text_async(None, self.on_paste_text)
def on_paste_text(self, _clipboard, result):
text = self.clipboard.read_text_finish(result)
if text is not None:
self.entry.set_text(text)
def copy_image(self, _button):
texture = self.picture.get_paintable()
gbytes = texture.save_to_png_bytes()
content = Gdk.ContentProvider.new_for_bytes("image/png", gbytes)
self.clipboard.set_content(content)
def paste_image(self, _button):
self.clipboard.read_texture_async(None, self.on_paste_image)
def on_paste_image(self, _clipboard, result):
texture = self.clipboard.read_texture_finish(result)
if texture is not None:
self.picture.set_paintable(texture)
def on_activate(app):
win = ClipboardWindow(application=app)
win.present()
app = Gtk.Application(application_id="com.example.App")
app.connect("activate", on_activate)
app.run(None)
```
--------------------------------
### Set Up Meson Build Directory
Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md
Initialize the Meson build system for the project. This command is typically needed only once.
```console
meson setup _build
```
--------------------------------
### GtkTextView Setup and Event Handling
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/textview.md
Sets up a GtkTextView with various wrapping options and connects signals for handling user interactions like toggling wrap modes and applying tags.
```Python
radio_wrapchar, radio_wrapnone, Gtk.PositionType.RIGHT, 1, 1
)
radio_wrapword = Gtk.CheckButton(label="Word Wrapping", group=radio_wrapnone)
grid.attach_next_to(
radio_wrapword, radio_wrapchar, Gtk.PositionType.RIGHT, 1, 1
)
radio_wrapnone.connect("toggled", self.on_wrap_toggled, Gtk.WrapMode.NONE)
radio_wrapchar.connect("toggled", self.on_wrap_toggled, Gtk.WrapMode.CHAR)
radio_wrapword.connect("toggled", self.on_wrap_toggled, Gtk.WrapMode.WORD)
def on_button_clicked(self, _widget, tag):
bounds = self.textbuffer.get_selection_bounds()
if len(bounds) != 0:
start, end = bounds
self.textbuffer.apply_tag(tag, start, end)
def on_clear_clicked(self, _widget):
start = self.textbuffer.get_start_iter()
end = self.textbuffer.get_end_iter()
self.textbuffer.remove_all_tags(start, end)
def on_wrap_toggled(self, _widget, mode):
self.textview.props.wrap_mode = mode
def on_justify_toggled(self, _widget, justification):
self.textview.props.justification = justification
def on_search_clicked(self, _widget):
self.search_dialog = SearchDialog(self)
self.search_dialog.button.connect("clicked", self.on_find_clicked)
self.search_dialog.present()
def on_find_clicked(self, _button):
cursor_mark = self.textbuffer.get_insert()
start = self.textbuffer.get_iter_at_mark(cursor_mark)
if start.get_offset() == self.textbuffer.get_char_count():
start = self.textbuffer.get_start_iter()
self.search_and_mark(self.search_dialog.entry.get_text(), start)
def search_and_mark(self, text, start):
end = self.textbuffer.get_end_iter()
match = start.forward_search(text, 0, end)
if match is not None:
match_start, match_end = match
self.textbuffer.apply_tag(self.tag_found, match_start, match_end)
self.search_and_mark(text, match_end)
def on_activate(app):
win = TextViewWindow(application=app)
win.present()
app = Gtk.Application(application_id="com.example.App")
app.connect("activate", on_activate)
app.run(None)
```
--------------------------------
### Install pyenv on macOS
Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md
Installs pyenv using Homebrew, then installs and sets Python 3.11 as the global version.
```console
brew install pyenv
pyenv install 3.11
pyenv global 3.11
```
--------------------------------
### Async Download Window Example
Source: https://github.com/gnome/pygobject/blob/main/docs/guide/asynchronous.md
Illustrates asynchronous file downloading with UI feedback using asyncio and Gtk. Use this for I/O-bound tasks that should not block the main thread.
```python
import asyncio
import time
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gio, GLib, Gtk
from gi.events import GLibEventLoopPolicy
class DownloadWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(
*args,
**kwargs,
default_width=500,
default_height=400,
title="Async I/O Example",
)
self.background_task = None
self.cancel_button = Gtk.Button(label="Cancel")
self.cancel_button.connect("clicked", self.on_cancel_clicked)
self.cancel_button.set_sensitive(False)
self.start_button = Gtk.Button(label="Load")
self.start_button.connect("clicked", self.on_start_clicked)
textview = Gtk.TextView(vexpand=True)
self.textbuffer = textview.get_buffer()
scrolled = Gtk.ScrolledWindow()
scrolled.set_child(textview)
box = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
spacing=6,
margin_start=12,
margin_end=12,
margin_top=12,
margin_bottom=12,
)
box.append(self.start_button)
box.append(self.cancel_button)
box.append(scrolled)
self.set_child(box)
def append_text(self, text):
iter_ = self.textbuffer.get_end_iter()
self.textbuffer.insert(iter_, f"[{time.time()}] {text}\n")
def on_start_clicked(self, button):
button.set_sensitive(False)
self.cancel_button.set_sensitive(True)
self.append_text("Start clicked...")
self.background_task = asyncio.create_task(self.download())
def on_cancel_clicked(self, button):
self.append_text("Cancel clicked...")
self.background_task.cancel()
async def download(self):
file_ = Gio.File.new_for_uri("https://pygobject.gnome.org/")
try:
_success, content, _etag = await file_.load_contents_async()
except GLib.GError as e:
self.append_text(f"Error: {e.message}")
else:
content_text = content[:100].decode("utf-8")
self.append_text(f"Got content: {content_text}...")
finally:
self.cancel_button.set_sensitive(False)
self.start_button.set_sensitive(True)
class Application(Gtk.Application):
def do_activate(self):
window = DownloadWindow(application=self)
window.present()
def main():
asyncio.set_event_loop_policy(GLibEventLoopPolicy())
app = Application()
app.run()
if __name__ == "__main__":
main()
```
--------------------------------
### Install PyGObject with Homebrew on macOS
Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md
Use this command to install PyGObject and GTK4 using Homebrew. Ensure Homebrew is installed first.
```bash
brew install pygobject3 gtk4
```
--------------------------------
### GTK4 Application Setup and Event Handling
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/application.md
This snippet shows how to define an application class, handle 'about' and 'quit' actions, and run the application. It requires the Gtk and sys modules.
```Python
import sys
import gi
ti.require_version('Gtk', '4.0')
from gi.repository import Gtk
class Application(Gtk.Application):
def __init__(self):
super().__init__(application_id='org.example.app')
def do_activate(self):
win = self.props.active_window
if not win:
win = Gtk.ApplicationWindow(application=self)
win.present()
def on_about(self, _action, _param):
about_dialog = Gtk.AboutDialog(transient_for=self.window, modal=True)
about_dialog.present()
def on_quit(self, _action, _param):
self.quit()
if __name__ == "__main__":
app = Application()
app.run(sys.argv)
```
--------------------------------
### Install Ubuntu/Debian Dependencies for PyGObject
Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md
Installs necessary packages for compiling Python and pip installing PyGObject on Ubuntu or Debian-based systems.
```console
sudo apt-get install -y python3-venv python3-wheel python3-dev
sudo apt-get install -y gobject-introspection libgirepository-2.0-dev \
gir1.2-girepository-3.0 build-essential libbz2-dev libreadline-dev \
libssl-dev zlib1g-dev libsqlite3-dev wget curl llvm libncurses-dev \
xz-utils tk-dev libcairo2-dev
```
--------------------------------
### Gtk.Switch Example
Source: https://github.com/gnome/pygobject/blob/main/docs/tutorials/gtk4/controls/switch.md
Demonstrates creating and managing Gtk.Switch widgets. Connects to the `notify::active` signal to detect state changes and prints the new state.
```Python
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
class SwitcherWindow(Gtk.ApplicationWindow):
def __init__(self, **kargs):
super().__init__(**kargs, title="Switch Demo")
hbox = Gtk.Box(spacing=6, homogeneous=True, margin_top=24, margin_bottom=24)
self.set_child(hbox)
switch = Gtk.Switch(active=False, halign=Gtk.Align.CENTER)
switch.connect("notify::active", self.on_switch_activated)
hbox.append(switch)
switch = Gtk.Switch(active=True, halign=Gtk.Align.CENTER)
switch.connect("notify::active", self.on_switch_activated)
hbox.append(switch)
def on_switch_activated(self, switch, _gparam):
state = "on" if switch.props.active else "off"
print("Switch was turned", state)
def on_activate(app):
win = SwitcherWindow(application=app)
win.present()
app = Gtk.Application(application_id="com.example.App")
app.connect("activate", on_activate)
app.run(None)
```
--------------------------------
### Install pyenv on Linux
Source: https://github.com/gnome/pygobject/blob/main/docs/devguide/dev_environ.md
Installs pyenv using a curl script, reloads the shell, and then installs and sets Python 3.11 as the global version.
```console
curl https://pyenv.run | bash
exec $SHELL
pyenv install 3.11
pyenv global 3.11
```
--------------------------------
### Install PyGObject on Fedora (Pip)
Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md
Install PyGObject and its dependencies from PyPI using pip on Fedora. Ensure all necessary build tools and libraries are installed first.
```bash
sudo dnf install gcc gobject-introspection-devel cairo-gobject-devel pkg-config python3-devel gtk4
```
```bash
pip3 install pycairo
```
```bash
pip3 install PyGObject
```
```bash
python3 hello.py
```
--------------------------------
### Install PyGObject on Ubuntu/Debian (Pip)
Source: https://github.com/gnome/pygobject/blob/main/docs/getting_started.md
Install PyGObject and its dependencies from PyPI using pip on Ubuntu or Debian. This method requires installing build dependencies first.
```bash
sudo apt install libgirepository-2.0-dev gcc libcairo2-dev pkg-config python3-dev gir1.2-gtk-4.0
```
```bash
pip3 install pycairo
```
```bash
pip3 install PyGObject
```
```bash
python3 hello.py
```