L'Isola di Niente
L'Isola di Niente » PyGObject Tips » ダイアログを作る

ダイアログを作る

ダイアログといえば設定ダイアログのような補助的なものを思い浮かべますが単体でも利用できます。
メインループ処理は不要で run() で表示し destroy() で破棄という流れで使います。

GtkDialog

GtkDialog の GTK3 バインディングは少々変わっていて new_with_button() メソッドは利用できません。
そのまま Gtk.Dialog() にバインドされているようです、しかも PyGtk 同様デフォルト引数付き。
多分継承して class として利用することが多い Python の特性に合わせたのだと思います。

ということで最小限コードはこんな感じでしょう。
#!/usr/bin/env python3

from gi.repository import Gtk

'''
    Gtk.Dialog(title=None, parent=None, flags=0, buttons=None)
    # This code results in an error
    dlg = Gtk.Dialog.new_with_buttons() # Error
'''

dlg = Gtk.Dialog(buttons=("homura", Gtk.ResponseType.CLOSE))
dlg.run()
dlg.destroy()

img/dlg1.png

title:   タイトルバー文字列
parent:  親ウインドウ、None ならデスクトップ
flags:   Gtk.DialogFlags.MODAL, Gtk.DialogFlags.DESTROY_WITH_PARENT の選択
buttons: 挿入する(ボタン文字列 or ストック、戻り値)をタプルで指定
ボタン文字列は通常多言語化が簡単なストックを利用したほうがいいでしょう。
Gtk.STOCK_CLOSE, Gtk.STOCK_CANCEL 等など。
戻り値は Gtk.ResponseType の以下から選択
NONE, REJECT, ACCEPT, DELETE_EVENT, OK, CANCEL, CLOSE, YES, NO, APPLY, HELP

又ボタンは複数指定することもできます。

GTK+ 3.4 からは vbox アトリビュートが使えるようになり更に PyGtk 同様になったようです。

ダイアログはリサイズ可能にさせたくない場合が多い、その場合 set_resizable(False) を指定。

以上を踏まえたサンプルコードを以下に。
#!/usr/bin/env python3

from gi.repository import Gtk

class Dlg(Gtk.Dialog):
    """
        GtkDialog Sample
    """
    def __init__(self):
        Gtk.Dialog.__init__(
                self,
                "Titlebar",
                None,
                Gtk.DialogFlags.MODAL,
                (Gtk.STOCK_YES, Gtk.ResponseType.YES,
                Gtk.STOCK_NO, Gtk.ResponseType.NO))
        # Tab Label strings
        tabs = ("1page", "2page", "3page")
        # Page List
        pages = []
        # Create GtkNotebook
        notebook = Gtk.Notebook()
        for s in tabs:
            vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
            label = Gtk.Label(s)
            notebook.append_page(vbox, label)
            pages.append(vbox)
        # Add Contents
        check = Gtk.CheckButton.new_with_label("Contents")
        pages[0].pack_start(check, False, False, 0)
        entry = Gtk.Entry()
        pages[1].pack_start(entry, False, False, 0)
        # Add self
        self.vbox.pack_start(notebook, False, False, 0)
        self.set_resizable(False)
        self.show_all()

dlg = Dlg()
dlg.run()
dlg.destroy()

GtkMessageDialog

GtkMessageDialog は GtkDialog のサブクラスで文字列の表示に特化した Widget です。
GtkDialog を使って同じことが可能ですが警告文の表示等に手間がかからず便利です。
#!/usr/bin/env python3

from gi.repository import Gtk

"""
    Gtk.MessageDialog(parent, flags, type, buttons, message)
"""

message = "「はい」を押すと終了"
icon = Gtk.MessageType.QUESTION

while 1:
    dlg = Gtk.MessageDialog(
            None,
            Gtk.DialogFlags.MODAL,
            icon,
            Gtk.ButtonsType.YES_NO,
            "まどかはカワイイ" )
    dlg.format_secondary_text(message)
    r = dlg.run()
    dlg.destroy()
    icon = Gtk.MessageType.ERROR
    if r == Gtk.ResponseType.YES:
        break
    elif r == Gtk.ResponseType.NO:
        message = "それは「いいえ」だろ!"
    elif r == Gtk.ResponseType.DELETE_EVENT:
        message = "閉じるボタンじゃネェ!"
    else:
        message = "不明な動作..."
GtkMessageType はアイコンです、以下から選択。
INFO, WARNING, QUESTION, ERROR, OTHER
GtkButtonsType は GtkDialog より簡素化されて ResponseType や複数ボタンもセットです。
NONE, OK, CLOSE, CANCEL, YES_NO, OK_CANCEL

format_secondary_text() でサブメッセージも表示できます。

やはり new_with_markup() で作成できないようですが set_markup() することは可能です。
dlg.set_markup("マミさんも<span font='30'>カワイイ</span>")

GtkAboutDialog

