Claudiu
Claudiu

Reputation: 229361

gtk: trouble modifying TreeView model on CellRendererCombo 'changed' signal

I have a treeview with a CellRendererCombo in a given column. I use the following code to set up the column:

crc = gtk.CellRendererCombo()
crc.set_property('model', comboModel)
crc.set_property('text-column', 0)
crc.set_property('editable', True)
crc.set_property('has_entry', False)
cl = gtk.TreeViewColumn(ctitle, crc, text=i)

def changed(cell, path, newiter):
    treeViewModel[path][0] = "HAH"
crc.connect("changed", changed)

treeView.append_column(cl)

treeView is a TreeView, treeViewModel is its model, and comboModel is the model for the combo entry containing just two strings.

If I run the code, then the combo works as expected, except that the first time I select an entry I get the following errors:

c:\python25\lib\site-packages\twisted\internet\gtk2reactor.py:255: Warning: inva
lid unclassed pointer in cast to `GObject'
  gtk.main()
c:\python25\lib\site-packages\twisted\internet\gtk2reactor.py:255: Warning: g_ob
ject_notify: assertion `G_IS_OBJECT (object)' failed
  gtk.main()

On the second time I get:

c:\python25\lib\site-packages\twisted\internet\gtk2reactor.py:255: Warning: inva
lid uninstantiatable type `<invalid>' in cast to `GObject'
  gtk.main()

and on the third time the program crashes. If I change the connect line to:

crc.connect("edited", changed)

...then the code works fine. However, the value only changes after clicking out of the combo box, and I'd rather have it change every time an object is selected. How can I do the latter?

EDIT: I just noticed this in the API docs for pygtk:

Note that as soon as you change the model displayed in the tree view, the tree view will immediately cease the editing operating. This means that you most probably want to refrain from changing the model until the combo cell renderer emits the edited or editing_canceled signal.

It doesn't mention that the code would crash, though. In any case, I'd like it that after clicking an entry in the combobox, editing stops, without having to press ENTER or click somewhere else. How can I accomplish that?

Upvotes: 4

Views: 1616

Answers (2)

user911434
user911434

Reputation: 11

Ending editing of a CellRendererCombo immediately after an item is selected is a two stage process.

In the first stage, you must capture the combo itself, since it is not accessible later. To capture the combo, connect to the editing-started CellRenderer signal. You may define the connection in Glade or create it manually in code.

In the second stage, emit a focus-out-event in a changed signal handler for CellRendererCombo.

Here is your original code modified to demonstrate:

comboEditable = None

crc = gtk.CellRendererCombo()
crc.set_property('model', comboModel)
crc.set_property('text-column', 0)
crc.set_property('editable', True)
crc.set_property('has_entry', False)
cl = gtk.TreeViewColumn(ctitle, crc, text=i)

def changed(cell, path, newiter):
    treeViewModel[path][0] = "HAH"
    e = gtk.gdk.Event(gtk.gdk.FOCUS_CHANGE)
    e.window = treeView.window
    e.send_event = True
    e.in_ = False
    comboEditable.emit('focus-out-event', e)
def started(cell, editable, path):
    # Or to make life more predictable, use a class and set self.comboEditable
    global comboEditable
    comboEditable = editable
crc.connect('changed', changed)
crc.connect('editing-started', started)

treeView.append_column(cl)

Note that in more recent versions of GTK+, you don't ordinarily modify the TreeModel in the changed signal handler. You should use the edited signal handler.

Here is the final version:

comboEditable = None

crc = gtk.CellRendererCombo()
crc.set_property('model', comboModel)
crc.set_property('text-column', 0)
crc.set_property('editable', True)
crc.set_property('has_entry', False)
cl = gtk.TreeViewColumn(ctitle, crc, text=i)

def changed(cell, path, newiter):
    e = gtk.gdk.Event(gtk.gdk.FOCUS_CHANGE)
    e.window = treeView.window
    e.send_event = True
    e.in_ = False
    comboEditable.emit('focus-out-event', e)
def started(cell, editable, path):
    # Or to make life more predictable, use a class and set self.comboEditable
    global comboEditable
    comboEditable = editable
def edited(cell, path, newtext):
    treeViewModel[path][columnNumber] = newText
crc.connect('changed', changed)
crc.connect('editing-started', started)
crc.connect('edited', edited)

treeView.append_column(cl)

Upvotes: 1

bjarneh
bjarneh

Reputation: 618

i'm not sure, but i guess the fastest way to get an answer is to search the pygtk mailing list, and if you cant find a similar post, try posting it to the mailing list.

pygtk mailing list

Upvotes: 0

Related Questions