Radio Buttons, Combo Boxes and Event Handling

Welcome back! Today we will walk through a slightly bigger example to understand the way event handling works in YUI. We will also learn use two new widgets that we see in almost all the applications we use : Radio Buttons and Combo Boxes.

We will create a program that contains a combo box, two radio buttons, a label and a push button. The radio buttons are called immediate and event1. If immediate is selected, the label reflects the selected value of the combo box without clicking the push button. If event1 radio button is selected, the push button has to be clicked for the label to reflect the value of the selected element of the combo box. Simple concept, right?

Before we proceed, please note that all the examples found in this blog are available at : https://gitorious.org/libyui. So feel free to compile and see the output for yourself! (ofcourse, only on openSUSE at the moment.)

Also, I will be assuming that you know the basics of YUI and that you have read my previous post : http://nbprashanth.wordpress.com/2011/04/22/libyui-an-introduction/. If not, it is highly recommended that you read that first as we will build on that foundation.

So, lets start with the example.


#include "YUI.h"
#include "YWidgetFactory.h"
#include "YDialog.h"
#include "YLayoutBox.h"
#include "YComboBox.h"
#include "YEvent.h"
#include "YLabel.h"
#include "YPushButton.h"
#include "YRadioButton.h"
#include "YRadioButtonGroup.h"

int main( int argc, char **argv )
{
YDialog * dialog = YUI::widgetFactory()->createPopupDialog();

YLayoutBox * vbox = YUI::widgetFactory()->createVBox( dialog );
YLayoutBox * radiobox = YUI::widgetFactory()->createHBox( vbox );

YRadioButtonGroup *radiogrp = YUI::widgetFactory()->createRadioButtonGroup(radiobox);
YRadioButton *immediate = YUI::widgetFactory()->createRadioButton(radiobox,"Immediate", false);
YRadioButton *event1 = YUI::widgetFactory()->createRadioButton(radiobox,"Not Immediate", true);
immediate->setNotify(true);
event1->setNotify(true);

radiogrp->addRadioButton(immediate);
radiogrp->addRadioButton(event1);

YLayoutBox * hbox = YUI::widgetFactory()->createHBox( vbox );
YComboBox *cbox = YUI::widgetFactory()->createComboBox(hbox,"Choose Item",false);
YLabel *label = YUI::widgetFactory()->createLabel(hbox,"",false,false);

YLayoutBox * hbtnbox = YUI::widgetFactory()->createHBox( vbox );
YPushButton *button = YUI::widgetFactory()->createPushButton(hbtnbox,"&Update");

cbox->addItem("English",true);
cbox->addItem("Spanish",false);
cbox->addItem("French",false);
cbox->addItem("Hindi",false);
cbox->addItem("Chinese",false);
cbox->addItem("Russian",false);

do
{
YEvent *event = dialog->waitForEvent();

if(event)
{
if(event->eventType() == YEvent::CancelEvent)
break;

if(event->widget() == cbox || event->widget() == button)
{
label->setText(cbox->selectedItem()->label());
}

if(event->eventType() == YEvent::WidgetEvent && (event->widget() == immediate || event->widget() == event1))
{
radiogrp->uncheckOtherButtons((YRadioButton*)event->widget());

if(event->widget()==immediate)
cbox->setNotify(true);
else
cbox->setNotify(false);
}

}
}while(1);

dialog->destroy();
}

Lets go through the code a few lines at a time now.


YDialog * dialog = YUI::widgetFactory()->createPopupDialog();

As in hello world example, the line above is used to create the window, which would contain all our widgets (buttons, radio buttons etc).


YLayoutBox * vbox = YUI::widgetFactory()->createVBox( dialog );
YLayoutBox * radiobox = YUI::widgetFactory()->createHBox( vbox );

The next two lines, are used to set the layout. We add a VBox layout (used to arrange the widgets in a vertical stack) to the window and add a HBox layout (used to arrange the widgets in a horizontal stack) to the vbox layout created before. The layouts, as such do not show up on the screen. They are used as containers to place widgets on the screen in an easy way. It is always preferred to place components/widgets in such containers as they take care of events like window resizing.


