GTK言語バインディングの世界観です。
GTK+/GNOMEはC言語で書かれながら、GLib/GObjectという仕組みを使うことでオブジェクト指向を実現しています。
これにより、さまざまな言語のラッパーを作ることが可能です。それによって、言語バインディングが用意されています。
ArchWikiにGTK+の各種言語バインディングのサンプル一覧があります。
| バインディング | 言語 |
|---|---|
| GTK+ | C言語 |
| gtkmm | C++ |
| GTK# | mono (C#/VB.NET) |
| Java-GNOME | Java |
| GTK-Perl | Perl |
| PyGTK | Python |
| Ruby/GTK+ | Ruby |
| gjs | JavaScript |
ただ、これらのAPIの問題は、C言語のラッパーであるせいか、「init()関数やrun()関数をわざわざ記述する必要があって、意外と美しくない」ということがある。
C++やPythonを最初から使うのであれば、KDEのQt/PyQtを試しても良いかもしれない。ただしQtの場合もapp.exec();を実行する必要はある。どっこいどっこいだ。
たくさんのバインディングに対応しているとは言っても、本当は「一部分だけしか対応していない」とか、「開発状況が遅れていてバグや動かない機能が多い」となりがちである。
GTK Language Bindingsに、公式のバインディングのサポート状況がある。
C/C++, JavaScript, Python, Valaが公式でサポートされている。よって、できるだけこれらの言語で開発するように心がけよう。
ちなみに、これらの言語でどのようなコードになるかは、GNOME Developer Platform Demosから参照できる。
以下はRuby/GTKの例。
Rubyも参照のこと。
以下はGtk::Builderを使ってGladeのUIファイルを読み込む例。
gladeを使う例。GladeのUIファイルを読み込んでいる。Rubyのコード以外にGladeで作ったUIファイルを別途用意する必要がある。
標準のウィジェットを使うだけではなく、自分独自のウィジェットを作りたい場合は、GTK+では以下のようにカスタムウィジェットを開発できる。
PyGObjectは、PythonからGTKアプリケーションを書くための言語バインディングです。
Pythonのツールも参照のこと。
以下はPyGTKの例。
後日注記:GTK3においてはPyGTKはPyGObjectへと置き換えられる。これはGObjectへのPythonやその他言語のバインディング(GObject Introspectionというライブラリ)で、GTKなどGNOME系デスクトップライブラリをPythonやさまざまな言語から使えるようにする。言語バインディングの開発が楽になり、対応が遅れることも少なくなる。
以下はGoogleのAIによるPyGObjectとCairoを使ったペイントソフトのサンプル。
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, Cairo
import cairo
class PaintWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Simple Paint with GTK3")
self.set_default_size(800, 600)
self.connect("destroy", Gtk.main_quit)
# 描画サーフェス(バックバッファ)
self.surface = None
# 描画エリア
self.drawing_area = Gtk.DrawingArea()
self.drawing_area.connect("draw", self.on_draw)
self.drawing_area.connect("configure-event", self.on_configure)
# マウスイベントの設定
self.drawing_area.set_events(Gdk.EventMask.BUTTON_PRESS_MASK |
Gdk.EventMask.BUTTON_RELEASE_MASK |
Gdk.EventMask.POINTER_MOTION_MASK)
self.drawing_area.connect("button-press-event", self.on_button_press)
self.drawing_area.connect("button-release-event", self.on_button_release)
self.drawing_area.connect("motion-notify-event", self.on_motion_notify)
self.add(self.drawing_area)
# 描画の初期状態
self.last_x = 0
self.last_y = 0
self.is_drawing = False
def on_configure(self, widget, event):
"""ウィンドウサイズ変更時にサーフェスを再作成"""
allocation = widget.get_allocation()
# 新しいサーフェスを作成
new_surface = cairo.ImageSurface(
cairo.FORMAT_ARGB32, allocation.width, allocation.height
)
cr = cairo.Context(new_surface)
# 背景を白で塗りつぶし
cr.set_source_rgb(1, 1, 1)
cr.paint()
# 前のサーフェスがあれば、新しいサーフェスにコピー
if self.surface:
cr.set_source_surface(self.surface, 0, 0)
cr.paint()
self.surface = new_surface
return True
def on_draw(self, widget, cr):
"""描画エリアを更新する"""
if self.surface:
cr.set_source_surface(self.surface, 0, 0)
cr.paint()
return False
def on_button_press(self, widget, event):
if event.button == Gdk.BUTTON_PRIMARY:
self.is_drawing = True
self.last_x = event.x
self.last_y = event.y
def on_button_release(self, widget, event):
if event.button == Gdk.BUTTON_PRIMARY:
self.is_drawing = False
def on_motion_notify(self, widget, event):
if self.is_drawing:
cr = cairo.Context(self.surface)
cr.set_source_rgb(0, 0, 0) # 描画色(黒)
cr.set_line_width(2)
cr.set_line_cap(cairo.LINE_CAP_ROUND)
# 線を描画
cr.move_to(self.last_x, self.last_y)
cr.line_to(event.x, event.y)
cr.stroke()
# 位置を更新
self.last_x = event.x
self.last_y = event.y
# 描画エリアに更新を通知
widget.queue_draw()
if __name__ == "__main__":
win = PaintWindow()
win.show_all()
Gtk.main()
以下は必要なライブラリのインストール (Ubuntu/Debian系)。
sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0
以下は関連記事。
2026.03.16
以下はgtkmmの例。
C++も参照のこと。
以下はGoogleのAIによるgtkmmとGStreamerを使った音楽プレイヤーソフトのサンプル。
#include <gtkmm.h>
#include <gst/gst.h>
#include <iostream>
class MusicPlayerWindow : public Gtk::Window {
public:
MusicPlayerWindow();
virtual ~MusicPlayerWindow();
private:
// シグナルハンドラ
void on_button_play();
void on_button_stop();
void on_file_set();
// GStreamerのセットアップ
void setup_gstreamer(const std::string& uri);
// UI要素
Gtk::Box m_vbox{Gtk::Orientation::VERTICAL, 5};
Gtk::FileChooserButton m_file_button{"音楽ファイルを選択", Gtk::FileChooserAction::OPEN};
Gtk::Button m_button_play{"再生"};
Gtk::Button m_button_stop{"停止"};
Gtk::Label m_label{"ファイル未選択"};
// GStreamer要素
GstElement *pipeline;
bool is_playing = false;
};
MusicPlayerWindow::MusicPlayerWindow() {
set_title("GTKmm 音楽プレイヤー");
set_default_size(400, 150);
// GStreamerの初期化
gst_init(nullptr, nullptr);
// レイアウト設定
set_child(m_vbox);
m_vbox.append(m_file_button);
m_vbox.append(m_label);
Gtk::Box *button_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 5);
button_box->append(m_button_play);
button_box->append(m_button_stop);
m_vbox.append(*button_box);
// シグナル接続
m_button_play.signal_clicked().connect(sigc::mem_fun(*this, &MusicPlayerWindow::on_button_play));
m_button_stop.signal_clicked().connect(sigc::mem_fun(*this, &MusicPlayerWindow::on_button_stop));
m_file_button.signal_file_set().connect(sigc::mem_fun(*this, &MusicPlayerWindow::on_file_set));
}
MusicPlayerWindow::~MusicPlayerWindow() {
if (pipeline) {
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
}
}
void MusicPlayerWindow::setup_gstreamer(const std::string& uri) {
if (pipeline) {
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
}
// playbinはメディア再生を自動化するGStreamer要素
pipeline = gst_element_factory_make("playbin", "player");
g_object_set(pipeline, "uri", uri.c_str(), nullptr);
}
void MusicPlayerWindow::on_file_set() {
auto file = m_file_button.get_file();
if (file) {
std::string uri = file->get_uri();
m_label.set_text("再生中: " + file->get_basename());
setup_gstreamer(uri);
}
}
void MusicPlayerWindow::on_button_play() {
if (!pipeline) return;
if (!is_playing) {
gst_element_set_state(pipeline, GST_STATE_PLAYING);
m_button_play.set_label("一時停止");
is_playing = true;
} else {
gst_element_set_state(pipeline, GST_STATE_PAUSED);
m_button_play.set_label("再生");
is_playing = false;
}
}
void MusicPlayerWindow::on_button_stop() {
if (pipeline) {
gst_element_set_state(pipeline, GST_STATE_NULL);
m_button_play.set_label("再生");
is_playing = false;
}
}
int main(int argc, char* argv[]) {
auto app = Gtk::Application::create("org.example.musicplayer");
return app->make_window_and_run<MusicPlayerWindow>(argc, argv);
}
以下はコードの解説。
| コード | 説明 |
|---|---|
| Gtk::FileChooserButton | ファイル選択用のダイアログを開くボタン。 |
| GstElement *pipeline | GStreamerのplaybin要素。これ一つでファイル読み込みからデコード、出力(オーディオ)まで自動で行う。 |
| setup_gstreamer() | 選択されたファイルのURIをplaybinにセットする。 |
| gst_element_set_state() | GST_STATE_PLAYINGが再生、GST_STATE_PAUSEDが一時停止、GST_STATE_NULLが停止・リソース解放。 |
以下は必要なライブラリのインストール (Ubuntu/Debian系)。
sudo apt install libgtkmm-4.0-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
以下はビルド。
g++ -std=c++17 music_player.cpp -o music_player \
`pkg-config gtkmm-4.0 gstreamer-1.0 --cflags --libs`
以下は実行。
./music_player
2026.03.16-17
以下はgjsの例。
GNOME-Shellと拡張機能は、gjsを用いてJavaScriptで記述されています。GNOMEデスクトップも参照のこと。
JavaScriptも参照のこと。
C#/GTK#による.NETアプリケーション開発についてはMonoを参照のこと。
ValaとGenieはGLibを使ったGNOME専用のオブジェクト指向言語です。C#/Monoを置き換えます。ValaとGenieを参照のこと。
OSS界隈の一部で流行っているのが、Rustバインディング。以下のリンクが参考になります。
Rustも参照のこと。
もっとたくさんの例はGTK+/開発 - ArchWikiからも参照できる。
GTK以外のスクリプト言語として、Tcl/Tkツールキットを使うこともできます。Tcl/Tkを参照のこと。
全般
C++
C#
Python
Ruby