[pygtk] Custom cell renderers
Osmo Salomaa
otsaloma at cc.hut.fi
Sun Apr 10 10:35:45 WST 2005
I didn't manage to subclass CellRendererText but I got the job done the hard
way with GenericCellRenderer. Below is the code for an editable multiline text
cell renderer.
If you try it, use shift/ctrl/alt + return/keypad enter for linebreaking while
editing the text in a cell.
It seems to work well. However, since I'm new to python and pygtk, any
corrections or suggestions will be apprechiated.
Osmo
#!/usr/bin/env python
# -*- coding: utf8 -*-
import pygtk
import gtk
import gobject
import pango
class CellTextView(gtk.TextView, gtk.CellEditable):
def set_text(self, text):
text_buffer = self.get_buffer()
text_buffer.set_text(text)
def get_text(self, *args):
text_buffer = self.get_buffer()
start = text_buffer.get_start_iter()
end = text_buffer.get_end_iter()
return text_buffer.get_text(start, end, True)
def do_editing_done(*args):
pass
def do_remove_widget(*args):
pass
def do_start_editing(*args):
pass
class CellRendererMultilineText(gtk.GenericCellRenderer):
__gproperties__ = {
'text': (gobject.TYPE_STRING, 'text', 'text displayed', '',
gobject.PARAM_READWRITE)
}
__gsignals__ = {
'edited': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
(gobject.TYPE_STRING, gobject.TYPE_STRING))
}
property_names = __gproperties__.keys()
def __init__(self):
self.__gobject_init__()
self.set_property('mode', gtk.CELL_RENDERER_MODE_EDITABLE)
def __getattr__(self, name):
try:
return self.get_property(name)
except TypeError:
raise AttributeError
def __setattr__(self, name, value):
try:
self.set_property(name, value)
except TypeError:
self.__dict__[name] = value
def do_get_property(self, property):
if property.name not in self.property_names:
raise TypeError('No property named %s' % (property.name,))
return self.__dict__[property.name]
def do_set_property(self, property, value):
if property.name not in self.property_names:
raise TypeError('No property named %s' % (property.name,))
self.__dict__[property.name] = value
def on_render(self, window, widget, bg_area, cell_area, exp_area, flags):
x_offset, y_offset, width, height = self.on_get_size(widget, cell_area)
layout = self.get_layout(widget)
# Determine state to get text color right.
if flags & gtk.CELL_RENDERER_SELECTED:
if widget.get_property('has-focus'):
state = gtk.STATE_SELECTED
else:
state = gtk.STATE_ACTIVE
else:
state = gtk.STATE_NORMAL
widget.style.paint_layout(
window, state, True, cell_area, widget, 'foo',
cell_area.x + x_offset, cell_area.y + y_offset, layout
)
def get_layout(self, widget):
'''Gets the Pango layout used in the cell in a TreeView widget.'''
layout = pango.Layout(widget.get_pango_context())
layout.set_width(-1) # Do not wrap text.
if self.text:
layout.set_text(self.text)
else:
layout.set_text('')
return layout
def on_get_size(self, widget, cell_area):
# The following size calculations have tested so that the TextView
# will fully fit in the cell when editing and it will be the same
# size as a CellRendererText cell with same amount or rows.
xpad = 2
ypad = 2
xalign = 0
yalign = 0.5
layout = self.get_layout(widget)
width, height = layout.get_pixel_size()
x_offset = xpad
y_offset = ypad
if cell_area:
x_offset = xalign * (cell_area.width - width)
x_offset = max(x_offset, xpad)
x_offset = int(round(x_offset, 0))
y_offset = yalign * (cell_area.height - height)
y_offset = max(y_offset, ypad)
y_offset = int(round(y_offset, 0))
width = width + (xpad * 2)
height = height + (ypad * 2)
return x_offset, y_offset, width, height
def on_start_editing(self, event, widget, path, bg_area, cell_area, flags):
editor = CellTextView()
editor.set_wrap_mode(gtk.WRAP_NONE)
editor.connect('key-press-event', self.on_key_press_event, path)
if self.text:
editor.set_text(self.text)
editor.grab_focus()
editor.show()
return editor
def on_key_press_event(self, widget, event, path):
'''Catch pressing Enter keys.
Shift, Ctrl or Alt combined with Return or Keypad Enter can be used
for linebreaking. Pressing Return or Keypad Enter alone will finish
editing.'''
mask = event.state
keyname = gtk.gdk.keyval_name(event.keyval)
accel_masks = (gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK | \
gtk.gdk.MOD1_MASK)
enter_keynames = ('Return', 'KP_Enter')
if (keyname in enter_keynames) and not (mask & accel_masks):
self.emit('edited', path, widget.get_text())
widget.destroy()
gobject.type_register(CellTextView)
gobject.type_register(CellRendererMultilineText)
def on_edited(widget, path, new_value, store, column):
iter = store.get_iter(str(path))
store.set(iter, column, new_value)
if __name__ == '__main__':
store = gtk.ListStore(str, str)
tree = gtk.TreeView()
tree.set_model(store)
tree.set_size_request(360, 140)
tree.set_headers_visible(True)
cr = gtk.CellRendererText()
cr.connect('edited', on_edited, store, 0)
cr.set_property('editable', True)
column = gtk.TreeViewColumn('gtk.CellRendererText', cr, text = 0)
tree.append_column(column)
cr = CellRendererMultilineText()
cr.connect('edited', on_edited, store, 1)
column = gtk.TreeViewColumn('CellRendererMultilineText', cr, text = 1)
tree.append_column(column)
store.append(['Phou flou\nghou fhou.', 'Phou flou\nghou fhou.'])
store.append(['Bhuu fvou\nghaa neff.', 'Bhuu fvou\nghaa neff.'])
window = gtk.Window()
window.set_position(gtk.WIN_POS_CENTER)
window.connect('delete-event', gtk.main_quit)
window.add(tree)
window.show_all()
gtk.main()
More information about the pygtk
mailing list