gtkmm/togglebutton.h

Wuttup toons!

Let's talk about Gtk::ToggleButton! This is a super class to checkboxes and radio buttons. This means that understanding this intermediate type will carry over to other button subtypes.

Toggle a button from another

Create a new project and in the source directory, create a main.cpp, which looks very much like our last main file.

// main.cpp
#include "buttonWindow.h"
#include <gtkmm/application.h>

int main(int argc, char** argv) {  
  auto app = Gtk::Application::
    create(
      argc, argv,
      "org.animatedlew.buttons"
    );
  ButtonWindow window;
  return app->run(window);
}

Here we create an app, which is a smart pointer to a Gtk::Application. This pointer type is similar to std::shared_ptr in that they both reference count pointers. When counts reach zero, they self-destruct.

The next step is to instantiate a ButtonWindow and pass it into the app's event loop: app->run(buttons).

Define the header

Next, we define the buttonWindow header.

// buttonWindow.h
#pragma once

#include <gtkmm/window.h>
#include <gtkmm/togglebutton.h>
#include <gtkmm/box.h>

class ButtonWindow : public Gtk::Window {  
public:  
  ButtonWindow();
  virtual ~ButtonWindow();

protected:  
  void onClicked();
  void onToggle();

  Gtk::Button togglerBtn;
  Gtk::ToggleButton toggleeBtn;

  Gtk::Box boxContainer;
};

There are three header files included in this file. We bring in window.h because we extend it and pass the subclass instance into our app.

We bring in a togglebutton.h, which by default, also includes button.h. Additionally, we also bring in box.h, to hold our buttons. Without a container, our window can only hold a single item.

As far as member functions go, we declare a vanilla button that will control the toggle state of the toggle button. This is to demonstrate how other controls can trigger signals. As mentioned previously, the boxContainer member will literally do nothing but hold our two buttons.

Defining the window

Finally, let's flesh out the details of our ButtonWindow in buttonWindow.cpp.

// buttonWindow.cpp
#include "buttonWindow.h"
#include <iostream>

ButtonWindow::ButtonWindow() {

  set_title("Toggle Buttons");
  set_border_width(10);

  add(boxContainer);

  // hook up the onClicked handler to the signal
  togglerBtn
    .signal_clicked()
    .connect(sigc::mem_fun(*this,
      &ButtonWindow::onClicked));

  toggleeBtn
    .signal_toggled()
    .connect(sigc::mem_fun(*this,
      &ButtonWindow::onToggle));

  togglerBtn.set_label("toggler");
  toggleeBtn.set_label("togglee");

  // add the button to the window container
  boxContainer.pack_start(togglerBtn);
  boxContainer.pack_start(toggleeBtn);

  // saves us from calling show on all widgets
  show_all_children();
}

ButtonWindow::~ButtonWindow() {}

void ButtonWindow::onToggle() {  
    std::cout << "isActive: " << toggleeBtn.get_active() << std::endl;
}

void ButtonWindow::onClicked() {  
    toggleeBtn.set_active(!toggleeBtn.get_active());
}

After adding a border width and a title to our top-level window, we add our boxContainer to it. This will allow us to pack more widgets into the window. As you can tell, I'm trying to hammer that in.

Just like before, we retrieve our clicked signal and connect the onClicked method in the slot. Next we connect the onToggle method to a toggled slot.

I'll skim over setting labels as this is self-explanatory. Next, we call pack_start on our boxContainer to place both of our buttons on the window. The final call of the constructor triggers show on all the sub-widgets.

Notable ToggleButton methods

  • get_active() returns a bool of whether the button is activated
  • set_active() forces the button to be in a specific state
  • toggled() triggers a toggled signal and doesn't do much else

Final thoughts

Now you're 90% there to understanding checkboxes and radio buttons in gtkmm. In the next session, we're going to bundle all these types together and have them live in harmony.

Before signing off, I want to point out that libsigc++ is not thread safe. This is the library that allows us to use sigc::mem_fun to wrap our member functions as slots. In our code, we connect signals and slots. This sounds fancy but slots are nothing more than functions wrapped in objects. That said, in a future article, I will cover how to properly use these signals in mutlithreaded code.

...and remember to stay wise!