Tutorial
|
|
|
|
The Button Widget
- Normal Buttons
- Toggle Buttons
- Check Buttons
- Radio Buttons
Normal Buttons
We've almost seen all there is to see of the
button widget. It's pretty simple. There are however several ways to
create a button. You can use one following constructors:
Button();
explicit Button(Gtk::Image&
image);
explicit Button(const
String& label, bool use_underline = false);
|
to create an blank button, a button with an image,
a button with a label or a button with a mnemonic label if use_underline
is true. If you create a blank button it is then up to you to pack a
label or image into the new button by calling Gtk::Container::add(). You
can also create a button that displays a stock GTK image and text by
calling to following constructor:
explicit
StockButton(const char
*stock_id);
|
Here's an example of using Button() to create a
button with a image and a label in it. I've broken up the code to create
an image button class so you can use it in your programs. There are
further examples of using images later in the tutorial.
The header file for
Pixmap'd Buttons! is buttons.h:
#include<inti/main.h>
#include <inti/core.h>
#include <inti/gtk/button.h>
using namespace Inti;
class ImageButton : public Gtk::Button
{
protected:
virtual void
on_clicked();
public:
ImageButton(const
String& xpm_filename, const String&
label_text);
virtual ~ImageButton();
};
class ButtonWindow : public Gtk::Window
{
public:
ButtonWindow();
virtual ~ButtonWindow();
}; |
and the source file is buttons.cc:
#include"buttons.h"
#include <inti/gtk/image.h>
#include <inti/gtk/label.h>
#include <iostream>
// ImageButton
ImageButton::ImageButton(const String&
xpm_filename, const String& label_text)
{
// Create box for image
and label
Gtk::HBox *box = new
Gtk::HBox;
box->set_border_width(2);
// Now on to the image
stuff
Gtk::Image *image = new Gtk::Image(xpm_filename);
// Create a label for
the button
Gtk::Label *label = new Gtk::Label(label_text);
// Pack the image and
label into the box
box->pack_start(*image, false, false, 3);
box->pack_start(*label, false,false, 3);
box->show_all();
add(*box);
}
ImageButton::~ImageButton()
{
}
void
ImageButton::on_clicked()
{
using namespace std;
cout << "Hello again - cool button was
pressed" << endl;
}
// ButtonWindow
ButtonWindow::ButtonWindow()
{
set_title("Pixmap'd Buttons!");
set_border_width(10);
// Create a new button
ImageButton *button = new ImageButton("info.xpm", "cool button");
add(*button);
button->show();
}
ButtonWindow::~ButtonWindow()
{
}
int main(int
argc, char *argv[])
{
using namespace Main;
init(&argc, &argv);
ButtonWindow window;
window.sig_destroy().connect(slot(&Inti::Main::quit));
window.show();
run();
return 0;
}
|
The Button widget has the following protected static signals:
- pressed_signal - emitted when pointer button is pressed within
Button widget
- released_signal - emitted when pointer button is released within
Button widget
- clicked_signal - emitted when pointer button is pressed and then
released within Button widget
- enter_signal - emitted when pointer enters Button widget
- leave_signal - emitted when pointer leaves Button widget
Each protected signal has a corresponding public
accessor method that is used to connect to the protected signal. The
public methods are for convenience and pass the object pointer to the
protected signal for you. The Button widget has the following public
signal accessor methods:
- sig_pressed()
- sig_released()
- sig_clicked()
- sig_enter()
- sig_leave()
Toggle Buttons
Toggle buttons are derived from normal buttons and
are very similar, except they will always be in one of two states,
alternated by a click. They may be depressed, and when you click again,
they will pop back up. Click again, and they will pop back down.
Toggle buttons are the basis for check buttons and radio buttons, as
such, many of the calls used for toggle buttons are inherited by radio
and check buttons. I will point these out when we come to them.
To create a toggle button you can use one of the following constructors:
ToggleButton();
explicit ToggleButton(const String& label, bool
use_underline = false); |
The first creates a blank toggle button, and the
second a button with a label widget already packed into it. If
use_underline
is true the label is parsed for '_'-prefixed mnemonic characters.
To retrieve the state of the toggle widget, including radio and check
buttons, we use a construct as shown in our example below. This tests
the state of the toggle button, by accessing the active field of the
toggle widget's structure. The signal of interest to us emitted by
toggle buttons (the toggle button, check button, and radio button
widgets) is the "toggled" signal. There are two ways to check the state
of these buttons.
- Derive your own class from the existing button class and override
it's protected virtual on_toggled signal handler.
- Create an instance of the existing button class and connect a
slot to it's toggled signal.
Using the second method to check the state of a toggle button, create a
new button instance and connect a signal handler to it's
toggled
signal. This is done using a
slot.
Gtk::ToggleButton
*button = new Gtk::ToggleButton("Button");
button->sig_toggled().connect(bind(slot(this,
&MyClass::on_button_toggled), button));
|
Since the
on_button_toggled slot is a
method in MyClass you will have to bind the button pointer to the slot
so that it gets passed as the last argument to the slot method when a
toggled signal is emitted. In the case of on_button_toggled() it is the
only argument because the toggled signal has no parameters. Remember
bound slots, I introduced them to you in the
Theory of Signals and Slots. To
check the state of the toggle button use the following construct:
void
MyClass::on_button_toggled(Gtk::ToggleButton *button)
{
if
(button->get_active())
{
// If
control reaches here, the toggle button is down
}
else
{
// If
control reaches here, the toggle button is up
}
} |
To force the state of a toggle button, and its children, the radio and
check buttons, use this method:
void
set_active(bool is_active); |
The above call can be used to set the state of the
toggle button, and its children the radio and check buttons. Passing in
true or false for the is_active argument to specify whether it
should be down (depressed) or up (released). Default is up, or false.
Note that when you use the Gtk::ToggleButton::set_active() method, and
the state is actually changed, it causes the "clicked" and "toggled"
signals to be emitted from the button.
This returns the current state of the toggle button as a bool
true/false value.
Check Buttons
Check buttons inherit many properties and
functions from the toggle buttons above, but look a little different.
Rather than being buttons with text inside them, they are small squares
with the text to the right of them. These are often used for toggling
options on and off in applications.
The constructors are similar to those of the normal button.
CheckButton();
explicit CheckButton(const String& label, bool
use_underline = false);
|
The second constructor creates a check button
with a label beside it. Checking the state of the check button is
identical to that of the toggle button.
Radio Buttons
Radio buttons are similar to check buttons except
they are grouped so that only one may be selected/depressed at a time.
This is good for places in your application where you need to select
from a short list of options.
Creating a new radio button is done with one of the following
constructors:
RadioButton();
explicit RadioButton(Group *group);
explicit RadioButton(const Gtk::RadioButton *group);
RadioButton(const String& label, bool
use_underline = false);
RadioButton(Group *group, const
String& label, bool use_underline = false);
RadioButton(const Gtk::RadioButton *group, const String& label, bool
use_underline = false); |
You'll notice the extra argument to these
constructors. They require a group to perform their duty properly. The
group specified can either be a pointer to a Group, which
is just a typedef for a GSList or a pointer to a radio button already in
the group. The first radio button can be created by either calling the
first or fourth constructors, or by calling the fifth or sixth
constructors and passing null for the group argument. Subsequent radio
buttons must be constructed by either calling the fifth or sixth
constructors and specifying the group. For the fifth constructor, the
group can be retrieved by calling:
Group* get_group() const; |
The important thing to remember is that
Gtk::RadioButton::get_group() must be called on the previous button and
the result passed in as the group argument to the new button. Then the
result of calling Gtk::RadioButton::get_group() on the new button is
passed into the constructor call for the next button. This allows a
chain of buttons to be established. The example below should make this
clear.
Gtk::RadioButton::Group
*group = 0;
Gtk::RadioButton *button = new
Gtk::RadioButton(group, "button1");
pack_start(*button);
button->show();
group = button->get_group();
button = new Gtk::RadioButton(group,
"button2");
pack_start(*button);
button->show();
|
You can shorten this slightly by using either of the following syntax,
which removes the need for a variable to hold the Group (list) of
buttons:
Gtk::RadioButton
*button2 = new
Gtk::RadioButton(button1->get_group(), "button2");
or
Gtk::RadioButton *button2 = new Gtk::RadioButton(button1,
"button2");
|
It is also a good idea to explicitly set which button should be the
default depressed button with:
void
set_active(bool is_active); |
The following example creates a radio button group with three buttons.
The header file for
radio buttons is radiobuttons.h:
#include<inti/main.h>
#include <inti/core.h>
using namespace Inti;
class RadioButtonWindow : public Gtk::Window
{
public:
RadioButtonWindow();
~RadioButtonWindow();
};
|
and the source file is radiobuttons.cc:
#include"radiobuttons.h"
#include <inti/gtk/radiobutton.h>
#include <inti/gtk/separator.h>
RadioButtonWindow::RadioButtonWindow()
{
set_title("radio buttons");
set_border_width(0);
Gtk::VBox *box1 = new
Gtk::VBox;
add(*box1);
box1->show();
Gtk::VBox *box2 = new
Gtk::VBox(false, 10);
box2->set_border_width(10);
box1->pack_start(*box2);
box2->show();
// When adding the first
radio button to a group pass null for the group parameter.
Gtk::RadioButton::Group *group = 0;
Gtk::RadioButton *radio_button = new Gtk::RadioButton(group, "button1");
box2->pack_start(*radio_button);
radio_button->show();
// Then, pass the group
returned by calling get_group() to the constructors of the other buttons.
group = radio_button->get_group();
radio_button = new
Gtk::RadioButton(group, "button2");
radio_button->set_active(true);
box2->pack_start(*radio_button);
radio_button->show();
// Or even easier, pass
a pointer to a radio button already in the group.
radio_button = new
Gtk::RadioButton(radio_button, "button3");
box2->pack_start(*radio_button);
radio_button->show();
Gtk::HSeparator *separator = new
Gtk::HSeparator;
box1->pack_start(*separator, false);
separator->show();
box2 = new
Gtk::VBox(false, 10);
box2->set_border_width(10);
box1->pack_start(*box2, false);
box2->show();
Gtk::Button *button = new
Gtk::Button("close");
button->sig_clicked().connect(slot(this, &RadioButtonWindow::dispose));
box2->pack_start(*button);
button->set_flags(Gtk::CAN_DEFAULT);
button->grab_default();
button->show();
}
RadioButtonWindow::~RadioButtonWindow()
{
}
int main (int
argc, char *argv[])
{
using namespace Main;
init(&argc, &argv);
RadioButtonWindow window;
window.sig_destroy().connect(slot(&Inti::Main::quit));
window.show();
run();
return 0;
}
|