BlinkGTK Python (PyGObject) チュートリアル

対象バージョン: BlinkGTK 1.2.5 以降
言語: 日本語 | English


目次

  1. はじめに
  2. PyGObjectのセットアップ
  3. 最小限のブラウザ
  4. シグナル処理
  5. プロパティ監視
  6. ナビゲーション機能
  7. 実践的な使い方
  8. トラブルシューティング

はじめに

BlinkGTK は GObject Introspection に対応しているため、Python から PyGObject を使って利用できます。
このチュートリアルの完全なプログラムは、どれも BlinkGTK 1.2.5 (Chromium 156) で実行して確かめています。

必要なもの

以前のチュートリアルのコードを使っていた方へ

以前このページに載っていたコードは、そのままでは動きません。次の 3 点を書き換えてください。

以前の書き方 1.2.5 以降の書き方
初期化を呼ばずにウィジェットを作る ウィジェットを作る前に BlinkGTK.gtk_init(sys.argv[:1]) を呼ぶ
app.run(sys.argv) BlinkGTK.gtk_application_run(app) の後に BlinkGTK.gtk_shutdown()
BlinkGtk などの別の名前空間、blink_gtk モジュールの import gi.require_version("BlinkGTK", "0.1") と from gi.repository import BlinkGTK

app.run() で回すと、ウィンドウは出ますが Chromium の処理が回らず、ページが読み込まれません。


PyGObjectのセットアップ

必要なパッケージのインストール

# Fedora
sudo dnf install python3-gobject gtk4 blinkgtk-bin blinkgtk-bin-gir

# Debian / Ubuntu
sudo apt install python3-gi gir1.2-gtk-4.0
# BlinkGTK 本体と型情報は、ダウンロードした DEB をファイルで指定します (APT のリポジトリはありません)
sudo apt install ./libblinkgtk-0.1-0_<版>-1_amd64.deb ./gir1.2-blinkgtk-0.1_<版>-1_amd64.deb

BlinkGTK のパッケージを入れるためのリポジトリの設定は、インストールガイド を参照してください。

インポートの確認

import gi

gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")
from gi.repository import BlinkGTK, Gtk

print(f"GTK {Gtk.get_major_version()}.{Gtk.get_minor_version()}.{Gtk.get_micro_version()}")
print(f"BlinkGTK {BlinkGTK.gtk_get_version()} (Chromium {BlinkGTK.gtk_get_chromium_version()})")

BlinkGTK.gtk_get_version() と BlinkGTK.gtk_get_chromium_version() は、初期化の前でも呼べます。
ここで 1.2.4 以前が表示された場合は、BlinkGTK を更新してください。


最小限のブラウザ

基本的な使い方

次のプログラムを minimal.py として保存し、blinkgtk-run python3 minimal.py で実行します。

Python のプログラムは、必ず blinkgtk-run を通して実行してください。 BlinkGTK (Chromium) のメモリ割り当ての仕組みは、プロセスの最初から読み込まれている必要があります。C のアプリは起動時に読み込みますが、Python では BlinkGTK が後から読み込まれるため、blinkgtk-run を通さないと HTTPS の頁を開いたときに異常終了します。blinkgtk-run は RPM・DEB では /usr/bin/blinkgtk-run、tarball では展開した場所の usr/bin/blinkgtk-run にあります。blinkgtk-run は環境変数 LD_PRELOAD を使うので、プログラムから起動する別のプログラムにも引き継がれます。
引数に URL を渡すと、そのページを開きます。

#!/usr/bin/env python3
"""最小限の BlinkGTK ブラウザ"""
import sys

import gi

gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")
from gi.repository import BlinkGTK, Gtk  # noqa: E402


def on_activate(app, url):
    window = Gtk.ApplicationWindow(application=app, title="BlinkGTK Minimal Browser")
    window.set_default_size(1024, 768)

    view = BlinkGTK.WebView.new()
    window.set_child(view)
    window.present()

    view.load_uri(url)


