GTK+」タグアーカイブ

GTK4: ActionBar and CenterBox

GTK4 は CenterBox という Widget が追加された。
説明を見ると GTK3 にあった ActionBar みたいなものか。
って ActionBar は GTK4 にも残っているんですけど。

Gtk.ActionBar

Gtk.CenterBox

ActionBar の CSS Node には Revealer というものがある。
これは Gtk::Revealer ではなく単純に表示と非表示の切り替えみたい。
Widget::show では何か都合が悪かったのだろうか?
ちなみに HeaderBar と違うのは背景透過であること。
フルスクリーンで使おうとしたけど背景が無くて文字列が読めないんでパス。

対する CenterBox は Widget ベースな単一ノード。
Gtk::Orientable インプリメントなので縦にもできるようだ。
でも縦に並んだ Widget で中心に何か置きたいという状況が思いつかない。

そういえば ButtonBox はとうとう無くなったな。
これの代わりってことかも、試してみよう。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk

class Win(Gtk.ApplicationWindow):
    '''
        GTK4: Sample Code
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a, title='GTK4')
        buttons = [Gtk.Button(label=f'Button{i+1}', hexpand=True) for i in range(6)]
        # ActionBar
        bar = Gtk.ActionBar()
        bar.pack_start(buttons[0])
        bar.set_center_widget(buttons[1])
        bar.pack_end(buttons[2])
        # CenterBox
        box = Gtk.CenterBox()
        box.set_start_widget(buttons[3])
        box.set_center_widget(buttons[4])
        box.set_end_widget(buttons[5])
        #
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.append(bar)
        vbox.append(box)
        self.set_child(vbox)
        self.set_default_size(400, 1)

def app_activate(a):
    w = Win(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

centerbox

hexpand を指定してみたけど、引き伸ばされるのは共にセンターのみ。
ButtonBox のように等間隔に引き伸ばされると思ったけど違っていた。

違うのは ActionBar は挿入した Widget の回りに隙間ができるかどうか、のみ。
HeaderBar のよう Button を置きたいなら ActionBar を。
ステータスバーのように Label を置きたいなら CenterBox を。
という感じか。
まったくベースは違うけどあまり使い道は変わらない。

GTK4: ShortcutAction

前回 Gtk::Shortcut で SignalAction や ActivateAction を使いました。
これらは ShortcutAction のサブクラス、それらから必要なものを選びます。
名前でどういう用途かはだいたい解りますよね。

Gtk.ShortcutAction

その ShortcutAction の関数を見ると activate という関数がある。
第二引数に指定した Widget に activate を送る命令みたい、コレはもしかして!
GTK4 で排除された「ボタンをコードで模擬クリック」をコイツで賄えるかも。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk

class Win(Gtk.ApplicationWindow):
    '''
        GTK4: Sample Code
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a, title='GTK4')
        # Action
        self.act_action = Gtk.ActivateAction()
        # Button
        b1 = Gtk.Button(label='Button1')
        b1.connect('clicked', self.on_button1_clicked)
        self.b2 = Gtk.Button(label='Button2')
        self.b2.connect('clicked', self.on_button2_clicked)
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.append(b1)
        box.append(self.b2)
        self.set_child(box)

    def on_button1_clicked(self, widget):
        print('Button1 Clicked!')
        self.act_action.activate(Gtk.ShortcutActionFlags.EXCLUSIVE, self.b2)

    def on_button2_clicked(self, widget):
        print('Button2 Clicked!')

def app_activate(a):
    w = Win(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

Button1 を押すと Button2 も押されることが GUI でも確認できるはず。
なるほど、コードで模擬クリックがしたいならこの手段が使えます。
第一引数は固定なので存在理由が不明ですが今後増えるかも、ということで。
本来の使い方では無いのでしょうけど、使い道は多かったりします。

GTK4: Shortcut

GTK4 には ShortcutController というものがあった。
あれ?筆者は以前嘘を書いてしまったのかな??

Gtk.ShortcutController

そう思って調べてみるとコレはアプリ全体のショートカット指定ではない。
Widget 毎にショートカットを設定するものってことみたい。
何が違うんだよって感じはしなくはないですけど。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk

class Win(Gtk.ApplicationWindow):
    '''
        GTK4: Sample Code
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a, title='GTK4')
        # Shortcut
        t = Gtk.ShortcutTrigger.parse_string('<Control>Z')
        a = Gtk.SignalAction(signal_name='clicked')
        s = Gtk.Shortcut(trigger=t, action=a)
        c = Gtk.ShortcutController()
        c.add_shortcut(s)
        # Button
        b = Gtk.Button(label='Test')
        b.connect('clicked', self.on_button_clicked)
        b.add_controller(c)
        self.set_child(b)

    def on_button_clicked(self, widget):
        print('Clicked!')

def app_activate(a):
    w = Win(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

こんな感じ。

これで Ctrl+z でも clicked シグナルを発生できます。
ところで公式は GtkBuilder 形式にて activate を指定しています。

a = Gtk.ActivateAction()

でもいいです、こちらだとボタンが押された GUI アクションを行なわれます。
ただ activate と clicked 両方のシグナルが発生しますので扱いに注意。

ということでゴールデンウイークラストは花。

poppy

フラワーパーク江南にてシャーレーポピーが満開です。
くーるまにポピー♪って古い!

poppy

日本語名はヒナゲシです。
おっかのうえヒーナゲシのはーなでー♪だから古い!

sirotumekusa

一面にシロツメクサが咲き誇っています。
シロツメクサの♪花が咲いたら♪さあ♪いこー♪ラスカール!

花は素晴らしい、行けば必ず撮れるもん。
それよりデジイチを持っている人が沢山いるから浮かないのがいい。
ところで 17mm パンケーキとプロレンズの差を今更ながら痛感する。
去年まではボケの奇麗さなんて気にしなかったのに困った。

GTK4: Image

GtkImage が GTK3 から結構変わっていた。
そもそものインプリメント関数がまるっきり違うし。

pixbuf や surface プロパティが無くなった。
surface にいたっては new_*** すら削除されている、変換しろってことですね。
pixbuf は筆者が使っているぞ、 new_*** が残っていて良かった。
そんなことよりコレですよ。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk

class RadioWin(Gtk.ApplicationWindow):
    '''
        GTK4: GtkPicture
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a, title='GTK4')
        image = Gtk.Image(file='400x300px.jpg')
        self.set_child(image)
        #image.set_pixel_size(400)

