PyGTK
適当メモ.主に日記からの転載.
TextView
textField = gtk.TextView() textBuffer = textField.get_buffer() [startIter, endIter] = textBuffer.get_bounds() # [最初の位置, 最後の位置] print textBuffer.get_text(startIter, endIter)
- 最初の位置と最後の位置を取得し,中の文字列を得る
ある処理を x 秒後に裏で実行
def __init__(self): self.id = gtk.timeout_add(1000, self.run) def run(self): ... # process return True def stop(self): if self.id: gtk.timeout_remove(self.id)
- run が True を返し続ける限りは繰り返し実行される.False が返ると止まる.
×ボタンが押された時にウィジェットを破壊せずに hide する
window = gtk.Widnow(gtk.WINDOW_TOPLEVEL) window.connect("delete-event", close) open(window) def close(w): w.hide() return True def open(w): w.show()
注意点は以下の通り.
- destroy イベントでなく delete-event をフックする
- close メソッドで True を返す
TextView 内の文字に色づけなど
textview = gtk.TextView() buffer = textview.get_buffer() tag = buffer.create_tag('tag_name') tag.set_property('foreground', 'blue') # tag_name という名前の,字の色を青にするタグの生成 buffer.insert_with_tags_by_name(buffer.get_end_iter(), 'hogehoge', 'tag_name')
TextView 内にハイパーリンク的なものを作ってみる
DnD は未実装.
#!/usr/bin/env python import gtk import gobject import pango class HyperTextView(gtk.TextView): __gtype_name__ = 'HyperTextView' __gsignals__ = {'anchor-clicked': (gobject.SIGNAL_RUN_LAST, None, (str, str, int))} __gproperties__ = { 'link': (gobject.TYPE_PYOBJECT, 'link color', 'link color of TextView', gobject.PARAM_READWRITE), 'active':(gobject.TYPE_PYOBJECT, 'active color', 'active color of TextView', gobject.PARAM_READWRITE), 'hover': (gobject.TYPE_PYOBJECT, 'link:hover color', 'link:hover color of TextView', gobject.PARAM_READWRITE), } def do_get_property(self, prop): try: return getattr(self, prop.name) except AttributeError: raise AttributeError, 'unknown property %s' % prop.name def do_set_property(self, prop, val): if prop.name in self.__gproperties__.keys(): setattr(self, prop.name, val) else: raise AttributeError, 'unknown property %s' % prop.name def __init__(self, buffer=None): gtk.TextView.__init__(self, buffer) self.link = {'background': 'white', 'foreground': 'blue', 'underline': pango.UNDERLINE_SINGLE} self.active = {'background': 'light gray', 'foreground': 'red', 'underline': pango.UNDERLINE_SINGLE} self.hover = {'background': 'light gray', 'foreground': 'blue', 'underline': pango.UNDERLINE_SINGLE} self.set_editable(False) self.set_cursor_visible(False) self.__tags = [] self.connect('motion-notify-event', self._motion) self.connect('focus-out-event', lambda w, e: self.get_buffer().get_tag_table().foreach(self.__tag_reset, e.window)) def insert(self, text, _iter=None): b = self.get_buffer() if _iter is None: _iter = b.get_end_iter() b.insert(_iter, text) def insert_with_anchor(self, text, anchor=None, _iter=None): b = self.get_buffer() if _iter is None: _iter = b.get_end_iter() if anchor is None: anchor = text tag = b.create_tag(None, **self.get_property('link')) tag.set_data('is_anchor', True) tag.connect('event', self._tag_event, text, anchor) self.__tags.append(tag) b.insert_with_tags(_iter, text, tag) def _motion(self, view, ev): window = ev.window x, y, _ = window.get_pointer() x, y = view.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, x, y) tags = view.get_iter_at_location(x, y).get_tags() for tag in tags: if tag.get_data('is_anchor'): for t in set(self.__tags) - set([tag]): self.__tag_reset(t, window) self.__set_anchor(window, tag, gtk.gdk.Cursor(gtk.gdk.HAND2), self.get_property('hover')) break else: tag_table = self.get_buffer().get_tag_table() tag_table.foreach(self.__tag_reset, window) def _tag_event(self, tag, view, ev, _iter, text, anchor): _type = ev.type if _type == gtk.gdk.MOTION_NOTIFY: return elif _type in [gtk.gdk.BUTTON_PRESS, gtk.gdk.BUTTON_RELEASE]: button = ev.button cursor = gtk.gdk.Cursor(gtk.gdk.HAND2) if _type == gtk.gdk.BUTTON_RELEASE: self.emit('anchor-clicked', text, anchor, button) self.__set_anchor(ev.window, tag, cursor, self.get_property('hover')) elif button in [1, 2]: self.__set_anchor(ev.window, tag, cursor, self.get_property('active')) def __tag_reset(self, tag, window): if tag.get_data('is_anchor'): self.__set_anchor(window, tag, None, self.get_property('link')) def __set_anchor(self, window, tag, cursor, prop): window.set_cursor(cursor) for key, val in prop.iteritems(): tag.set_property(key, val) gobject.type_register(HyperTextView) if __name__ == '__main__': def clicked(widget, text, anchor, button): print widget, text, anchor, button t = HyperTextView() t.connect('anchor-clicked', clicked) t.link['foreground'] = 'dark blue' t.insert_with_anchor('Google', 'http://www.google.com/') t.insert('\n') t.insert_with_anchor('Yahoo!', 'http://www.yahoo.com/') w = gtk.Window() w.set_default_size(200, 100) w.connect('destroy', lambda w: gtk.main_quit()) w.add(t) w.show_all() gtk.main()
key-press-event の罠
- SCIM とかならキー入力が key-press-event に渡らないが,XIM だと渡ってしまうくさい.
- 例えば Return 入力時の動作をいじるとき,key-press-event をフックする方法を採ると SCIM とかは大丈夫でも XIM でおかしなことになる.
- キーバインドをシグナルに結びつける方法を採ればこの問題は解消する.
import gobject import gtk class EnterKeyPressTextView(gtk.TextView): __gsignals__ = { 'enter-pressed': (gobject.SIGNAL_RUN_LAST|gobject.SIGNAL_ACTION, gobject.TYPE_NONE, (gobject.TYPE_INT,)) } gobject.type_register(EnterKeyPressTextView) for mod in [0, gtk.gdk.SHIFT_MASK, gtk.gdk.CONTROL_MASK, gtk.gdk.MOD1_MASK]: gtk.binding_entry_add_signal(EnterKeyPressTextView, gtk.keysyms.Return, mod, 'enter-pressed', gobject.TYPE_INT, mod) gtk.binding_entry_add_signal(EnterKeyPressTextView, gtk.keysyms.KP_Enter, mod, 'enter-pressed', gobject.TYPE_INT, mod) if __name__ == '__main__': import sys e = EnterKeyPressTextView() e.connect('enter-pressed', lambda _e, m: sys.stdout.write('mod:%d\n' % m)) w = gtk.Window() w.add(e) w.connect('delete-event', lambda _w, _e: gtk.main_quit()) w.set_default_size(640, 480) w.show_all() gtk.main()