KDE Development - Part 8

From LXF Wiki

KDE Development

PART 8 With a twinkle in his eye, Jono Bacon sets forth to improve himself as a status symbol...

Welcome to another instalment of our KDE Development series in which we are going to plough on and add some more interesting and flexible features into LXFGallery. This month we are going to continue to sprinkle some user interface fairy dust on our code and make LXFGallery as easy to use as possible. This ease of use cannot be guaranteed by using one technique in isolation – we need to combine lots of techniques to provide an overall feeling of sheen.

A common user interface element in modern applications is the status bar. This small area at the bottom of the application window provides useful information that helps to indicate the current status of the application. A typical example of this functionality is in networking applications. When you connect to a network resource such as a website or FTP server, some programs will indicate that you are connected by displaying ‘Connected’ in the status bar, or by including a relevant icon. The benefit of this feature is that the user is always able to look at the status bar to get an idea of how the application is working.

Before we look at the code to actually implement the status bar, we will consider what types of information should go on there – always remember that just because you can use a particular feature in a particular way, it doesn’t necessarily mean that it is the best way of doing it.

Table of contents

Designing the status bar

The key point to remember about status bars is that they display different types of information for different contexts. In our previous example, the text ‘Connected’ is written in networking applications for the entire duration of time that the connection exists. When the connection drops, it will say ‘Offline’ or nothing at all. Either way, many tools indicate their connection status all of the time in the application window. Some other uses of the status bar will display a note for only a few seconds. An example of this is when you start the program; it may say ‘Welcome to xyz’.

Image:61_kde01.jpg

The humble status bar can prove
to be a lifesaver in an application...

The difference between these two types of use of the status bar is that the connection status example is something that the user is likely to check often, whereas the welcome note is not critical to the operation of the program. Although there is a subtle difference between the two, these kinds of decisions need to be made when starting the design of a new application. If you consider the needs of the user at this early level, you will be able to create a more coherent interface.

In LXFGallery we are going to have two sections in our status bar that will indicate different types of information:

  • Number of pictures This is a permanent entry in our status bar that will show how many images we have in the current album. Although not critical information, we only have two uses for the status bar and this is a reasonable use.
  • General status This area will display messages that appear for a few seconds when you interact with different parts of the program. As an example, we will display ‘Loading the album...’ when we open a directory full of pictures.

Some of you may be wondering why we are displaying the number of pictures in the status bar, but not the album directory. This is simply because the common user interface technique for indicating the current document (our album will be our current document in our context) is to display it in the caption of the window next to the application name. For example, LXFGallery - /home/jono/expophotos.

Creating the status bar

A status bar in KDE/Qt programming is simply an area at the bottom of the window that is reserved for storing widgets. This area is built into the KMainWindow class so that you can deal with it easily, and you can put any widget that you want into this area. Although there is a temptation to put buttons, combo boxes and an assortment of other interesting widgets here, try to keep your status bar as text-orientated as possible. This is simply because most users only experience text in status bars; anything other than this could cause confusion. To create the status bar, first create a function that will keep our status bar code together. To do this, first add a declaration to lxfgallery.h on the private part of the class:

void createStatusBar();

The reason we are creating this function inside the LXFGalleryclass is because this is the general ‘container’ class in which the rest of the functionality of the application is included. This class also inherits KMainWindow, and we want to use KMainWindow to access the status bar. We now need to add the main body of the function to lxfgallery.cpp:

void LXFGallery::createStatusBar()
{
}

Before we write the contents of this function, we’ll add the code the actually runs the function in the LXFGallery constructor:

createStatusBar();

This line is added after the createMenus(); line. This method of creating a function and then adding the code that calls the function is a good practice to get used to. There’s nothing more frustrating when your code is not working than finding out that you simply forgot to add the code to call the function in the first place.

The next step is for us to create some QLabels, which will be placed on the status bar. As we discussed earlier, the vast majority of status bars rely on simple textual information that is displayed in the bar. To achieve this, you will need to use some QLabels to create two different text indicators on the status bar (one for the number of pictures and one for the general information label). We will first declare these labels in LXFGallery in the private part of the class:

QLabel * statusPicsText;
QLabel * statusStatusText;

Remember to add #include <qlabel.h> when you add these lines to lxfgallery.h. Our next step is to create the status bar itself with the labels inside our createStatusbar() function. We will do this one label at a time, and we will discuss what each line does to achieve this. First, we need to create the actual label and add some simple text to it. Note how we also use the HTML < b > tag to make ‘None’ bold in the label:

statusPicsText = new QLabel(“Photos Loaded: < b >None</ b >”, this);

With the label created, our next step is set how this label will be aligned in the status bar. We would prefer to have it aligned centrally in a horizontal direction, and we can use AlignHCenter to indicate this:

statusPicsText->setAlignment(AlignHCenter);

The last tweak of our label is to set the minimum size for it. Many Qt widgets enable you to set sizes, and a useful function to automate this process is sizeHint(). This function will simply take into consideration the size status of the widget and give a hint that indicates the suggested size:

statusBar()->setMinimumSize(statusPicsText->sizeHint());

We will now perform the same steps to create our second (general) status bar label:

statusStatusText = new QLabel(“Status: < b >READY</ b >”, this);
statusStatusText->setAlignment(AlignHCenter);
statusBar()->setMinimumSize(statusStatusText->sizeHint());

With our two labels created, we can now add them to the main status bar. Use the addWidget() function that is part of the KMainWindow statusBar() feature to add each label:

statusBar()->addWidget(statusPicsText);
statusBar()->addWidget(statusStatusText);

statusBar() is useful in that it can be used to give access to the status bar in different parts of the application. Here we’re using it to add a widget, but there’s also a variety of other functions that can be used – see the documentation for more information. Our complete createStatusbar() function looks like this:

void LXFGallery::createStatusBar()
{
          statusPicsText = new QLabel(“Photos Loaded: < b >None</ b >”, this);
          statusPicsText->setAlignment(AlignHCenter);
          statusBar()->setMinimumSize(statusPicsText->sizeHint());
          statusStatusText = new QLabel(“Status:< b >READY</ b >”, this);
          statusStatusText->setAlignment(AlignHCenter);
          statusBar()->setMinimumSize(statusStatusText->sizeHint());
          statusBar()->addWidget(statusPicsText);
          statusBar()->addWidget(statusStatusText);
}

When you now compile and run the application, you will see the status bar containing the two labels appear at the bottom of the screen.

MORE IN-DEPTH OOP

Learning about OOP will help you with KDE coding

Object Orientated Programming (OOP) is at the heart of KDE/Qt development, and for many people this kind of programming can be a complex and difficult journey. Although we are not covering general OOP programming concept in this series, it is advised to continue learning more about OOP as the series gets more complex. As we write more code, we are likely t have more reliance on the theories involved with OOP, and much of the existing code has already used many of these theories.

A great place to start learning about some of these issues is the C++ FAQ available at http://www.parashift.com/c++-faq-lite . In addition to theonline copy of the FAQ, there is also a book version that considerably expands on the free online equivalent. Another useful guide is the cplusplus.com tutorial available at http://www.cplusplus.com/doc/tutorial .

If you are getting confused with some of the OOP principles covered in this series, another great place to ask for help is comp.lang.c++ on Usenet and the #c++ IRC channel on irc.eu.freenode.net . Of course, another place that is also useful for help is the Linux Format discussion forums at http://www.linuxformat.co.uk – go and discuss the series with other readers and help solve common problems together.

Interacting with the status bar

Now that we have created a status bar, it is only really useful if we can update it in different parts of the application with different types of information. With this requirement we do face a challenge, however, and we need to consider the best way of implementing status bar updates with our code base.

The reason why we keep the functions that control our status bar in the LXFGallery class is that this is where we deal with the general shell of the application. Despite this making logical sense, the problem is that we need to access functions in LXFGallery from other classes that are instantiated within the LXFGallery constructor (classes such as SelectionBarCode). This creates a challenge in how we access these other parts of the source code base effectively. To solve this, we can make use of Qt’s signals and slots to trigger changes in different parts of the code when needed.

Many languages and toolkits are based around a concept that if something happens (such as clicking on a button), the program should then perform a check to see if that button has been clicked and act accordingly. In some situations this can involve an endless amount of condition checks to determine if a potential interaction has occurred. In Qt we can bypass this process and essentially lay a number of conceptual mousetraps that can be triggered when certain functionality has occurred.

As an example, if we click on a button and we want something to happen, instead of making a connect() line for each button in the program, we can simply create a signal to emit and place a single connect() line somewhere that can listen out for when this signal has been triggered. This can be particularly beneficial when you want to hook together functions scattered around different parts of the program. We will demonstrate this process by creating a signal and emitting it so that we can run a slot to update the status bar.

Image:61_kde02.jpg

Adding the number of photos to the status bar is simple...

The first step is for us to create a slot that will actually update part of the status bar. As we have two parts to our status bar (the two labels), we will create a different slot for each part of the bar. If we first look at the number of pictures label, we will need to update the label with a number that indicates how many pictures are in the current album. We will begin by creating a declaration for this slot in the lxfgallery.h file. Place this line in the public slots: part of the file:

void updateStatusPicsLabel( const QString& );

In this slot we are going to pass a QString that will contain the number of pictures that are to be updated. We will now create the body of the slot in lxfgallery.cpp:

void LXFGallery::updateStatusPicsLabel( const QString& lab)
{
             QString textLabel = “Photos Loaded: < b >” + lab + “</ b >”;
             statusPicsText->setText(textLabel);
}

In this code we are first concatenating the text that appears in the label and putting it in textLabel. The reason why we are performing this procedure is that we only really want to pass the number of pictures to the slot, and not have to pass Photos Loaded: < b > (number) </ b > each time we update the status bar. The Photos Loaded section should be added by the slot to the number of pictures that we pass. This text is formatted by using the + operator to glue together Photos Loaded: < b >, lab and </ b > as a single string stored in textLabel. The next step is to use the QLabel setText function to set the contents of the label that was created on the status bar.

With the slot complete, you can now create the signal. This signal will be created in the SelectionBarCode class (the class where we load the pictures and hence need to update the status bar). Add this to the class:

signals:
   void updateStatusPics( const QString& );

The next step is to actually emit a signal when we need to update the status bar. The best place for this to happen is at the end of the addAlbum() function; this is when the photos are added to the thumbnail and they can be counted. Add this code right at the end of the function:

emit(updateStatusPics( QString::number(picList->count()) ));

This code uses the emit() function to emit the signal that we have just created, and we get the number of pictures by using the count() method that is used with our picture thumbnail box (picList). This method will return a number (uint) and not a string, so we also need to convert this number to a string by using the QString::number() method.

The final step is to connect the signal and slot together. This needs to be done in the class that contains the slot (LXFGallery). Remember to add this connect() line after the SelectionBar object has been instantiated (otherwise the class would not exist yet) and also after you have run the createStatusBar() function to create the status bar itself. Place this line right at the end of the LXFGallery constructor:

connect( selectionBar, SIGNAL( updateStatusPics( const QString& ) ), this, SLOT( updateStatusPicsLabel( const QString& ) ) );

This code will probably look familiar, as it works in virtually the same way as the previous connect() lines that we have used in the code.

Implementing status bar signals

We will now go on to create the functionality to update the second part of our status bar. Again, we will begin by creating a slot to deal with updating the label. This slot works in virtually the same way as our previous slot, but we change which label is updated and also change the starting text of the label from Pictures Loaded to Status. First we will create our declaration:

void updateStatusGeneralLabel( const QString& );

Next we can create the main body of the slot:

void LXFGallery::updateStatusGeneralLabel( const QString& lab)
{
            QString textLabel = “Status: < b >” + lab + “</ b >”;
            statusStatusText->setText(textLabel);
}

The next step is to create a signal that can trigger a change for this general part of the status bar. Add the following line to the signals: part of selectionbarcode.h:

void updateStatusGeneral( const QString& );

Now we can actually emit the signal with something to update the box. An example of this is if we wanted to indicate that the photos have been loaded. Add this line to the end of the addAlbum() function after the previous emit() line:

emit(updateStatusGeneral(“Loaded photos”));

Finally, we need to connect all of this together so that the emitting of the signal will trigger the slot. Add this line to the end of the LXFGallery constructor just after the last connect() that we added:

connect( selectionBar, SIGNAL( updateStatusGeneral( const QString& ) ), this, SLOT( updateStatusGeneralLabel( const QString& ) ) );

Image:61_kde03.jpg

Changing the selected album will update the status bar.


Additional status updates

With an infrastructure in place to update the status bar, we can now add some additional features to ensure that the status bar is updated with necessary information. At the moment, the number of pictures status label is being updated when we load a new album, but when there are a number of albums loaded, the number of pictures should be changed when an album is selected in the album list box. In addition to this, it would be useful to indicate in the general status area that we are changing the selected album.

To add these changes, simply add two emit() lines at the end of the changeSelectedAlbum() function (the function that changes the selected album):

emit(updateStatusPics( QString::number(picList->count()) ));
emit(updateStatusGeneral(“Changing selected album”));

Now, compile the code, run the program and load up more than one album. If you now click on the entries in the album selection box, you will see that the number of pictures is updated in the status bar. The general status bar will also indicate that you have changed the album. A status thing In this issue we have covered a lot of ground, and we have written a lot of code to get our status bar working. These steps have involved us learning about how to create a status bar, adding labels, creating signals/slots to update the status bar across our web of classes, and the all-important usability considerations that need to be made when creating any kind of interface element. As we meander through the series and explore these different aspects of our program, you can see how different parts of the code will create distinctive restrictions and opportunities for us. Many of these rules are based around the concept of Object Orientated Programming (OOP), and as our program gets more complex, a better understanding of OOP will be essential. See the box for more on the complex world of OOP. Until next month, good luck with hacking LXFGallery and remember to send in your feedback about the series. Your comments will help push the series and LXFGallery in the direction that you want it to. Good luck!

READER CONTRIBUTIONS

Thanks must go out to Iain Moppett, Marc Roth and Leif Nordlund for their comments on the series. Remember that you can send your comments over to jono@jonobacon.org and you can also access the latest code and information on http://www.jonobacon.org/minisites/linuxformat/kdedevelopment

NEXT MONTH

Next month we are going to continue our development and resolve some of the bugs and problems before beginning to move on to add some additional features to deal with our photos.