def main():
    url = sys.argv[1] if len(sys.argv) > 1 else "https://example.com/"

    # 1. BlinkGTK を初期化する (GTK のウィジェットを作る前に 1 回だけ)
    ok, _argv = BlinkGTK.gtk_init(sys.argv[:1])
    if not ok:
        print("BlinkGTK を初期化できませんでした", file=sys.stderr)
        return 1

    # 2. アプリケーションを作り、BlinkGTK のメインループで回す
    app = Gtk.Application(application_id="org.example.MinimalBrowser")
    app.connect("activate", on_activate, url)
    rc = BlinkGTK.gtk_application_run(app)  # 最後のウィンドウを閉じると戻る

    # 3. BlinkGTK を終了する
    BlinkGTK.gtk_shutdown()
    return rc


if __name__ == "__main__":
    sys.exit(main())

コードの解説

1. バージョン指定

gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")

使うライブラリの版を明示します。from gi.repository import ... より前に書きます。

2. 初期化

ok, _argv = BlinkGTK.gtk_init(sys.argv[:1])

3. WebView の作成

view = BlinkGTK.WebView.new()

4. メインループと終了

rc = BlinkGTK.gtk_application_run(app)
BlinkGTK.gtk_shutdown()

シグナル処理

基本的なシグナル

BlinkGTK.WebView は、読み込みに関わる次の 4 つのシグナルを出します。

シグナル名 ハンドラの引数 説明
load-changed (view, event: BlinkGTK.LoadEvent) 読み込みの状態が変わった
load-failed (view, error_code: int, failing_uri: str) 読み込みが確定せずに終わった (中断など)
title-changed (view) ページのタイトルが変わった。値は view.get_title() で読む
uri-changed (view) URI が変わった。値は view.get_uri() で読む

title-changed と uri-changed には、新しい値が引数として渡されません。

シグナルの接続

def on_load_changed(view, event):
    if event == BlinkGTK.LoadEvent.FINISHED:
        print(f"読み込み完了: {view.get_title()} ({view.get_uri()})")


def on_load_failed(view, error_code, failing_uri):
    if failing_uri != (view.get_uri() or failing_uri):
        return  # iframe など、表示中のページではない失敗
    if error_code == -3:
        return  # 中断。停止ボタンや次の読み込みで普通に起きる
    print(f"読み込みが確定しませんでした: {failing_uri} (エラー番号 {error_code})")


def on_title_changed(view):
    window.set_title(f"{view.get_title()} - Browser")


view.connect("load-changed", on_load_changed)
view.connect("load-failed", on_load_failed)
view.connect("title-changed", on_title_changed)

BlinkGTK.LoadEvent の値

値 意味
BlinkGTK.LoadEvent.STARTED load_uri() / load_html() で読み込みを始めた。リンク・戻る・進む・再読み込みでは来ない
BlinkGTK.LoadEvent.COMMITTED 表示する文書が確定した
BlinkGTK.LoadEvent.FINISHED 読み込みが終わった
BlinkGTK.LoadEvent.REDIRECTED 将来のために予約されています。現在は送られません

比較には数値ではなく、上の名前を使ってください。
STARTED はすべての移動で来るわけではないため、読み込み中かどうかの判定にはプロパティ監視の notify::is-loading を使います。

load-failed が来る場合と来ない場合


プロパティ監視

notify::プロパティ名 シグナル

GObject のプロパティの変化は、notify::プロパティ名 シグナルで受け取れます。
ハンドラの引数は (view, pspec) です。値は view.props.title のように読めます。

def on_title_notify(view, pspec):
    print(f"タイトル: {view.props.title}")


def on_uri_notify(view, pspec):
    print(f"URI: {view.props.uri}")


view.connect("notify::title", on_title_notify)
view.connect("notify::uri", on_uri_notify)

利用できるプロパティ

プロパティ名 型 説明
uri str 現在の URI
title str ページのタイトル
zoom-level float 拡大率。1.0 が 100% (読み書き可)
is-loading bool 読み込み中かどうか

読み込み中かどうか (is-loading)

読み込み中の表示 (進み具合のバー、停止・再読み込みのボタン) は、notify::is-loading で切り替えます。
リンク・戻る・進む・再読み込みを含むどの移動でも、読み込みの開始と終了で届きます。値は view.is_loading() で読みます。
開始のときは続けて 2 回届くことがあるので、届いた回数ではなく値で判定してください。

def on_is_loading_changed(view, pspec):
    loading = view.is_loading()
    stop_button.set_sensitive(loading)
    reload_button.set_sensitive(not loading)


