Paepoi

Paepoi » PyGObject Tips » 非推奨になったもの

非推奨になったもの

せっかくページを作ったけど非推奨になった Widget はココに移動します。
タッチパネルに不向きなもの、レガシーな UI は今後も廃止が続くと思う。

GtkUIManager

GtkUIManager を使えばそれらを簡単にかつスッキリ実装できます。
ニーモニック、アクセラレータ、ツールチップも GtkActionEntry で一括指定可能。

GtkAccelGroup の処理はこちらでも必要です。
GtkActionEntry は Python では単なるタプルでデフォルト引数もある。
その GtkActionEntry 最初の引数に XML で指定した action を指定しその他を実装していく。
ソレをリストにして GtkActionGroup として登録。
それを GtkUIManager で XML と結びつける、後は取り出せばメニューバー等は完成している。

ハンドラの action は呼び出した GtkAction です。
GtkCheckMenuItem でチェック状態等をこの引数から得ることができます。

ちなみに StockItem を利用するとアクセラレータはストックのものが上書き反映されるので注意。
後は下記コードのコメントで。
#!/usr/bin/env python3

from gi.repository import Gtk, Gdk

ui_str = """<ui>
    <menubar name="MenuBar">
        <menu action="File">
            <menuitem action="open"/>
            <separator/>
            <menuitem action="quit"/>
        </menu>
    </menubar>
    <toolbar name="ToolBar">
        <toolitem action="open"/>
        <separator/>
        <toolitem action="quit"/>
    </toolbar>
    <popup name="PopUp">
        <menuitem action="open"/>
        <menuitem action="quit"/>
    </popup>
</ui>"""

class Win(Gtk.Window):
    """
        GtkUIManager でメニュー、ツールバー、右クリックメニュー
    """
    def __init__(self):
        Gtk.Window.__init__(self)
        # GtkUIManager 作成
        uimanager = Gtk.UIManager()
        # GtkAccelGroup を取り出し self に挿入
        accelgroup = uimanager.get_accel_group()
        self.add_accel_group(accelgroup)
        # GtkActionGroup 作成
        actiongroup = Gtk.ActionGroup("nandemoii")
        # GtkActionEntry の list を作成
        # (name, stock_id, label, accelerator=None, tooltip=None, callback=None)
        action_entry = [
            ("File", None, "ファイル(_F)"),
            ("open", Gtk.STOCK_OPEN, None, "<Control>O", "新しいドキュメントを開きます", self.on_open),
            ("quit", Gtk.STOCK_QUIT, None, "<Control>Q", "終了します", self.on_quit) ]
        actiongroup.add_actions(action_entry)
        # GtkUIManager の更新
        uimanager.insert_action_group(actiongroup, 0)
        uimanager.add_ui_from_string(ui_str)
        # メニュー、ツールバー、ポップアップメニューを取り出す
        menubar = uimanager.get_widget("/MenuBar")
        toolbar = uimanager.get_widget("/ToolBar")
        self.popup_menu = uimanager.get_widget("/PopUp")
        # パッキング
        drawingarea = Gtk.DrawingArea()
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        vbox.pack_start(menubar, False, True, 0)
        vbox.pack_start(toolbar, False, True, 0)
        vbox.pack_start(drawingarea, True, True, 0)
        self.add(vbox)
        # 右クリック用の処理
        self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.STRUCTURE_MASK )
        self.connect("button_press_event", self.on_button_press)
        # キーボードのメニューキー用の処理
        self.connect("popup-menu", self.on_popup_menu)
        # いつもの処理
        self.set_title("UIManager")
        self.connect("delete-event", self.on_quit)
        self.resize(320, 240)
        self.show_all()

    def on_open(self, action, data=None):
        # メニューのラベルを変更することもできる
        action.set_label("開くを押したよ!")

    def on_quit(self, action, data=None):
        Gtk.main_quit()

    def on_popup_menu(self, widget, data=None):
        self.popup_menu.popup(None, None, None, None, 0, 0)

    def on_button_press(self, widget, event, data=None):
        if event.button == 3:
            self.popup_menu.popup(None, None, None, None, 0, event.time)

if __name__ == "__main__":
    Win()
    Gtk.main()
ツールバーや右クリックメニューを別々に作らず実装できてしまいます。
並び順を変更したい場合も XML で指定するだけです。

RadioAction, ToggleAction

GtkUIManager はラジオメニューやトグルメニューも作れます。
GtkRadioActionEntry, GtkToggleActionEntry は引数が若干違いますので注意。
以下簡単なサンプルコードを。
#!/usr/bin/env python3

from gi.repository import Gtk, Gdk, GLib

ui_str = """<ui>
    <menubar name="MenuBar">
        <menu action="Color">
            <menuitem action="red"/>
            <menuitem action="blue"/>
        </menu>
        <menu action="Line">
            <menuitem action="circle"/>
        </menu>
    </menubar>
    <toolbar name="ToolBar">
        <toolitem action="red"/>
        <toolitem action="blue"/>
        <separator/>
        <toolitem action="circle"/>
    </toolbar>
    <popup name="PopUp">
        <menuitem action="red"/>
        <menuitem action="blue"/>
        <separator/>
        <menuitem action="circle"/>
    </popup>
</ui>"""

class Win(Gtk.Window):
    """
        GtkUIManager で GtkRadioAction, GtkToggleAction
    """
    def __init__(self):
        Gtk.Window.__init__(self)
        # Variant
        self.color = False
        self.circle = False
        # GtkUIManager
        uimanager = Gtk.UIManager()
        accelgroup = uimanager.get_accel_group()
        self.add_accel_group(accelgroup)
        actiongroup = Gtk.ActionGroup("nandemoii")
        # GtkActionEntry の list
        # (name, stock_id, label, accelerator=None, tooltip=None, callback=None)
        action_entry = [
            ("Color", None, "ファイル(_F)"),
            ("Line", None, "ライン") ]
        actiongroup.add_actions(action_entry)
        # GtkRadioActionEntry の list
        # (name, stock_id, label, accelerator, tooltip, value)
        radio_action_entry = [
            ("red", None, "赤(_R)", None, "red", False),
            ("blue", None, "青(_B)", None, "blue", True) ]
        # (entries, value, callback)
        actiongroup.add_radio_actions(radio_action_entry, 0, self.on_radio)
        # GtkToggleActionEntry の list
        # (name, stock_id, label, accelerator, tooltip, callback, is_active)
        toggle_action_entry = [
            ("circle", None, "まる(_C)", None, "丸を書く", self.on_toggled) ]
        actiongroup.add_toggle_actions(toggle_action_entry)
        # GtkUIManager の更新
        uimanager.insert_action_group(actiongroup, 0)
        uimanager.add_ui_from_string(ui_str)
        # メニュー、ツールバー、ポップアップメニューを取り出す
        menubar = uimanager.get_widget("/MenuBar")
        toolbar = uimanager.get_widget("/ToolBar")
        self.popup_menu = uimanager.get_widget("/PopUp")
        # GtkDrawingArea
        self.drawingarea = Gtk.DrawingArea()
        self.drawingarea.connect("draw", self.on_draw)
        # パッキング
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        vbox.pack_start(menubar, False, True, 0)
        vbox.pack_start(toolbar, False, True, 0)
        vbox.pack_start(self.drawingarea, True, True, 0)
        self.add(vbox)
        # 右クリック用の処理
        self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.STRUCTURE_MASK )
        self.connect("button_press_event", self.on_button_press)
        # キーボードのメニューキー用の処理
        self.connect("popup-menu", self.on_popup_menu)
        # いつもの処理
        self.set_title("UIManager")
        self.connect("delete-event", Gtk.main_quit)
        self.resize(320, 240)
        self.show_all()

    def on_radio(self, action, current, data=None):
        self.color = action.get_current_value()
        self.drawingarea.queue_draw()

    def on_toggled(self, action, data=None):
        self.circle = action.get_active()
        self.drawingarea.queue_draw()

    def on_popup_menu(self, widget, data=None):
        self.popup_menu.popup(None, None, None, None, 0, 0)

    def on_button_press(self, widget, event, data=None):
        if event.button == 3:
            self.popup_menu.popup(None, None, None, None, 0, event.time)

    def on_draw(self, widget, cr):
        # サイズを得る
        width = widget.get_allocated_width()
        height = widget.get_allocated_height()
        # 塗りつぶす
        if self.color:
            cr.set_source_rgb(0, 0, 1)
        else:
            cr.set_source_rgb(1, 0, 0)
        cr.rectangle(0, 0, width, height)
        cr.fill()
        # 四角か丸を書く
        cr.set_source_rgb(0, 0, 0)
        if self.circle:
            cr.arc(width/2, height/2, min(width, height)/2, 0, 2*GLib.PI)
            cr.stroke()
        else:
            cr.rectangle(20, 20, width-40, height-40)
            cr.stroke()

if __name__ == "__main__":
    Win()
    Gtk.main()
img/action.png

GtkAlignment

GtkAlignment は親の拡大時に子ウイジェットの追従位置と拡大比率を指定するコンテナです。

Gtk.Alignment.new(xalign, yalign, xscale, yscale)
引数はすべて 0.0〜1.0 で指定
xalign, yalign は数値が大きいほど右下に追従
xscale, yscale は 0 なら拡大しない、1 なら通常の Expand になる。

正直右下に張り付くボタンくらいしか使い道が無いと思う。
scale が 1 だと追従は無意味だし GtkBox で充分だし。
#!/usr/bin/env python3

from gi.repository import Gtk

class AlignmentWin(Gtk.Window):
    def __init__(self):
        """
            拡大してもサイズが変わらない
            かつ右下九割の位置に張り付くボタン
        """
        Gtk.Window.__init__(self)
        self.set_title("Alignment")
        self.connect("delete-event", Gtk.main_quit)
        # GtkAlignment
        al = Gtk.Alignment.new(0.9, 0.9, 0, 0)
        button = Gtk.Button.new_with_label("右下")
        al.add(button)
        self.add(al)
        #
        self.resize(300, 150)
        self.show_all()

AlignmentWin()
Gtk.main()
img/gtk_alignment.png

GtkTable

Gtk+3.2 より GtkTable は廃止になり GtkGrid を使ってくれになりました。
table.attach(left, right, top, bottom) を絶対値で指定だったのが
grid.attach(left, top, width, height) となったので全置換では対応できません...

GtkAttachOptions は GtkWidget の expand プロパティ。
padding の指定も GtkWidget の margin プロパティにて対応可能です。
Copyright(C) sasakima-nao All rights reserved 2002 --- 2024.