wiki:WikiStart/Ruby/VizkitExtendingCXXWidgetsInRuby

The problem

I want to create, in Ruby, a new widget called RasterMapView. The strategy for this widget would be to extend the already existing Vizkit ImageView widget.

This is not doable directly, from Alex answer on the ML:

This is not going to work because the ImageView class is not known to
ruby. You can only instantiate an instance of the ImageView class which
behaves like a QWidget class on the ruby side.

Unfortunately all events from the ImageView class are not redirected to
the ruby instance so you cannot extend the instance to implement a new
behavior. To get this running you have to write qt bindings.

However, due to how Ruby widgets are registered in Vizkit, there actually is a workaround.

The idea is to create a module (not class) that implements the parts that are specific to RasterMapView, and customize the instanciation of RasterMapView when registering it

Code wise, it looks like:

module RasterMapView
  # Loads the GDAL file at +path+ and displays it in the imageview
  def load(path)
  end

  # This statement does the necessary configuration for this module
  # to be usable with the UiLoader
  vizkit_subclass_of 'ImageView'
  # RasterMapView-specific configuration. vizkit_subclass_of will call this
  # everytime RasterMapView is used to extend a widget
  def self.setup(widget)
    widget.setAspectRatio(true)
  end
end

Vizkit::UILoader.register_ruby_widget 'RasterMapView', RasterMapView.method(:new)

Et voila ! One can now do

require 'envire/raster_map_view'
Vizkit.default_loader.RasterMapView

Unfortunately, it is not (yet) compatible with loading .ui files. To have a RasterMapView in a qtdesigner UI, you need to add an ImageView and do:

widget = Vizkit.load('widget.ui')
widget.image_view.extend RasterMapView

See ruby/envire/raster_map_view.rb in slam/envire for the complete code

Last modified 8 years ago Last modified on 04/11/11 17:16:21