view.connect("notify::is-loading", on_is_loading_changed)

読み込みの進み具合 (0.0〜1.0) は view.get_estimated_load_progress() で読めます。
これはプロパティではないため、変化の通知はありません。使い方は実践的な使い方の例を参照してください。


ナビゲーション機能

ナビゲーションのメソッド

メソッド 説明
load_uri(uri) URI を開く
reload() 再読み込み
stop() 読み込みを止める
go_back() / go_forward() 履歴を戻る / 進む
can_go_back() / can_go_forward() 戻れるか / 進めるか

戻る・進むボタンと URL 欄を持つブラウザ

#!/usr/bin/env python3
"""戻る・進む・再読み込みと URL 欄を持つブラウザ"""
import sys

import gi

gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")
from gi.repository import BlinkGTK, Gtk  # noqa: E402


class BrowserWithNavigation(Gtk.ApplicationWindow):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.set_default_size(1024, 768)

        toolbar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)

        self.back_button = Gtk.Button(label="←", sensitive=False)
        self.back_button.connect("clicked", lambda _b: self.webview.go_back())
        toolbar.append(self.back_button)

        self.forward_button = Gtk.Button(label="→", sensitive=False)
        self.forward_button.connect("clicked", lambda _b: self.webview.go_forward())
        toolbar.append(self.forward_button)

        reload_button = Gtk.Button(label="↻")
        reload_button.connect("clicked", lambda _b: self.webview.reload())
        toolbar.append(reload_button)

        self.url_entry = Gtk.Entry(hexpand=True)
        self.url_entry.connect("activate", self.on_url_activate)
        toolbar.append(self.url_entry)

        self.webview = BlinkGTK.WebView.new()
        self.webview.set_vexpand(True)
        # 読み込みの開始と終了 (どの経路の移動でも来る) でボタンを更新する
        self.webview.connect("notify::is-loading", self.on_is_loading_changed)
        self.webview.connect("title-changed", self.on_title_changed)
        self.webview.connect("uri-changed", self.on_uri_changed)

        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        main_box.append(toolbar)
        main_box.append(self.webview)
        self.set_child(main_box)

    def on_url_activate(self, entry):
        url = entry.get_text().strip()
        if url and "://" not in url and not url.startswith(("about:", "data:")):
            url = "https://" + url
        if url:
            self.webview.load_uri(url)

    def on_is_loading_changed(self, webview, pspec):
        self.update_navigation_buttons()

    def on_title_changed(self, webview):
        title = webview.get_title()
        self.set_title(f"{title} - Browser" if title else "Browser")

    def on_uri_changed(self, webview):
        self.url_entry.set_text(webview.get_uri() or "")
        self.update_navigation_buttons()

    def update_navigation_buttons(self):
        self.back_button.set_sensitive(self.webview.can_go_back())
        self.forward_button.set_sensitive(self.webview.can_go_forward())


def on_activate(app, url):
    window = BrowserWithNavigation(application=app)
    window.present()
    window.webview.load_uri(url)


def main():
    url = sys.argv[1] if len(sys.argv) > 1 else "https://example.com/"
    ok, _argv = BlinkGTK.gtk_init(sys.argv[:1])
    if not ok:
        print("BlinkGTK を初期化できませんでした", file=sys.stderr)
        return 1
    app = Gtk.Application(application_id="org.example.NavigationBrowser")
    app.connect("activate", on_activate, url)
    rc = BlinkGTK.gtk_application_run(app)
    BlinkGTK.gtk_shutdown()
    return rc


if __name__ == "__main__":
    sys.exit(main())

戻る・進むボタンの有効・無効は、uri-changed と notify::is-loading で更新しています。リンクや戻る・進むによる移動でも更新されます。


実践的な使い方

ヘッダーバーと進み具合の表示

#!/usr/bin/env python3
"""ヘッダーバーと読み込みの進み具合を表示するブラウザ"""
import sys

import gi

gi.require_version("Gtk", "4.0")
gi.require_version("BlinkGTK", "0.1")
from gi.repository import BlinkGTK, GLib, Gtk  # noqa: E402