GtkAboutDialog は掟に従って作成するだけです。
#!/usr/bin/env python3

from gi.repository import Gtk

w = Gtk.AboutDialog()
#w.set_transient_for(self)

#w.set_logo(self.get_icon()) # アイコン
w.set_program_name("Test")
w.set_version("1.0.0")
w.set_comments("コメント")
w.set_website("http://localhost/")
w.set_website_label("localhost") # 指定しなければ「ホームページ」と表示
w.set_copyright("Copyright(C) 2012 sasakima-nao")

# ライセンスボタン、指定しなければボタンは出ない
w.set_license("GPL")

# クレジットボタン、文字列の List にする
w.set_authors(["sasakima-nao"])     # 開発担当
w.set_artists(["sasakima-nao"])     # アートワーク担当
w.set_documenters(["sasakima-nao"]) # ドキュメント担当
w.set_translator_credits("sasakima-nao") # 翻訳担当、ここは str

w.run()
w.destroy()
parent ウインドウを指定する引数が無いので set_transient_for() にて親ウインドウを指定。

self にアイコン指定済みなら上記関数でアイコンを利用できる。

GTK2 時と違い set_url_hook しなくても URL は開ける。

GtkAssistant

GtkAssistant は Windows でいうウィザードです。
対話形式で質問に答えていくことで複雑な処理を簡易に行う一つの手段である。

set_page_type() でページの種類を指定
set_page_complete() で次に進むボタンの ON/OFF
が行えます。
#!/usr/bin/env python3

from gi.repository import Gtk

TITLES = ("INTRO", "CONTENT", "PROGRESS", "SUMMARY or CONFIRM")

class AssistantWin(Gtk.Assistant):
    def __init__(self):
        """
            4 ページあるサンプル
        """
        Gtk.Assistant.__init__(self)
        self.connect("cancel", self.on_close)
        self.connect("close", self.on_close)
        self.connect("apply", self.on_apply)
        # Pages
        self.pages = []
        for title in TITLES:
            vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
            self.pages.append(vbox)
            self.append_page(vbox)
            self.set_page_title(vbox, title)
        # Introduction page
        label0 = Gtk.Label("導入ページ - 進んでください")
        self.pages[0].pack_start(label0, False, False, 0)
        self.set_page_type(self.pages[0], Gtk.AssistantPageType.INTRO)
        self.set_page_complete(self.pages[0], True)
        # Next page
        label1 = Gtk.Label("コンテンツページ - チェックすると次に進めます")
        check = Gtk.CheckButton.new_with_label("了解しました")
        check.connect("toggled", self.on_checkbutton_toggled)
        self.pages[1].pack_start(label1, False, False, 0)
        self.pages[1].pack_start(check, False, False, 0)
        self.set_page_type(self.pages[1], Gtk.AssistantPageType.CONTENT)
        # Next page
        label2 = Gtk.Label("進度ページ - 適用しますか?")
        r1 = Gtk.RadioButton.new_with_label_from_widget(None, "いいえ")
        r2 = Gtk.RadioButton.new_with_label_from_widget(r1, "はい")
        r2.connect("toggled", self.on_radiobutton_toggled)
        self.pages[2].pack_start(label2, False, False, 0)
        self.pages[2].pack_start(r1, False, False, 0)
        self.pages[2].pack_start(r2, False, False, 0)
        self.set_page_type(self.pages[2], Gtk.AssistantPageType.CONTENT)
        self.set_page_complete(self.pages[2], True)
        # Last page
        self.last_label = Gtk.Label("ウイザートを終了します")
        self.pages[3].pack_start(self.last_label, False, False, 0)
        self.set_page_type(self.pages[3], Gtk.AssistantPageType.SUMMARY)
        self.set_page_complete(self.pages[3], True)
        #
        self.show_all()

    def on_close(self, assistant, data=None):
        """
            delete-event もココにくる
        """
        Gtk.main_quit()

    def on_apply(self, assistant, data=None):
        """
            適用でココにくる
            close シグナルも発生するので main_quit 処理は不要
        """
        dlg = Gtk.MessageDialog(self, 0, 0, 2, "何かをする")
        dlg.run()
        dlg.destroy()

    def on_checkbutton_toggled(self, widget, data=None):
        """
            次に進むボタンの ON/OFF
        """
        self.set_page_complete(self.pages[1], widget.get_active())

    def on_radiobutton_toggled(self, widget, data=None):
        """
            CONFIRM, SUMMARY の振り分け
        """
        if widget.get_active():
            self.last_label.set_text("適用してください")
            self.set_page_type(self.pages[3], Gtk.AssistantPageType.CONFIRM)
        else:
            self.last_label.set_text("ウィザードを終了します")
            self.set_page_type(self.pages[3], Gtk.AssistantPageType.SUMMARY)

if __name__ == '__main__':
    AssistantWin()
    Gtk.main()
Copyright(C) sasakima-nao All rights reserved 2002 --- 2017.