PyGTKでテキストビュー内の文字列にスタイルを適用する
GTK+のテキストビュー(gtk.TextViewオブジェクト)に表示されるテキストバッファ(gtk.TextBufferオブジェクト)には文字情報以外に書式などの情報を適用するタグ(gtk.TextTagオブジェクト)を含めることができる。これによりテキストビュー内の一部(もしくは全て)の文字列にスタイルを適用できる。
流れ
- gtk.TextTagオブジェクトを作成し、必要であれば名前も付ける(効果は後述・既定では名前は付かない)
- gtk.TextTagオブジェクトをgtk.TextBufferオブジェクトの「テーブル」に追加(具体的には下のコード例を参照)
- gtk.TextBufferオブジェクトの中のスタイルを適用したい範囲(始点と終点)を示す2つのgtk.TextIterオブジェクト*1を用意
- gtk.TextBufferオブジェクトのメンバ関数apply_tag()/remove_tag()でタグを適用/解除・あるいはタグ生成時に名前を付けた場合apply_tag_by_name()/remove_tag_by_name()を用いて名前による指定を行うこともできる
gtk.TextIterオブジェクトを用意する方法
- テキストビュー上の選択範囲から得るにはgtk.TextBufferオブジェクトのget_selection_bounds()が使用できる
- gtk.TextBufferオブジェクトのget_start_iter()でテキストバッファの先頭、get_end_iter()で最後の位置をそれぞれ示すオブジェクトが得られる
- gtk.TextBufferオブジェクトの「get_iter_at_」系メンバ関数を用いるとテキストバッファ内の特定の行や文字の数などから位置を指定できる
- 始点を得たらそのオブジェクトを「iter_end = iter_start.copy()」のようにして複製し、終点のオブジェクトのほうをgtk.TextIterオブジェクトの「forward_」系メンバ関数を用いるなどして実際の終点に到達するまで移動を繰り返す
設定できる書式など
gtk.TextTagオブジェクトの「gtk.TextTag Properties」のところに載っている項目が利用でき、メンバ関数set_property()により設定していく。
コード例
選択した範囲に対して「On」で強調され、「Off」で強調が解除される。
[任意]ファイル名: texttagtest.py
#! /usr/bin/python # -*- encoding: utf-8 -*- import sys try: import pygtk pygtk.require('2.0') except: pass try: import pango import gtk except: print >> sys.stderr, 'Error: PyGTK is not installed' sys.exit(1) class MainWindow(gtk.Window): """ メインウィンドウ """ def __init__(self, *args, **kwargs): gtk.Window.__init__(self, *args, **kwargs) # ショートカットキー(アクセラレータ) self.__accelgroup = gtk.AccelGroup() self.add_accel_group(self.__accelgroup) # メニュー項目 self.__item_quit = gtk.ImageMenuItem(gtk.STOCK_QUIT, self.__accelgroup) self.__menu_file = gtk.Menu() self.__menu_file.add(self.__item_quit) self.__item_file = gtk.MenuItem('_File') self.__item_file.set_submenu(self.__menu_file) self.__menubar = gtk.MenuBar() self.__menubar.append(self.__item_file) # テキストビュー self.__textbuf = gtk.TextBuffer() self.__textview = gtk.TextView(self.__textbuf) self.__textview.set_wrap_mode(gtk.WRAP_CHAR) self.__sw = gtk.ScrolledWindow() self.__sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) self.__sw.add(self.__textview) # テキストタグ self.__texttag_strong = gtk.TextTag('strong') # タグに名前を付けられる # 以下色々なスタイルを適当に設定 self.__texttag_strong.set_properties(foreground='yellow', background='black') self.__texttag_strong.set_property('family', 'Serif') self.__texttag_strong.set_property('size-points', 16) self.__texttag_strong.set_property('weight', pango.WEIGHT_BOLD) self.__texttag_strong.set_property('underline', pango.UNDERLINE_DOUBLE) self.__texttag_strong.set_property('style', pango.STYLE_ITALIC) # 各タグはテキストバッファの「テーブル」に登録しておく必要がある self.__textbuf.get_tag_table().add(self.__texttag_strong) # ボタン self.__button_on = gtk.Button('On') self.__button_off = gtk.Button('Off') # レイアウト用コンテナ self.__hbox = gtk.HBox() self.__hbox.pack_start(self.__button_on) self.__hbox.pack_start(self.__button_off) self.__vbox = gtk.VBox() self.__vbox.pack_start(self.__menubar, expand=False, fill=False) self.__vbox.pack_start(self.__sw) self.__vbox.pack_start(self.__hbox, expand=False, fill=False) # シグナル self.connect('delete_event', gtk.main_quit) self.__item_quit.connect('activate', gtk.main_quit) self.__button_on.connect('clicked', self.__on_button_on_clicked) self.__button_off.connect('clicked', self.__on_button_off_clicked) # ウィンドウ self.add(self.__vbox) self.set_size_request(350, 300) def __on_button_on_clicked(self, widget): """ Onボタンが押されたときに選択範囲の強調スタイルを有効にする """ selection = self.__textbuf.get_selection_bounds() # 選択範囲がない場合はNoneが返る if not selection: print 'No selections' return # 選択範囲の開始点と終了点のgtk.TextIterオブジェクトが得られる (iter_start, iter_end) = selection # 範囲とタグを指定してタグを適用 self.__textbuf.apply_tag(self.__texttag_strong, iter_start, iter_end) def __on_button_off_clicked(self, widget): """ Offボタンが押されたときに選択範囲の強調スタイルをなしにする """ selection = self.__textbuf.get_selection_bounds() if not selection: print 'No selections' return (iter_start, iter_end) = selection # タグの名前による指定(「_by_name」付きのメンバ関数)も可能 # 内部的にこの文字列からタグオブジェクトをたどって処理される self.__textbuf.remove_tag_by_name('strong', iter_start, iter_end) class PyGTKTextTagTest: """ テキストタグのテスト """ def main(self): """ アプリケーションのメイン処理 """ win = MainWindow() win.show_all() gtk.main() if __name__ == '__main__': app = PyGTKTextTagTest() app.main()
(2010/2/15)細かい部分を微調整(動作は以前と同じ)
関連記事:
参考URL:
*1:テキストバッファを操作するためのカーソル(キャレット)のようなオブジェクトで、バッファ内の位置を保持している