L'Isola di Niente
L'Isola di Niente » PyGObject Tips » 一行 EDIT

一行 EDIT

Windows でいう EDIT コントロールは GTK+ では GtkEntry です、ただし一行エディット。
マルチラインエディットは GtkTextView というまったくの別 Widget になっています。

GtkEntry

基本的に get_text() で文字列取得、set_text() で文字列挿入できる widget である。

しかし Windows の EDIT コントロールよりはるかに標準で用意された機能が多いです。
GtkEditable もインプリメントしているのでそちらの関数も利用可能。

様々な機能がありますがここではよく使いそうなものを。
#!/usr/bin/env python3

from gi.repository import Gtk

class Dlg(Gtk.Dialog):
    def __init__(self):
        Gtk.Dialog.__init__(self, buttons=(Gtk.STOCK_CLOSE, Gtk.ResponseType.CLOSE))
        # 文字数をカウント
        button = Gtk.Button.new_with_label("文字数をカウントします")
        button.connect("clicked", self.on_button_clicked)
        self.vbox.pack_start(button, False, False, 0)
        # GtkEntry、最低横サイズをセットする
        self.entry = Gtk.Entry()
        self.entry.set_size_request(300, -1)
        self.vbox.pack_start(self.entry, False, False, 0)
        # Entry にフォーカスがある状態で Enter
        self.entry.connect("activate", self.on_entry_activate)
        # 何も書かれていなくフォーカスが無い時に表示するテキスト
        self.entry.set_placeholder_text("何か書いてください")
        # 十文字しか打ち込めないように(漢字を含む)
        self.entry.set_max_length(10)
        # クリアアイコンの追加
        self.entry.set_icon_from_stock (Gtk.EntryIconPosition.SECONDARY, Gtk.STOCK_CLEAR);
        self.entry.connect("icon-press", self.on_entry_icon_press)
        # パスワード(隠し文字)形式に切り替える
        check_password = Gtk.CheckButton.new_with_label("パスワード形式")
        check_password.connect("toggled", self.on_check_password_toggled)
        self.vbox.pack_start(check_password, False, False, 0)
        # 描写位置指定ラジオボタン
        radio_left = Gtk.RadioButton.new_with_label_from_widget(None, "左寄せ")
        radio_left.connect("toggled", self.on_radio_toggled, 0)
        self.vbox.pack_start(radio_left, False, False, 0)
        radio_center = Gtk.RadioButton.new_with_label_from_widget(radio_left, "中央")
        radio_center.connect("toggled", self.on_radio_toggled, 0.5)
        self.vbox.pack_start(radio_center, False, False, 0)
        radio_right  = Gtk.RadioButton.new_with_label_from_widget(radio_left, "右寄せ")
        radio_right.connect("toggled", self.on_radio_toggled, 1.0)
        self.vbox.pack_start(radio_right, False, False, 0)
        self.show_all()

    def on_button_clicked(self, widget):
        n = self.entry.get_text_length()
        widget.set_label("{0} 文字です".format(n))

    def on_entry_activate(self, widget):
        if widget.get_text() == "exit":
            self.emit("delete-event", None)

    def on_check_password_toggled(self, widget):
        self.entry.set_visibility(not widget.get_active())

    def on_radio_toggled(self, widget, num):
        self.entry.set_alignment(num)

    def on_entry_icon_press(self, widget, icon_pos, event):
        if icon_pos == Gtk.EntryIconPosition.SECONDARY:
            widget.set_text("")

if __name__ == "__main__":
    dlg = Dlg()
    dlg.run()
    dlg.destroy()

img/entry1.png

Entry にフォーカスが当たると placeholder_text は消えます。
ほうきアイコンをクリックすると文字列がクリアされます。
ボタンを押せば解るとおり get_text_length() は日本語でも一文字としてカウントされます。
exit と書き込んで Enter するとダイアログが閉じます。

GtkSearchEntry

GtkSearchEntry は GTK+3.6 で追加された検索窓用途の Entry です。
上記ほうきアイコンのような機能等を最初から用意している(だけ)の Entry です。
Gedit, Devhelp 等の Ctrl+F に使われている、多分見た目の統一を狙った Widget と思われます。
#!/usr/bin/env python3

from gi.repository import Gtk

class SearchEntryWin(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        se = Gtk.SearchEntry.new()
        self.add(se)
        self.connect("delete-event", Gtk.main_quit)
        self.show_all()

SearchEntryWin()
Gtk.main()

img/gtk_searchentry.png

GtkEntryBuffer

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

from gi.repository import Gtk

class BufWin(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        # GtkEntryBuffre を共有させる
        entry1 = Gtk.Entry()
        buf = entry1.get_buffer()
        entry2 = Gtk.Entry()
        entry2.set_buffer(buf)
        # 数値以外は打ち込めないようにする
        buf.connect("inserted-text", self.on_buf_inserted_text)
        #
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        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)

if __name__ == "__main__":
    BufWin()
    Gtk.main()

img/entrybuf.png

GtkEntryCompletion

GtkEntryCompletion は GtkEntry に入力支援機能を追加する widget です。
#!/usr/bin/env python3

from gi.repository import Gtk

class CompWin(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        # GtkEntry
        entry = Gtk.Entry()
        # GtkEntryCompletion
        completion = Gtk.EntryCompletion()
        entry.set_completion(completion)
        # Inline
        completion.set_inline_completion(True)
        # GtkListStore
        liststore = Gtk.ListStore(str)
        liststore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        # Set
        completion.set_model(liststore)
        completion.set_text_column(0)
        for item in ["madoka", "mami", "sayaka", "kyoko", "homura" ]:
            liststore.append([item])
        #
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        vbox.pack_start(entry, False, False, 0)
        self.add(vbox)
        self.show_all()

if __name__ == "__main__":
    CompWin()
    Gtk.main()
起動して m と打ち込んでみましょう。

img/entrycomp.png

このように先頭から ListStore に登録した文字列と一致したテキストをドロップダウンします。
inline_completion が True なら一致した部分が自動的に流し込まれます。

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

from gi.repository import Gtk

class CompWin(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        # GtkEntry
        entry = Gtk.Entry()
        # GtkEntryCompletion
        completion = Gtk.EntryCompletion()
        entry.set_completion(completion)
        # Inline
        completion.set_inline_completion(True)
        # set match function
        completion.set_match_func(self.match_func, None)
        # GtkListStore
        liststore = Gtk.ListStore(str)
        liststore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        # Set
        completion.set_model(liststore)
        completion.set_text_column(0)
        for item in ["madoka", "mami", "sayaka", "kyoko", "homura" ]:
            liststore.append([item])
        #
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        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 in text:
            return True
        return False

if __name__ == "__main__":
    CompWin()
    Gtk.main()

img/entrycomp2.png
Copyright(C) sasakima-nao All rights reserved 2002 --- 2017.