class ProgressBrowser(Gtk.ApplicationWindow):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.set_default_size(1200, 900)
        self.set_titlebar(Gtk.HeaderBar())
        self.set_title("Browser")

        self.progress_bar = Gtk.ProgressBar(visible=False)
        self.timer_id = 0

        self.webview = BlinkGTK.WebView.new()
        self.webview.set_vexpand(True)
        # 読み込みの開始と終了は notify::is-loading で受け取る (リンク・戻る・再読み込みでも来る)
        self.webview.connect("notify::is-loading", self.on_is_loading_changed)
        self.webview.connect("notify::title", self.on_title_notify)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.append(self.progress_bar)
        vbox.append(self.webview)
        self.set_child(vbox)

    def on_is_loading_changed(self, webview, pspec):
        if webview.is_loading():
            self.progress_bar.set_visible(True)
            if self.timer_id == 0:
                # 進み具合には通知が無いので、読み込み中だけ 0.1 秒ごとに読む
                self.progress_bar.set_fraction(0.0)
                self.timer_id = GLib.timeout_add(100, self.update_progress)
        else:
            self.progress_bar.set_visible(False)
            if self.timer_id:
                GLib.source_remove(self.timer_id)
                self.timer_id = 0
            print(f"読み込み終了: {webview.get_title() or '(タイトルなし)'}", flush=True)

    def update_progress(self):
        self.progress_bar.set_fraction(self.webview.get_estimated_load_progress())
        return GLib.SOURCE_CONTINUE

    def on_title_notify(self, webview, pspec):
        self.set_title(webview.props.title or "Browser")


def on_activate(app, url):
    window = ProgressBrowser(application=app)
    window.present()
    window.webview.load_uri(url)


def main():
    url = sys.argv[1] if len(sys.argv) > 1 else "https://example.com/"
    ok, _argv = BlinkGTK.gtk_init(sys.argv[:1])
    if not ok:
        print("BlinkGTK を初期化できませんでした", file=sys.stderr)
        return 1
    app = Gtk.Application(application_id="org.example.ProgressBrowser")
    app.connect("activate", on_activate, url)
    rc = BlinkGTK.gtk_application_run(app)
    BlinkGTK.gtk_shutdown()
    return rc


if __name__ == "__main__":
    sys.exit(main())

JavaScript の実行について

ページの JavaScript を Python から実行して結果を受け取るメソッド (WebKitGTK の evaluate_javascript() に当たるもの) は、現在ありません。
ページとアプリの間でメッセージをやり取りする仕組みは アプリ統合 API で説明しています (C の説明です)。


トラブルシューティング

ModuleNotFoundError: No module named 'gi'

PyGObject がインストールされていません。

# Fedora
sudo dnf install python3-gobject

# Debian / Ubuntu
sudo apt install python3-gi

ValueError: Namespace BlinkGTK not available

BlinkGTK の introspection データ (BlinkGTK-0.1.typelib) が見つかりません。
Fedora では blinkgtk-bin-gir、Debian / Ubuntu では gir1.2-blinkgtk-0.1 をインストールしてください。

それでも見つからない場合の確認方法は、インストールガイド のトラブルシューティングを参照してください。

ウィンドウは出るがページが表示されない

app.run() で回していないか確認してください。BlinkGTK.gtk_application_run(app) で回す必要があります。
また、ウィジェットを作る前に BlinkGTK.gtk_init() を呼んでいるかも確認してください。

起動してすぐに終了する

BlinkGTK 1.2.4 以前では、Python から起動すると Chromium の子プロセスが起動できずに終了します。
BlinkGTK.gtk_get_version() で版を確かめ、1.2.5 以降に更新してください。

AttributeError: 'WebView' object has no attribute ...

以前の資料にあった名前を使っていないか確認してください。次の名前は存在しません。

存在しない名前 代わりに使うもの
execute_javascript() ありません (JavaScript の実行について)
set_enable_javascript() set_javascript_enabled()
set_auto_load_images() set_images_enabled()
set_enable_local_storage() set_local_storage_enabled()
estimated-load-progress プロパティ get_estimated_load_progress() メソッド

サンプルコード

実行して確かめた完全なプログラムが examples にあります。

blinkgtk-run python3 minimal_browser.py https://example.com/

まとめ

Python から BlinkGTK を使うときの要点は次のとおりです。

次のステップ:


BlinkGTK Project | Copyright 2025 | BSD-3-Clause License