Python GTK+3 チュートリアル

06. レイアウト コンテナ② Stack and StackSwitcher / HeaderBar / FlowBox / Notebook

The Python GTK+ 3 Tutorial【6. Layout Containers】の後半部分を翻訳することで勉強しようと思いますが… だんだん飽きて来ましたー!

そもそもどうしてGUIフレームワークを勉強しようと思ったかというと、自分にとって使いやすい文字起こしツールを作りたいためなのです。アプリ開発の仕事に就きたいとかではないのですね。(シルバーおばさんに雇い主があらわれるとも思わない。)

で、自分用アプリが最終どういう形になるかがまだ見えないので、「どうしてもこれをマスターするんだ!」という気持ちがだんだん弱くなっていく。チュートリアルを丹念に追う根気が薄れていく。ああ、いけませんねえ、「ちょこっといじってすぐ飽きる」いつもの悪い癖が出つつあります。

とはいえ、せっかく始めたので Gtk はマスターしたいです。頑張ります。


6.4. スタックと StackSwitcher

Gtk.Stack は一度に一つの子だけを表示するコンテナです。Gtk.Notebook とは対照的に、Gtk.Stack は表示されている子をユーザが変更する手段を提供しません。代わりに、Gtk.StackSwitcher ウィジェットを一緒に使うことで、この機能を提供することができます。

ページ間の遷移は、スライドやフェードとしてアニメーションさせることができます。これは Gtk.Stack.set_transition_type() で制御できます。これらのアニメーションは “gtk-enable-animations” の設定に従います。

トランジションの速度は Gtk.Stack.set_transition_duration() で調整できます。

Gtk.StackSwitcher ウィジェットは Gtk.Stack のコントローラとして動作します。Gtk.StackSwitcher には、関連するウィジェットのスタック内の様々なページを切り替えるボタンが並んで表示されます。

ボタンの内容はすべて Gtk.Stack の子プロパティから来ています。

複数の Gtk.StackSwitcher ウィジェットを同じ Gtk.Stack ウィジェットに関連付けることができます。

6.4.1. 例

スタックと StackSwitcher
# tut06-04.py
# スタックとStackSwitcherの例

import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk


class StackWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Stack Demo")
        self.set_border_width(10)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        self.add(vbox)

        stack = Gtk.Stack()
        stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
        stack.set_transition_duration(1000)

        checkbutton = Gtk.CheckButton("Click me!")
        stack.add_titled(checkbutton, "check", "Check Button")

        label = Gtk.Label()
        label.set_markup("<big>A fancy label</big>")
        stack.add_titled(label, "label", "A label")

        stack_switcher = Gtk.StackSwitcher()
        stack_switcher.set_stack(stack)
        vbox.pack_start(stack_switcher, True, True, 0)
        vbox.pack_start(stack, True, True, 0)


win = StackWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

6.5.ヘッダーバー

Gtk.HeaderBar は横長の Gtk.Box に似ていて、子を先頭や末尾に配置することができます。さらに、タイトルも表示できます。タイトルは、たとえ両側の子が異なるスペースを占めている場合でも、ボックスの幅を基準にして中央に配置されます。

GTK+ がクライアント側でのデコレーションをサポートするようになったので、タイトルバーの代わりに Gtk.HeaderBar を使用することができます (ウィンドウマネージャによってレンダリングされます)。

Gtk.HeaderBar は通常ウィンドウの上部に配置され、下のコンテンツに影響を与えるようなコントロールが格納されます。また、「ウィンドウを閉じるボタン」や「ウィンドウメニュー」などのウィンドウコントロールへのアクセスを提供します。

6.5.1. 例

ヘッダーバー
# tut06-05.py
# HeaderBarの例

import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio


class HeaderBarWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="HeaderBar Demo")
        self.set_border_width(10)
        self.set_default_size(400, 200)

        hb = Gtk.HeaderBar()
        hb.set_show_close_button(True)
        hb.props.title = "HeaderBar example"
        self.set_titlebar(hb)

        button = Gtk.Button()
        icon = Gio.ThemedIcon(name="mail-send-receive-symbolic")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
        button.add(image)
        hb.pack_end(button)

        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        Gtk.StyleContext.add_class(box.get_style_context(), "linked")

        button = Gtk.Button()
        button.add(Gtk.Arrow(Gtk.ArrowType.LEFT, Gtk.ShadowType.NONE))
        box.add(button)

        button = Gtk.Button()
        button.add(Gtk.Arrow(Gtk.ArrowType.RIGHT, Gtk.ShadowType.NONE))
        box.add(button)

        hb.pack_start(box)

        self.add(Gtk.TextView())


win = HeaderBarWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

6.6. フローボックス

この例では、GTK+ 3.12以上が必要です。

※ Gtkのバージョンを確認するには:Gtkをインポートしたあと、Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION, Gtk.MICRO_VERSIONを表示する

Gtkのバージョンを確認

Gtk.FlowBox は、子ウィジェットをその向きに応じて順番に配置するコンテナです。

例えば、水平方向の場合、ウィジェットは左から右へと配置され、必要に応じて前の行の下に新しい行が始まります。この場合、幅を狭くすると行数が多くなるので、高さを大きくする必要があります。

同様に垂直方向にすると、ウィジェットは上から下へと配置され、必要に応じて既存の列の右に新しい列を開始します。高さを下げると、より多くの列が必要になるので、幅を大きくする必要があります。

Gtk.FlowBox の子は動的にソートやフィルタリングを行うことができます。

Gtk.FlowBox Gtk.FlowBoxChild という子だけしか持てませんが、Gtk.Container.add() を通して任意の種類のウィジェットを追加することができ、ボックスとウィジェットの間に Gtk.FlowBoxChild ウィジェットが自動的に挿入されます。

6.6.1. 例

FlowBox
# tut06-06.py
# FlowBoxの例

import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk


class FlowBoxWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="FlowBox Demo")
        self.set_border_width(10)
        self.set_default_size(400, 230)

        header = Gtk.HeaderBar(title="Flow Box")
        header.set_subtitle("Sample FlowBox app")
        header.props.show_close_button = True

        self.set_titlebar(header)

        scrolled = Gtk.ScrolledWindow()
        scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)

        flowbox = Gtk.FlowBox()
        flowbox.set_valign(Gtk.Align.START)
        flowbox.set_max_children_per_line(30)
        flowbox.set_selection_mode(Gtk.SelectionMode.NONE)

        self.create_flowbox(flowbox)

        scrolled.add(flowbox)

        self.add(scrolled)
        self.show_all()

    def on_draw(self, widget, cr, data):
        context = widget.get_style_context()

        width = widget.get_allocated_width()
        height = widget.get_allocated_height()
        Gtk.render_background(context, cr, 0, 0, width, height)

        r, g, b, a = data["color"]
        cr.set_source_rgba(r, g, b, a)
        cr.rectangle(0, 0, width, height)
        cr.fill()

    def color_swatch_new(self, str_color):
        color = Gdk.color_parse(str_color)

        rgba = Gdk.RGBA.from_color(color)
        button = Gtk.Button()

        area = Gtk.DrawingArea()
        area.set_size_request(24, 24)
        area.connect("draw", self.on_draw, {"color": rgba})

        button.add(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",
        ]

        for color in colors:
            button = self.color_swatch_new(color)
            flowbox.add(button)


win = FlowBoxWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

6.7.ノートブック

Gtk.Notebook ウィジェットは、片側のエッジに沿ったタブを使ってページを切り替えられるような Gtk.Container です。

GtkNotebookには多くの設定オプションがあります。中でも、タブをどの辺に表示するか (Gtk.Notebook.set_tab_pos() を参照)、タブが多すぎてノートに収まらない場合はノートブックを大きくするか矢印を追加したりするかどうか (Gtk.Notebook.set_scrollable() を参照) 、ユーザがページを切り替えるためのポップアップメニューがあるかどうか(Gtk.Notebook.popup_enable(), Gtk.Notebook.popup_disable() を参照)が指定できます。

6.7.1. 例

ノートブック
# tut06-07.py
# Notebookの例

import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk


class MyWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Simple Notebook Example")
        self.set_border_width(3)

        self.notebook = Gtk.Notebook()
        self.add(self.notebook)

        self.page1 = Gtk.Box()
        self.page1.set_border_width(10)
        self.page1.add(Gtk.Label("デフォルトページです!"))
        self.notebook.append_page(self.page1, Gtk.Label("Plain Title"))

        self.page2 = Gtk.Box()
        self.page2.set_border_width(10)
        self.page2.add(Gtk.Label("タイトル画像付きのページです。"))
        self.notebook.append_page(
            self.page2, Gtk.Image.new_from_icon_name("help-about", Gtk.IconSize.MENU)
        )


win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()


関連記事