def app_activate(a):
    w = RadioWin(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

GTK4.

#!/usr/bin/env python3

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

class Win(Gtk.ApplicationWindow):
    '''
        GTK3: GtkPicture
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a, title='GTK3')
        image = Gtk.Image(file='400x300px.jpg')
        self.add(image)
        self.show_all()

def app_activate(a):
    w = Win(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

GTK3.

gtkimage

と、GTK3 と違い画像サイズに自動的設定されなくなっています。
コメントアウトを外すとリサイズできますが正方形にしかできません。

gtkimage

GTK3 の仕様だと巨大画像を間違って読み込むと本当にそのサイズになっていたし。
この Widget はアイコン用途にしか使っては駄目ですよってことなんでしょう。
どうしても GTK3 の時と同じでないと困る場合は GtkPicture を使います。

#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gio

class RadioWin(Gtk.ApplicationWindow):
    '''
        GTK4: GtkPicture
    '''
    def __init__(self, a):
        Gtk.ApplicationWindow.__init__(self, application=a, title='GTK4')
        gfile = Gio.file_new_for_path('400x300px.jpg')
        pic = Gtk.Picture(file=gfile)
        self.set_child(pic)

def app_activate(a):
    w = RadioWin(a)
    w.present()

app = Gtk.Application()
app.connect('activate', app_activate)
app.run()

いや。
画像を表示したいなら素直に GtkDrawingArea にしましょうね。

ということで今日の GTK4 おしまい。
やっと、やっと夏鳥が撮影できました!

musikui

センダイムシクイ、のようです。
葉っぱ邪魔、見つかりづらいからココにいるんだと解っているけど。

ooruri

オオルリのメス、だと思う。
ほんとヒタギ類のメスって判別がむつかしい。

ooruri

オオルリのオス、これは誰でも間違えない。
キビタキもいたらしいけど筆者の前には現われなかった。

以上、ゴールデンウイーク完全オケラはギリギリ防げた。
おかげで GTK4 の勉強が捗ったのでなんともいえないけど。

GTK4: MenuButton

以前 GTK4 のメニューサンプルコードを書いたけど。
toggled なんてシグナルは GTK4 版には無かったね。
エラーが出なかったのは GTK4 に無視されていただけだったようだ。

んで、GTK4 版 GtkMenuButton には primary というプロパティが追加されていた。
コレを True にすると F10 キーでポップアップできるようになる。

ただ、それを利用するとフルスクリーンで使えない。
フルスクリーンにしないアプリなら問題ないんだけど。

それとコレを実装していて気が付いたんだけど。
GTK4 はボタン類の cricked 関数が全部消えている。
つまりコードで模擬クリックすることができなくなってしまった。
アレ便利だったのに、しかたがないから別の手段で。

ということで GTK4 にてフルスクリーン用メニューが別にある場合。
F10 を振り分けする必要がある。

class ComipoliApplication(Gtk.Application):
    def __init__(self, version):
        # etc...

    def do_startup(self):
        Gtk.Application.do_startup(self)
        self.set_accels_for_action('win.action_f10', ['F10'])

GtkApplication.

class ComipoliWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        # etc...
        action_f10 = Gio.SimpleAction.new('action_f10', None)
        action_f10.connect('activate', self.on_action_function_key, 10)
        self.add_action(action_f10)

    def on_action_function_key(self, action, param, num):
        if num == 10:
            if self.is_fullscreen:
                self.upperbar.show()
                GLib.idle_add(self.show_fullscreen_menu)
            else:
                self.menu.popup()

    def show_fullscreen_menu(self):
        self.menuf.popup()
        return False

GtkApplicationWindow.

コレでなんとかなったけど F10 の二度押しで消すことができない。
おまけにポップアップ状態から矢印キーでメニュー選択もできない。
gnome-text-editor も同じだから仕様なんだろうね。

それより、ポップアップを出すとフォーカスを取られてキー操作を受け付けない。
GtkMenuButton の popdown 関数は何のためにあるのだ?
これを利用して F10 二度押しを実装しようとしたけど、無理っぽい。

ということで GTK4 でポップアップを消すには Esc を使いましょう。
逆に言えば現状 GTK4 製かどうかはソレで見分けできる。

今回は GTK4 でのショートカット実装方法でした。
<Control>W とかも同じ方法で実装できるよ。