# Writing a CellRenderer in Ruby

**URL:** <https://www.ruby-forum.com/t/writing-a-cellrenderer-in-ruby/72345>\
**Category:** Ruby-Gnome 2\
**Created:** [October 16, 2006, 5:54pm UTC](https://www.ruby-forum.com/t/writing-a-cellrenderer-in-ruby/72345 "2006-10-16T17:54:34Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Clifford\_H](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/49beb7/32.png) [@Clifford\_H](https://www.ruby-forum.com/u/Clifford_H)\
**Post date:** [October 16, 2006, 5:54pm UTC](https://www.ruby-forum.com/t/writing-a-cellrenderer-in-ruby/72345/1 "2006-10-16T17:54:34Z")

</div>

Folk,

I’ve subclassed the CellRendererPixbuf to make a renderer that  
has a “state” property that displays an appropriate icon for each  
state, and I want to add mouse button event handlers to it.

Problem is, there doesn’t seem to be any way to get the TreeView  
object which is the necessary Widget. In the \_GtkTreeView object  
in gtktreeview.h, there’s a “parent” member, but no supported way  
even in the C API of accessing it. What am I missing?

The code, such as it is, is below. The images for are  
simply loaded from \<state.png\>.

Clifford H…

module Gtk  
class CellRendererIconSet \< CellRendererPixbuf  
type\_register  
install\_property(GLib::Param::String.new(  
“state”,  
“state”,  
“The state of an IconSet”,  
“”,  
GLib::Param::READABLE|GLib::Param::WRITABLE))

```
    def initialize(*args)
        super()
        @state = nil
        @states = {}
        if (args.size > 0)
            states = args[0]
            if (states.is_a? Hash)
                @states = states
            elsif (states.is_a? Array)
                states.each{|s| @states[s] = nil }
            end
            # More handling needed here...
        end
        # and here...
    end

    attr_reader :state

    def state=(s)
        throw "CellRendererIconSet: no such state #{s.inspect} in

```

#{@states}" if !@states.include?(s)  
@state = s  
self.pixbuf=(icon)  
end

```
    def icon(s = nil)
        s ||= @state
        puts "loading icon for #{s}" if (!@states[s])
	# Needs a directory path from which to load here:
        @states[s] ||= Gdk::Pixbuf.new(s.to_s.downcase+".png")
    end
end

```

end

I want to move something like the following code into the class:

```
    tree.add_events(Gdk::Event::BUTTON_PRESS_MASK)
    tree.signal_connect("button_press_event") { |w, e|
        path, column, cell_x, cell_y = tree.get_path_at_pos(e.x,

```

e.y)

```
        puts "button #{e.button} at (#{e.x}, #{e.y}) row #{path},

```

column #{column}, at (#{cell\_x}, #{cell\_y})"

```
        next if column != self
	on_click(path, e.button, e.state)
    }

```

… so I can then write:

```
def on_click(path, button, state)
      next if e.button != 3

        # Get current state and calculate next state:
        storeRow = store[path]
        state = storeRow[Column::IconState]
        newstate = States[(States.index(state)+1) % States.size]
        storeRow[Column::IconState] = newstate
	true
  end

```

* * *

Using Tomcat but need to do more? Need to support web services,  
security?  
Get stuff done quickly with pre-integrated technology to make your job  
easier  
Download IBM WebSphere Application Server v.1.0.1 based on Apache  
Geronimo  
[http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642](http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642)

---

<div class="post-metadata">

**Author:** ![Clifford\_H](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/49beb7/32.png) [@Clifford\_H](https://www.ruby-forum.com/u/Clifford_H)\
**Post date:** [October 18, 2006, 2:27pm UTC](https://www.ruby-forum.com/t/writing-a-cellrenderer-in-ruby/72345/2 "2006-10-18T14:27:45Z")

</div>

Hi,

In [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
“[ruby-gnome2-devel-en] Writing a CellRenderer in Ruby” on Mon, 16 Oct  
2006 18:15:49 +1000,  
“Clifford H.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Problem is, there doesn’t seem to be any way to get the TreeView  
> object which is the necessary Widget. In the \_GtkTreeView object  
> in gtktreeview.h, there’s a “parent” member, but no supported way  
> even in the C API of accessing it. What am I missing?

Does the following changes solve your problem?

> ```
> tree.signal_connect("button_press_event") { |w, e|
> 
> ```

```
      tree.signal_connect("button_press_event", tree) { |w, e, t|

```

…

> ```
> on_click(path, e.button, e.state)
> 
> ```

```
	on_click(path, e.button, e.state, t)

```

…

> def on\_click(path, button, state)  
> def on\_click(path, button, state, tree)  
> …

## Thanks,

kou

* * *

Using Tomcat but need to do more? Need to support web services,  
security?  
Get stuff done quickly with pre-integrated technology to make your job  
easier  
Download IBM WebSphere Application Server v.1.0.1 based on Apache  
Geronimo  
[http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642](http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642)

---

<div class="post-metadata">

**Author:** ![Clifford\_H](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/49beb7/32.png) [@Clifford\_H](https://www.ruby-forum.com/u/Clifford_H)\
**Post date:** [October 18, 2006, 2:47pm UTC](https://www.ruby-forum.com/t/writing-a-cellrenderer-in-ruby/72345/3 "2006-10-18T14:47:53Z")

</div>

Kouhei S. wrote:

> “Clifford H.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:
> 
> > Problem is, there doesn’t seem to be any way to get the TreeView  
> > object which is the necessary Widget.  
> > Does the following changes solve your problem?  
> > tree.signal\_connect(“button\_press\_event”) { |w, e|  
> > tree.signal\_connect(“button\_press\_event”, tree) { |w, e, t|  
> > …

Thanks for your thought on this, but that doesn’t help.

The problem is that inside CellRendererIconSet, it’s not possible  
to get the “tree” object in order to call signal\_connect in the  
first place. I have to pass the tree widget to the new renderer  
in a separate call, as in the following revised version. It looks  
pretty clean, but the extra “set\_tree” call is bad - it should  
be possible to do this in the constructor without having to pass  
an additional argument (which isn’t what the attached code does).

It seems to me that when the CellRenderer is associated with a  
Column, it should receive a callback telling it the column object  
and the tree object, so it can attach to the tree’s widget then.

The further problem is that when an event does occur, I can find  
out what column it’s on, but can’t disregard it if it occurred on  
another column, because I can’t tell what column the renderer is  
on. That logic must go in the “click” handler, which is bad.

It’s annoying that this is _almost nice_, but I can’t see how to  
properly finish it.

module Gtk  
class CellRendererIconSet \< CellRendererPixbuf  
type\_register  
install\_property(GLib::Param::String.new(  
“state”,  
“state”,  
“The state of an IconSet”,  
“”,  
GLib::Param::READABLE|GLib::Param::WRITABLE))

```
    def initialize(*args)
        super()
        @state = nil
        @states = {}
        if (args.size > 0)
            states = args[0]
            if (states.is_a? Hash)
                @states = states
            elsif (states.is_a? Array)
                states.each{|s| @states[s] = nil }
            end
        end
    end

# Register events for this Renderer:
    signal_new("button_press_event", GLib::Signal::RUN_FIRST, nil, 

```

nil,  
Gdk::EventButton, Gtk::TreePath, Gtk::TreeViewColumn,  
Integer, Integer)

```
    signal_new("button_release_event", GLib::Signal::RUN_FIRST, nil, 

```

nil,  
Gdk::EventButton, Gtk::TreePath, Gtk::TreeViewColumn,  
Integer, Integer)

```
    signal_new("click", GLib::Signal::RUN_FIRST, nil, nil,
            Gdk::EventButton, Gtk::TreePath, Gtk::TreeViewColumn,
            Integer, Integer)

    def signal_do_button_press_event(event, path, column, cell_x, 

```

cell\_y)  
# puts “press event #{event.inspect}, path #{path.inspect}”  
end

```
    def signal_do_button_release_event(event, path, column, cell_x, 

```

cell\_y)  
# puts “release event #{event.inspect}, path  
#{path.inspect}”  
end

```
    def signal_do_click(event, path, column, cell_x, cell_y)
        # puts "click event #{event.inspect}, path #{path.inspect}"
    end

    def tree=(tree)
        tree.add_events(Gdk::Event::BUTTON_PRESS_MASK|Gdk::Event::BUTTON_RELEASE_MASK)
        armed_column = nil
        tree.signal_connect("button_press_event") { |w, e|
            path, column, cell_x, cell_y = tree.get_path_at_pos(e.x, 

```

e.y)  
#puts “press #{e.button} at (#{e.x}, #{e.y}) row  
#{path}, column #{column}, at (#{cell\_x}, #{cell\_y})”

```
            armed_column = column
            signal_emit("button_press_event", e, path, column, 

```

cell\_x, cell\_y)  
}  
tree.signal\_connect(“button\_release\_event”) { |w, e|  
path, column, cell\_x, cell\_y = tree.get\_path\_at\_pos(e.x,  
e.y)  
#puts “release #{e.button} at (#{e.x}, #{e.y}) row  
#{path}, column #{column}, at (#{cell\_x}, #{cell\_y})”  
cell\_x ||= -1 # Can’t be null  
cell\_y ||= -1  
signal\_emit(“button\_release\_event”, e, path, column,  
cell\_x, cell\_y)

```
            if (column == armed_column)
                signal_emit("click", e, path, column, cell_x, 

```

cell\_y)  
end  
armed\_column = nil  
}  
end

