Paepoi

Paepoi » PyGObject Tips » Gtk(PyGObject) Tips | 一行 EDIT

Gtk(PyGObject) Tips | 一行 EDIT

# 最終更新日 2019.08.18

2019 年現在の仕様に追記と書き換え。

GtkEntry
Windows でいう EDIT コントロールは GTK+ では GtkEntry です、ただし一行エディット。
マルチラインエディットは GtkTextView というまったくの別 Widget になっています。
基本的に text プロパティで文字列の取得や挿入ができる widget である。

EDIT コントロールや NSTextField よりはるかに標準で用意された機能が多いです。
GtkEditable もインプリメントしているのでそちらの関数も利用可能。
様々な機能がありますがここではよく使いそうなものを。
#!/usr/bin/env python3

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

class Win(Gtk.ApplicationWindow):
    '''
        標準で Cocoa の NSTextField 顔負けの多機能っぷり
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='Py', resizable=False)
        # 普通のエントリー
        self.entry1 = Gtk.Entry()
        # 何か書くまで文字列表示
        self.entry2 = Gtk.Entry(placeholder_text='何か書くと消えます')
        # 先頭にアイコン、クリックすると文字列流し込み
        self.entry3 = Gtk.Entry(primary_icon_name='document-edit-symbolic')
        self.entry3.connect('icon-press', self.on_entry_icon_press3)
        # 後方にアイコン、クリックするとクリア
        self.entry4 = Gtk.Entry(secondary_icon_name='edit-clear-all-symbolic')
        self.entry4.connect('icon-press', self.on_entry_icon_press4)
        # 右寄せ(0.0 〜 1.0)
        self.entry5 = Gtk.Entry(text='右寄せ', xalign=1.0)
        # パスワード
        self.entry6 = Gtk.Entry(text='pass', visibility=False)
        # 読み込み専用
        self.entry7 = Gtk.Entry(text='読み込み専用', editable=False)
        # pack
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.pack_start(self.entry1, False, False, 0)
        vbox.pack_start(self.entry2, False, False, 0)
        vbox.pack_start(self.entry3, False, False, 0)
        vbox.pack_start(self.entry4, False, False, 0)
        vbox.pack_start(self.entry5, False, False, 0)
        vbox.pack_start(self.entry6, False, False, 0)
        vbox.pack_start(self.entry7, False, False, 0)
        self.add(vbox)
        self.show_all()

    def on_entry_icon_press3(self, widget, icon_pos, event):
        self.entry3.props.text = 'スズキ'

    def on_entry_icon_press4(self, widget, icon_pos, event):
        self.entry4.props.text = ''

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
widget/gtkentry1.png
GtkEntryBuffer
GtkEntry 上でテキストの加工を行いたい、又は制限や加えたい場合があります。
その場合はバッファ部を抜き出してシグナルを利用する方法があります。
バッファは複数 Entry で共有することもできます、共有すると完全に同じテキストになります。
#!/usr/bin/env python3

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

class Win(Gtk.ApplicationWindow):
    '''
        更に多機能
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='Py', resizable=False)
        # GtkEntryBuffre を共有させる
        entry1 = Gtk.Entry()
        buf = entry1.get_buffer()
        entry2 = Gtk.Entry()
        entry2.set_buffer(buf)
        # 何か入力する毎に送信されるシグナル
        buf.connect('inserted-text', self.on_buf_inserted_text)
        # pack
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.pack_start(entry1, False, False, 0)
        vbox.pack_start(entry2, False, False, 0)
        self.add(vbox)
        self.show_all()

    def on_buf_inserted_text(self, buf, position, chars, n_chars):
        '''
            数値以外は打ち込めないようにする
        '''
        if not chars.isdigit():
            buf.delete_text(position, n_chars)

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
widget/gtkentry2.png
GtkEntryCompletion
GtkEntryCompletion は GtkEntry に入力支援機能を追加する widget です。
#!/usr/bin/env python3

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

class Win(Gtk.ApplicationWindow):
    '''
        text_column をプロパティ指定すると補完文字が表示されない、何故???
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='Py', resizable=False)
        # GtkListStore
        liststore = Gtk.ListStore(str)
        liststore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        for item in ['GSX-R1000', 'GSR400', 'Hayabusa', 'SV650', 'GSX-S1000', 'ST250']:
            liststore.append([item])
        # GtkEntryCompletion
        completion = Gtk.EntryCompletion(inline_completion=True, model=liststore)#, text_column=0)
        completion.set_text_column(0)
        # GtkEntry
        entry = Gtk.Entry(completion=completion)
        # pack
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.pack_start(entry, False, False, 0)
        self.add(vbox)
        self.show_all()

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
で、 起動して小文字の g と打ち込んでみましょう。
大文字小文字関係なく g から始まる候補が表示されました。
今度は大文字で G と打ち込んでみましょう。

widget/gtkentry3.png

今度は勝手に GS まで自動補完されました。
このように先頭から ListStore に登録した文字列と一致したテキストをドロップダウンします。
inline_completion が True なら完全一致した部分が自動的に流し込まれます。
Nautilus で Ctrl+L を叩いてパス名を打っていると勝手に補完するのと同様な動作です。

devhelp 等の検索機能でお馴染みの途中の文字列も検索対象にしたい場合もあります。
set_match_func() にマッチ判断する自作関数を指定、True を戻せばマッチと判断します。
#!/usr/bin/env python3

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

class Win(Gtk.ApplicationWindow):
    '''
        text_column をプロパティ指定すると補完文字が表示されない、何故???
    '''
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app, title='Py', resizable=False)
        # GtkListStore
        liststore = Gtk.ListStore(str)
        liststore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        for item in ['GSX-R1000', 'GSR400', 'Hayabusa', 'SV650', 'GSX-S1000', 'ST250']:
            liststore.append([item])
        # GtkEntryCompletion
        completion = Gtk.EntryCompletion(inline_completion=True, model=liststore)#, text_column=0)
        completion.set_text_column(0)
        # 追加
        completion.set_match_func(self.match_func)
        # GtkEntry
        entry = Gtk.Entry(completion=completion)
        # pack
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.pack_start(entry, False, False, 0)
        self.add(vbox)
        self.show_all()

    def match_func(self, completion, key, it):
        '''
            大文字小文字関係なく途中にあっても見つける関数
        '''
        model = completion.get_model()
        text = model.get_value(it, 0)
        if key.lower() in text.lower():
            return True
        return False

class App(Gtk.Application):
    def __init__(self):
        Gtk.Application.__init__(self)

    def do_startup(self):
        Gtk.Application.do_startup(self)
        Win(self)

    def do_activate(self):
        self.props.active_window.present()

app = App()
app.run(sys.argv)
widget/gtkentry4.png
Copyright(C) sasakima-nao All rights reserved 2002 --- 2020.