L'Isola di Niente
L'Isola di Niente » PyGObject Tips » マルチライン EDIT

マルチライン EDIT

GtkTextView は View という名前ですが文字列の書き込みも行うこともできます。

GtkTextView

いわゆるマルチライン EDIT を使うなら GtkTextView を作成するだけです。
文字列を流し込んだり取得するには GtkTextBuffer を得てやりとりします。
GtkScrolledWindow を噛まさないと流し込んだ文字列分サイズが大きくなるので注意。
#!/usr/bin/env python3

from gi.repository import Gtk

TEXTFILE = "hoge.txt"

class TextReader(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.connect("delete-event", Gtk.main_quit)
        # GtkTextView
        view = Gtk.TextView()
        # Read Text File
        f = open(TEXTFILE)
        s = f.read()
        f.close()
        buf = view.get_buffer()
        buf.set_text(s)
        # GtkScrolledWindow
        sw = Gtk.ScrolledWindow()
        sw.add(view)
        self.add(sw)
        # self
        self.resize(300, 300)
        self.set_title("Text Reader")
        self.show_all()

TextReader()
Gtk.main()

フォントを変更するには Pango を利用します。
font_desc = Pango.font_description_from_string("Monospace 8")
view.override_font(font_desc)

GtkSourceView

GtkSourceView は Gedit や Anjuta 等のエディタ部分そのものです。
行番号表示等は組み込みされていますし色分け表示手段もあらかじめ用意されています。
このあたりは興味があったら調べてみるのも面白いと思う。

Gedit 3.12 以降モドキを書いてみました。
色分け機能追加
#!/usr/bin/env python3
  
import sys
from gi.repository import Gtk, Gio, Gdk, GtkSource, Pango
  
class Win(Gtk.ApplicationWindow):
    """
        Gedit モドキ、タブは無い
    """
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, title="Title", application=app)
        #
        # AccelGroup
        accelgroup = Gtk.AccelGroup.new()
        self.add_accel_group(accelgroup)
        # MenuIten
        item_saveas = Gtk.MenuItem.new_with_mnemonic("名前を付けて保存(_A)")
        item_saveas.connect("activate", self.on_saveas)
        item_saveas.show()
        item_saveas.add_accelerator("activate", accelgroup, Gdk.KEY_s,
                Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK, Gtk.AccelFlags.VISIBLE)
        item_quit = Gtk.MenuItem.new_with_mnemonic("終了(_Q)")
        item_quit.connect("activate", self.on_quit)
        item_quit.show()
        item_quit.add_accelerator("activate", accelgroup, Gdk.KEY_q,
                Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE)
        # Menu
        menu = Gtk.Menu.new()
        menu.append(item_saveas)
        menu.append(Gtk.SeparatorMenuItem.new())
        menu.append(item_quit)
        menu.props.halign = Gtk.Align.CENTER
        # GtkMenuButton
        menubutton = Gtk.MenuButton.new()
        menubutton.set_popup(menu)
        # F10 キーでドロップ処理
        menubutton.add_accelerator("clicked", accelgroup, Gdk.KEY_F10,
                0, Gtk.AccelFlags.VISIBLE)
        # 三本線の svg 画像を貼り付ける、GNOME 3.14 から
        image = Gtk.Image()
        image.set_from_icon_name("open-menu-symbolic", Gtk.IconSize.MENU)
        menubutton.set_image(image)
        #
        # Button
        openbutton = Gtk.Button.new_with_mnemonic("開く(_O)")
        openbutton.connect("clicked", self.on_open)
        accelgroup.connect(Gdk.KEY_o, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE, self.on_keydown)
        savebutton = Gtk.Button.new_with_mnemonic("保存(_S)")
        savebutton.connect("clicked", self.on_save)
        accelgroup.connect(Gdk.KEY_s, Gdk.ModifierType.CONTROL_MASK, Gtk.AccelFlags.VISIBLE, self.on_keydown)
        #
        # ヘッダーバーに置く
        hbar = Gtk.HeaderBar()
        hbar.pack_start(openbutton)
        hbar.pack_end(menubutton)
        hbar.pack_end(savebutton)
        hbar.set_show_close_button(True)
        self.set_titlebar(hbar)
        #
        # GtkSourceView
        self.view = GtkSource.View()
        # 行番号表示
        self.view.set_show_line_numbers(True)
        # Font
        font_desc = Pango.font_description_from_string("VL ゴシック 10")
        self.view.override_font(font_desc)
        # LanguageManager
        self.language_manager = GtkSource.LanguageManager.new()
        #
        # StatusBar
        statusbar = Gtk.Statusbar()
        #
        # Add
        sw = Gtk.ScrolledWindow()
        sw.add(self.view)
        vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
        vbox.pack_start(sw, True, True, 0)
        vbox.pack_start(statusbar, False, True, 0)
        # var
        self.open_filename = ""
        # self
        self.add(vbox)
        self.resize(320, 320)
        self.show_all()
 
    def read_file(self, path):
        buf = self.view.get_buffer()
        with open(path, "r") as f:
            buf.set_text(f.read())
            self.open_filename = path
            # 色分け処理
            obj = Gio.file_new_for_path(path)
            info = obj.query_info(
                Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
                Gio.FileQueryInfoFlags.NONE )
            contype = info.get_content_type()
            lang = self.language_manager.guess_language(None, contype)
            buf = self.view.get_buffer()
            buf.set_language(lang)
 
    def write_file(self):
        buf = self.view.get_buffer()
        t = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), False)
        with open(self.open_filename, "w") as f:
            f.write(t)
 
    def on_open(self, widget):
        dlg = Gtk.FileChooserDialog(
                "Open File",
                self,
                Gtk.FileChooserAction.OPEN,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, 
                Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT))
        r = dlg.run()
        if r == Gtk.ResponseType.ACCEPT:
            self.read_file(dlg.get_filename())
        dlg.destroy()
 
    def on_save(self, widget):
        if self.open_filename == "":
            self.on_saveas(widget)
        else:
            self.write_file()
 
    def on_saveas(self, widget):
        dlg = Gtk.FileChooserDialog(
                "Save File",
                self,
                Gtk.FileChooserAction.SAVE,
                (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, 
                Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT))
        r = dlg.run()
        if r == Gtk.ResponseType.ACCEPT:
            self.open_filename = dlg.get_filename()
            self.write_file()
        dlg.destroy()
 
    def on_quit(self, widget):
        self.emit("destroy")
 
    def on_keydown(self, accelGroup, window, keyval, modifier):
        if keyval == Gdk.KEY_s:
            self.on_save(None)
        elif keyval == Gdk.KEY_o:
            self.on_open(None)
 
 
class AppClass(Gtk.Application):
    def __init__(self):
        """
            多重起動しない
        """
        Gtk.Application.__init__(
                self,
                application_id="org.cc.sakura",
                flags=Gio.ApplicationFlags.HANDLES_OPEN )
  
    def do_startup(self):
        """
            do_startup 呼び出し必須
        """
        Gtk.Application.do_startup(self)
        self.window = Win(self)
  
    def do_activate(self):
        """
            実行時に引数指定無しだとココに来る
        """
        self.window.present()
  
    def do_open(self, files, n_file, hint):
        """
            実行時に引数を指定するとココに来る
        """
        self.window.read_file(files[0].get_path())
        self.window.present()
  
if __name__ == "__main__":
    app = AppClass()
    app.run(sys.argv)

img2/sourceview.png
Copyright(C) sasakima-nao All rights reserved 2002 --- 2017.