YRadioButtonGroup *radiogrp = YUI::widgetFactory()->createRadioButtonGroup(radiobox);
YRadioButton *immediate = YUI::widgetFactory()->createRadioButton(radiobox,"Immediate", false);
YRadioButton *event1 = YUI::widgetFactory()->createRadioButton(radiobox,"Not Immediate", true);

The next three lines are used to create a radio button group, radiogrp and two radio buttons immediate and event1. Radio buttons are used when the user has to select exactly one of the given choices. Hence, it becomes necessary to group these radio buttons. The radio button group helps us do just that.

Please note that just by adding radio buttons to a radio button group, the other radio buttons are not deselected by default. This is handled in the event loop.

While creating the radio buttons, the first parameter is the parent widget, inside which the radio button is placed. The second parameter is the label value or the value of the text displayed next to the radio button. And finally, the last value represents the default selected state. In our example, the immediate radio button is disabled by default whereas the event1 radiobutton is enabled by default.


immediate->setNotify(true);
event1->setNotify(true);

In the last two lines, we call the set notify property of both the radio buttons and set them to true. If this is not done, an event is not generated by the radio button itself and we will have to manually check using some other strategy, like using a push button.

Let’s take a minute to understand this. There are two ways in which we can handle events. The first is when any change to the widget generates an event or by using another widget to generate an event and use it to check for any change. In the second case, the most commonly used widget would be the push button. You would probably have noticed google instant, where the search page gets updated as you change the search phrase. While not similar in technology (they use ajax), that is the an example for the first type of event notification. If you remember google in the olden days, where we had to press the search button after we change the search phrase everytime. That is an example for the second type. Let’s call the first type of events as “immediate” and the second type as “event-driven”.

So, since we want any clicks/changes to the radio button to reflect on it’s own without any button presses, we set their setNotify methods to true! Easy right? Let’s move on now.


radiogrp->addRadioButton(immediate);
radiogrp->addRadioButton(event1);

In the first two lines, we add the radio button to the radio button group we created. This is done because immediate mode and event driven modes are opposite and cannot be enabled at the same time. Hence, we group them so that only one can be enabled at a time. We disable the other radio buttons in the event loop and is not done automatically. This is a very important point to note as it is not very intuitive.


YLayoutBox * hbox = YUI::widgetFactory()->createHBox( vbox );
YComboBox *cbox = YUI::widgetFactory()->createComboBox(hbox,"Choose Item",false);
YLabel *label = YUI::widgetFactory()->createLabel(hbox,"",false,false);

The next set of lines define a HBox for the combo box and the label widget. The combo box is simply another name for the drop down box which we use to select an item from a list of items. In our case, while creating the combo box, we use three parameters. The first, is obviously the parent widget. the second, is a label that is used to describe the combo box. In our case it is “choose item”(Maybe “Choose language” is more appropriate?). The third parameter is a boolean value that is used to set the editable property of the combo box. If set to true, the user is allowed to enter a value that is not a part of the list. He can type it out as if the combo box was a text field or choose from the list. Since we want the user to select only from the list, we set this to false.


YLayoutBox * hbtnbox = YUI::widgetFactory()->createHBox( vbox );
YPushButton *button = YUI::widgetFactory()->createPushButton(hbtnbox,"&Update");

The next two lines are used to create a HBox and add a push button to it. Since we have seen the parameters used to create the push button in the last post, i am not elaborating it here again.


cbox->addItem("English",true);
cbox->addItem("Spanish",false);
cbox->addItem("French",false);
cbox->addItem("Hindi",false);
cbox->addItem("Chinese",false);
cbox->addItem("Russian",false);

The last set of lines are used to add elements to the combo box. The second boolean parameter is the default selected element. If “Spanish” was set to true, the first and default element in the combo box would be Spanish.

Please note that there are more efficient ways to add large number of items to a combo box. In this example, we neglect that as we have very few items.

A point to be noted here is that when layouts are used, please pay attention to their parent widget parameters. Giving incorrect parameters can cause skewed layouts. Also, like in our case, when we nest 3 HBox elements in a VBox, the Hbox elements are stacked one over another with the first HBox on the top. But the elements are arranged linearly within each HBox. I hope this distinction is very clear.

And that’s the end of the user interface! Take a break and lets move to the event handling part.


