connecting to GtkBuilder signals



Hi everybody,

I know C pretty well but am only a newbie in C++ and Gtk.

I am starting a new application. I want to try to use Glade to save me the boredom of coding the whole user interface in C++.

I am looking at the most convenient way to connect to signals coming from the objects instantiated by GtkBuilder.

The Gtkmm book has two examples of how to do so. This is the simple method:
http://library.gnome.org/devel/gtkmm-tutorial/unstable/sec-builder-accessing-widgets.html.en

This is the more complicated method, using "derived widgets":
http://library.gnome.org/devel/gtkmm-tutorial/unstable/sec-builder-using-derived-widgets.html.en

For my intended application the simple method does not seem suitable, because I don't think it would scale well for, let's say, 100 widgets, some of which may have multiple signals connected - the code would get messy.

The "derived widgets" approach, on the other hand, seems a bit too complicated for my needs, and to require a lot of typing.

What I am looking for is something in-between the two approaches, that is, a way to have encapsulation to keep the code tidy while being simpler than the "derived widgets".

Below is what I came up with. I have tweaked the C++ and Glade files that come with the simple example mentioned above. I modified the Glade file by adding a second button and changing the labels. I modified the C++ file by moving the signal handler inside a class and adding some other statements to test the implementation.

I have two questions.

My approach seems to work well for the simple case of two buttons. Would it work well for more complicated widgets?

If yes to the above, is my approach good C++ code or just an ugly hack? Or something in between?

Below is the C++ file followed by the Glade file.

Thanks.

P. S. I am using gtkmm v. 2.18.2, Glade v. 3.6.7, on Fedora 12.

-----------------------------------------------------------------

/* Test me with:

gcc -o sigtest sigtest.cc $(pkg-config --cflags --libs gtkmm-2.4) && ./sigtest

needs file sigtest.glade
*/

#include <gtkmm.h>
#include <iostream>

Gtk::Dialog* pDialog = 0;

class MyButton {
public:
MyButton(Glib::RefPtr<Gtk::Builder> *refBuilder, char * name);

// the only purpose of this function is to test if I can access the GtkBuilder Button object from a MyButton object
void change_label(char * name);

private:
Gtk::Button* pButton; // point to the object instantiated by GtkBuilder
void on_button_clicked();
};

void MyButton::change_label(char * name)
{
  if(pButton) pButton->set_label(name);
}

void MyButton::on_button_clicked()
{
  if(pDialog) pDialog->hide(); //hide() will cause main::run() to end.

  if(pButton) std::cerr << "Signal received from button: " << pButton->get_label() << std::endl;
}

MyButton::MyButton(Glib::RefPtr<Gtk::Builder> *refBuilder, char * name)
{
    //Get the GtkBuilder-instantiated Button, and connect a signal handler:
    pButton = 0;
    (*refBuilder)->get_widget(name, pButton);
    if(pButton)
    {
      pButton->signal_clicked().connect( sigc::mem_fun(*this, &MyButton::on_button_clicked) );
    }

    // if needed we could connect other signals here
};


int main (int argc, char **argv)
{
  Gtk::Main kit(argc, argv);

  //Load the GtkBuilder file and instantiate its widgets:
  Glib::RefPtr<Gtk::Builder> refBuilder = Gtk::Builder::create();
#ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
  {
    refBuilder->add_from_file("sigtest.glade");
  }
  catch(const Glib::FileError& ex)
  {
    std::cerr << "FileError: " << ex.what() << std::endl;
    return 1;
  }
  catch(const Gtk::BuilderError& ex)
  {
    std::cerr << "BuilderError: " << ex.what() << std::endl;
    return 1;
  }
#else
  std::auto_ptr<Glib::Error> error;

  if (!refBuilder->add_from_file("sigtest.glade", error))
  {
    std::cerr << error->what() << std::endl;
    return 1;
  }
#endif /* !GLIBMM_EXCEPTIONS_ENABLED */

  MyButton but1(&refBuilder, (char *) "quit_button1");
  MyButton but2(&refBuilder, (char *) "quit_button2");

  // test access to  GtkBuilder Button objects - by changing their labels
  but1.change_label((char *) "Close1");
  but2.change_label((char *) "Close2");

  //Get the GtkBuilder-instantiated Dialog:
  refBuilder->get_widget("DialogBasic", pDialog);
  if(pDialog)
  {
    kit.run(*pDialog);
  }

  return 0;
}

--------------------------------------------------------------------------

<?xml version="1.0"?>
<interface>
  <!-- interface-requires gtk+ 2.12 -->
  <!-- interface-naming-policy toplevel-contextual -->
  <object class="GtkDialog" id="DialogBasic">
    <property name="title" translatable="yes">basic libglademm example</property>
    <property name="type_hint">normal</property>
    <child internal-child="vbox">
      <object class="GtkVBox" id="dialog-vbox2">
        <property name="visible">True</property>
        <child>
          <object class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="label" translatable="yes">This is a basic libglademm example</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">False</property>
            <property name="position">2</property>
          </packing>
        </child>
        <child internal-child="action_area">
          <object class="GtkHButtonBox" id="dialog-action_area2">
            <property name="visible">True</property>
            <property name="layout_style">end</property>
            <child>
              <object class="GtkButton" id="quit_button1">
                <property name="label">Quit1</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="can_default">True</property>
                <property name="receives_default">False</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="quit_button2">
                <property name="label" translatable="yes">Quit2</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
              </object>
              <packing>
                <property name="expand">False</property>
                <property name="fill">False</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="pack_type">end</property>
            <property name="position">0</property>
          </packing>
        </child>
      </object>
    </child>
    <action-widgets>
      <action-widget response="0">quit_button1</action-widget>
      <action-widget response="0">quit_button2</action-widget>
    </action-widgets>
  </object>
</interface>






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]