```
    def state
        @state
    end

    def state=(s)
        throw "CellRendererIconSet: no such state #{s.inspect} in 

```

#{@states}" if !@states.include?(s)  
@state = s  
self.pixbuf=(icon)  
end

```
    def icon(s = nil)
        s ||= @state
        puts "loading icon for #{s}" if (!@states[s])
        @states[s] ||= Gdk::Pixbuf.new(s.to_s.downcase+".png")
    end
end

```

end

Then in the tree construction code, I put:

```
    tree.append_column(
        @iconColumn =
        Gtk::TreeViewColumn.new(
            "", # Heading
            r = Gtk::CellRendererIconSet.new(States),
            :state => Column::ProjectState # data
        )
    )
    r.tree = tree # This call should be unnecessary!

```

And finally, in order to handle the click event, I add:

```
    r.signal_connect("click") { |r, e, path, column, cell_x, cell_y|
        next if column != @iconColumn	# This should be unnecessary!
        next if e.button != 3 # ignore if not right-click

    # Handle the click by choosing the next icon in the States array:
        storeRow = store[path]
        state = storeRow[Column::ProjectState]
        newstate = States[(States.index(state)+1) % States.size]
        puts state+" -> "+newstate
        storeRow[Column::ProjectState] = newstate
    }

```

Does that make it clearer?

Clifford H…

* * *

Using Tomcat but need to do more? Need to support web services,  
security?  
Get stuff done quickly with pre-integrated technology to make your job  
easier  
Download IBM WebSphere Application Server v.1.0.1 based on Apache  
Geronimo  
[http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642](http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642)