do
{
YEvent *event = dialog->waitForEvent();

if(event)
{
if(event->eventType() == YEvent::CancelEvent)
break;

if(event->widget() == cbox || event->widget() == button)
{
label->setText(cbox->selectedItem()->label());
}

if(event->eventType() == YEvent::WidgetEvent && (event->widget() == immediate || event->widget() == event1))
{
radiogrp->uncheckOtherButtons((YRadioButton*)event->widget());

if(event->widget()==immediate)
cbox->setNotify(true);
else
cbox->setNotify(false);
}

}
}while(1);

These set of lines control all the events and actions of our program. It is very important to understand the working of the event loop in order to program effectively in YUI. Let’s go line by line.

As you can see, the entire set of code is placed in an infinite do while loop. The loop need not be do while. It can be a while loop or a for loop (your pick). The reason for the loop being infinite is obvious. We want to keep polling for events as long as the program is running.

The first line in the loop is is used to create an instance of YEvent which is equated to dialog->waitForEvent(). Here, dialog is the main window. We use this as it is the top level container for out program i.e, all widgets are under this. The dialog->waitForEvent() function is used to poll for events. With no parameters, it waits indefinitely for an event to occur. In some cases, we would like to set a time out and carry on with the loop in case no event occurs. In such a case, we can use an over loaded method which takes an integer which is the timeout in milli seconds. Thus, dialog->waitForEvent(5) waits for 5 ms for an event to occur. If an event occurs, the event is stored in the YEvent variable and the the loop continues. If no event occurs, then the program execution continues after the timeout, 5ms.

It is important to note that the waitForEvent is an infinite loop which is truncated by the timeout time or by an event.

In the next line, we check if event is not empty. This is not needed if a timeout has not been specified since this line is executed only when an event has occurred.

The main functions associated with YEvent variables are :
1. eventType() – Returns the event type. The types are defined in the YEvent class.
2. widget() – Returns the widget that raised the event.

The above two functions are frequently used and is handy to know about their function before we move further.


if(event->eventType() == YEvent::CancelEvent)
break;

In the above line, we check if the event is of the type “CancelEvent”. This event is triggered when the user closes the window. In such a case, we want to break out of the loop and destroy the widgets. Hence, we issue the break command.


if(event->widget() == cbox || event->widget() == button)
{
label->setText(cbox->selectedItem()->label());
}

In the above set of lines, we check if either the combo box or the button has raised an event using the widget() function. If true, we change the label text by using the setText() function as shown above. cbox->selectedItem()->label() is used to retrieve the text of the currently selected element.


if(event->eventType() == YEvent::WidgetEvent && (event->widget() == immediate || event->widget() == event1))
{
radiogrp->uncheckOtherButtons((YRadioButton*)event->widget());

if(event->widget()==immediate)
cbox->setNotify(true);
else
cbox->setNotify(false);
}

After the last two blocks of code, i guess this is easier to understand.Here we check for the event type “WidgetEvent”. Radio buttons, when setNotify is set to true, raise such events in case of a change. Also, we check if the widget that raised this event is either immediate or event1, our two radio buttons. This is to ensure that the event is being raised by specific widgets though in our case, it may be trivial and not necessary.

In the next line, we unset the other radio buttons in the same group. Again, note that we do this explicitly!! The uncheckOtherButtons takes a radio button as a parameter and unchecks all other radio buttons that are a part of the same group. Note that the uncheckOtherButtons function belongs to the RadioButtonGroup class and not the RadioButton class.

In the last few lines, we toggle the setNotify of the combo box depending on the radio button selected.


dialog->destroy();

This is the last line of code and is placed outside the event loop. It is used to destroy all widgets and the main window as well. Execution of this command truncates the program.

And that’s it! Phew… long post.

I hope this post helped a few of you out there to understand a the basic functioning of the YUI library. Now, you are ready to start writing a few programs of your own! In case you need some help, feel free to contact me through the comments section below.

About these ads

About N.B.Prashanth

I am an engineering graduate currently pursuing my Masters in Embedded Systems. Computers and programming form a big part of my life. My interests include : Programming, AI, Machine Learning, Automation, Circuit Design and Embedded Systems.

Posted on May 2, 2011, in openSUSE and tagged , , . Bookmark the permalink. 1 Comment.

  1. Why no screenshots?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: