mattintosh note

どこかのエンジニアモドキの備忘録

🐧 Python と GTK で GUI を作ってみる

Linux でも簡易の GUI を作りたいな〜と思っていて Linux Mint に搭載されている mintstick のソースを見てみたらなんと import gi.repository from Gtk だけで作れちゃうことが判明。Mac OS XAppleScript よか面倒だけど色々カスタマイズできるし、何より作っていて楽しい。

今回作成したのは RAR コマンドをちょっと便利にするための GUI。某掲示板で他の人用に作成したものだけどその掲示板に掲載するのがなんとなく微妙だったのでここに置いておく。

引数にファイルを与えて実行すると圧縮方法とリカバリレコードレベルを選択できる。

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""Desktop entry example (~/.local/share/applications/rar_controller.desktop)
[Desktop Entry]
Name=RAR Controller
Comment=
TryExec=rar
Exec=python /path/to/rar_controller.py %F
NoDisplay=false
StartupNotify=true
Terminal=1
Type=Application
MimeType=inode/directory
"""

import sys
import subprocess
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):

        Gtk.Window.__init__(self, title="RAR Controller")

        # Compression Menu -----------------------------------------------------
        comp_menu_label = Gtk.Label("圧縮方法")
        comp_menu_model = Gtk.ListStore(int, str)
        comp_menu_items = [
            [0, "0 - 無圧縮"],
            [1, "1 - 最速"],
            [2, "2 - 速度優先"],
            [3, "3 - 標準"],
            [4, "4 - 圧縮重視"],
            [5, "5 - 最高圧縮"]]
        for i in range(len(comp_menu_items)):
            comp_menu_model.append(comp_menu_items[i])
        comp_menu_combo = Gtk.ComboBox.new_with_model_and_entry(comp_menu_model)
        comp_menu_combo.connect("changed", self.on_comp_menu_combo_changed)
        comp_menu_combo.set_entry_text_column(1)
        self.comp_value = 3
        comp_menu_combo.set_active(self.comp_value)

        # Recovery Record Menu -------------------------------------------------
        recovery_menu_label = Gtk.Label("リカバリレコード")
        recovery_menu_model = Gtk.ListStore(int, str)
        for i in range(0,11):
            recovery_menu_model.append([i, str(i) + "%"])
        recovery_menu_combo = Gtk.ComboBox.new_with_model_and_entry(recovery_menu_model)
        recovery_menu_combo.connect("changed", self.on_recovery_menu_combo_changed)
        recovery_menu_combo.set_entry_text_column(1)
        self.recovery_value = 5
        recovery_menu_combo.set_active(self.recovery_value)

        # Buttons --------------------------------------------------------------
        button_run = Gtk.Button("圧縮開始")
        button_run.connect("clicked", self.on_click_run)

        button_cancel = Gtk.Button("キャンセル")
        button_cancel.connect("clicked", self.on_click_cancel)

        # Layouts --------------------------------------------------------------
        self.set_border_width(10)
        grid = Gtk.Grid(
            column_spacing=20,
            row_spacing=10)
        grid.attach(comp_menu_label,    0, 0, 2, 1)
        grid.attach(comp_menu_combo,    0, 1, 2, 1)
        grid.attach(recovery_menu_label,0, 2, 2, 1)
        grid.attach(recovery_menu_combo,0, 3, 2, 1)
        grid.attach(button_cancel,      0, 4, 1, 1)
        grid.attach(button_run,         1, 4, 1, 1)
        self.add(grid)

    def on_comp_menu_combo_changed(self, combo):
        self.comp_value = combo.get_model()[combo.get_active_iter()][0]
 
    def on_recovery_menu_combo_changed(self, combo):
        self.recovery_value = combo.get_model()[combo.get_active_iter()][0]
 
    def on_click_cancel(self, button):
        Gtk.main_quit()

    def on_click_run(self, button):
        cmd = ["rar", "a"]
        cmd.append("-m" + str(self.comp_value))
        cmd.append("-rr" + str(self.recovery_value) + "p")
        cmd.append("-ep1")
        cmd.append("-x.desktop")
        for f in sys.argv[1:]:
            full_cmd = cmd + [f + ".rar", f]
            sys.stdout.write("%s\n" % " ".join(full_cmd))
            subprocess.check_call(full_cmd)
        else:
            Gtk.main_quit()

if __name__ == "__main__":
    win = MyWindow()
    win.connect("delete-event", Gtk.main_quit)
    win.show_all()
    Gtk.main()

GNOME 系は Python が多いから Python の勉強しておいて良かったな〜と思ってるけど暫く書いてなかったからだいぶ忘れてる…。

今回参考にしたのは Python GTK+ 3 のドキュメント。Linux Mint の場合は各種ツールが同モジュールを使っているので何かを新しくインストールすることなくすぐに利用できる。日本語のドキュメントはほとんど無いけどサンプルコードが一緒に掲載されているので比較的わかりやすい。GitHub でこの情報を日本語に翻訳されている方がいたのでそちらも参考にさせていただいた。

インターフェイスの作成は Glade を使ってグラフィカルに行うこともできる。Glade で作成したレイアウトデータを Python スクリプトの中で Gtk.Builder() を使って追加するだけなので簡単。(今回は部品が少なかったので Glade を使わずに grid で配置した)

これを機に PyGTK の方も勉強してみようかなぁ。