" Dont judge those who try and fail, judge those who fail to try "

Beginning KDevelop Programming Version 3.x

Chapter One :- Introducing KDevelop Chapter Two :- The KDE Application Chapter Three :- Common Widgets Chapter Four :- Containers And Views Chapter Five :- Database Programming With MySQL Chapter Six :- Input And Display Chapter Seven :- KDE Display Widgets Chapter Eight :- KDE Buttons And Input Chapter Nine :- KDE Containers And Views Chapter Ten :- Custom Widgets Chapter Eleven :- Events Chapter Twelve :- Drawing Chapter Thirteen :- Global Information and Configuration Files Chapter Fourteen :- A Simple Editor Application

Appendices

Appendix A :- Upgrading KDevelop

Downloads

PDF

Beginning KDevelop Programming ( 13.4 mb )

ZIP

Chapter One Source ( 1.2mb ) Chapter Two Source ( 3.8 mb ) Chapter Three Source ( 6.9 mb ) Chapter Four Source ( 6.4 mb ) Chapter Five Source ( 6.6 mb ) Chapter Six Source ( 3.6 mb ) Chapter Seven Source ( 2.2 mb ) Chapter Eight Source ( 2.2 mb ) Chapter Nine Source ( 1.1 mb ) Chapter Ten Source ( 5.3 mb ) Chapter Eleven Source ( 1.6 mb ) Chapter Twelve Source ( 5.2 mb ) Chapter Thirteen Source ( 3.8 mb ) Chapter Fourteen Source ( 616 kb )

Contributions

Contributors Page

Contacts

Author

[email protected]

Page Designer

[email protected]

Chapter Four :- Containers And Views

In this chapter we will look at the next three tabs in our Gui toolbox, these being the Buttons which contains one button that we haven't seen yet and the Containers and Views tabs.

The Tool Button

The QToolButton widget is more of a design guideline than an actual new widget implementation in that it is designed with the idea that it is used for tools and configuration options, hence the name. It is shown in the workspace as a button with the picture of a spanner head and when you place it on the form it has a text of ... The idea here is that you add an icon to the QToolButton and then display it without text.


The button on the left above is the QToolButton while the button on the right is the standard QPushButton. The QToolButton is capable of displaying either an icon or text whereas the QPushButton can display both icons and text at the same time. The QToolButton is used mostly on toolbars and dialogs where it is used to setup some specific options.

The Tab Widget

The QTabWidget class displays pages on a form in an organised way through the use of tabs at the top of each page. Customarily each page will have a name and they will be used for configuring a program before assigning it a specific task with each page being assigned a certain common area of operability ie one tab page may contain page options for a printer while another may contain control options for the printer hardware.


In the example we can see a QTabWidget with two tabs and the first tab is on display. The first tab contains a QGroupBox widget which has a button and a number of QRadioButtons. You can see here that unlike the QButtonGroup class the QGroupBox class doesn't control the QRadioButtons for you. This gives the QGroupBox a purely presentational role in that you can have related items under a collectives header within the form but it adds nothing else.

Using properties in KDevelop you can change the appearance of the tabs slightly and have them appear at the bottom or the top of the page, although you can't have both and the most commonly used position is the top of the page. To add or edit the tab right click on the widget for the menu.


The top three items of the menu apply to the QTabPage widget. The page title is the text that is seen on the top of the tab page and you can add or delete pages as required.


With the second tab we can see a frame and once again a few random buttons. The QFrame class is the base class of all the container classes and can be used to organise the layout of widgets within the form but does not provide any text options as a group header nor does it control the selection of radio buttons as the QButtonGroup class does.

The Widget Stack Widget

The QWidgetStack displays a user configured number of pages with no descernable page selection and it is usually implemented with forwards and back ( next and prev ) buttons. It is basically a wizard widget where the user can select options and progress steadily through the pages rather than being able to jump from page to page as they can with the tab widget or the tool box widget.


The application has three pages each containing a QLabel with some text which are moved through with the following code,

void ChapterFourWidgetStackWidget::forwardButton_clicked()
{
    if( widgetStack->widget( ChapterFourWidgetStackWidget::widgetPageOne ) == widgetStack->visibleWidget() )
    {
        widgetStack->raiseWidget( ChapterFourWidgetStackWidget::widgetPageTwo );
        return;
    }
    if( widgetStack->widget( ChapterFourWidgetStackWidget::widgetPageTwo ) == widgetStack->visibleWidget() )
    {
        widgetStack->raiseWidget( ChapterFourWidgetStackWidget::widgetPageThree );
    }
}

void ChapterFourWidgetStackWidget::backButton_clicked()
{
    if( widgetStack->widget( ChapterFourWidgetStackWidget::widgetPageTwo ) == widgetStack->visibleWidget() )
    {
        widgetStack->raiseWidget( ChapterFourWidgetStackWidget::widgetPageOne );
    }
    if( widgetStack->widget( ChapterFourWidgetStackWidget::widgetPageThree ) == widgetStack->visibleWidget() )
    {
        widgetStack->raiseWidget( ChapterFourWidgetStackWidget::widgetPageTwo );
    }
}

The widget pages are added to the QWidgetStack with the code,

widgetStack->addWidget( WStackPage, 0 );

in the generated quot;projectnamequot;widgetbase.cpp file and rather than use magic numbers I added an enum to the ChapterFourWidgetStackWidget class,

enum WidgetPages{ widgetPageOne, widgetPageTwo, widgetPageThree };

so if moving forward the code checks if the currently visible page is widget page one using the visibleWidget function and the widget( int ) function which takes the id of the widget to retrieve. If the two match then raiseWidget( int ) is called with the required id to give the widget we want.

Accelerators

In the picture and if you run the application you can see that the Back and the Forward buttons have an underlined letter this is the accelerator for the button. An accelerator is the keyboard shortcut that the user can use so that they don't have to use the mouse to operate the application. Accelerators are set by putting an & infront of the letter that you want to use as the keyboard shortcut when typing the text into the properties tab.


you can also set it explicitly in the accel section. Accelerators are part of the guidelines for what makes a good application so if you are going to publicly release your application they are required.

Views

In the next example we look at the remaining containers and the views tab of the toolbox and see how to fill each one with data, which we do by setting up a Simple Designer based KDE Application as described earlier and draw the widgets on the form, but first,

Graphical Connections

It is also possible to use KDevelop to add Signals and Slots to the program by using the Connections menu if we right click on the form,


This will bring up the dialog,


This gives us a way to add the four parameters that we need for a call to connect which if you remember,

connect( pageOneButton, SIGNAL( clicked() ), this, SLOT( pageOneButton_clicked() ) );

has the format of parameter one is the object emitting the signal, parameter two is the signal to be emitted, parameter three is the object receiving the signal and parameter four is the slot or function that will respond to the signal.


If you click on the New button then the dialog inserts a line of QComboBoxes that allow you to select the widgets and functions. The Sender is,


the object emitting the signal and in this case it is the directoryButton object, The Signal is,


one of the standard signals emitted by the QPushButton class. The reciever,


can be anyone of the widgets within the program, which is one of the reasons you should be cautious when using this method as it only takes a slight lack of concentration to mess up your program here, if you start trying to send signals to classes that you don't want receiving them. The slot to handle the signal is,


and this is where we can get ourselves into trouble. If you think that this is a wizard that is going to create a slot for you that responds to the directoryButton widget being pressed then you are just about as wrong as you could be and are going to end up with a dialog that looks something like this,


what you actually have here is a pair of QButtons that are emitting signals when clicked but both of them are being directed to the same button_clicked slot which in this case is the button_clicked slot that was left behind from the automatically generated code when the project was created.

What the Slot is showing when you look at it is the slots that are already defined, unlike when you create a connection by right clicking on the Signal Handlers tab in the Properties box earlier, here you are just selecting one of the available slots. To add a new slot you need to click on the Edit Slots button,


here you can add the slots and functions that you want to implement in your code. It is a matter of personal preference if you use this method of connecting signals and slots but when you open the View and Edit Connections dialog you want to see something like this,


with each signal being clearly directed to it's own slot. There will of course be occaisions when you want to send signals from different widgets to the same functions but these will probably be few and far between.

The Views Demonstration

The idea behaind the views demonstration is that as all the widgets are use for displaying data we add all the widgets to a form open up a directory and then display the files in the directory in the different views. Note though that this is just for display purposes only and we wont be adding any functionality to program other than what we need for display purposes.


The application consists of a QToolBox containing a QListView, a QIconView and a QTableView on different pages. The user selects a directory through the “Select A Directory” button and each view displays the details of the file or directory in a slightly different way.

The options for each widget are setup through the right clicking on the widget and and selecting edit


The options when you click on edit are all pretty similar and straight forward,




The choices about what each view should show were made by looking at the KFileItem class in the KDevelop help files and splitting the information into managable chunks across the three views.

Adding Libraries To A Project

In the following code we use classes from both KDE and Qt, the rather surprising thing is that while the Qt Libraries appear to be included as a whole the KDE libraries aren't and this is the first place we come across this as we are trying to use classes from the KIO library. In order to add a library to a project open the automake manager and select the project line,


You will notice that the tool button on the right has ceased to be greyed out, if you click on it or alternatively right click on the highlighted line and select options from the drop down menu, you get this dialog.


The flags option gives you some specific options that you can use when linking your project. We are happy to leave these at the defaults for the moment, what we are interested in is the Libraries tab.


Here we can see the libraries that are already included in the project and we want to add the KIO library so click on add,


The dialog pops up with the include option already to pass to the linker. Because we are using one of the KDE libraries delete this and add,


Click on OK,


Now we can add any class from the KIO library, as long as we include the header files. So what does it mean.

The $(LIB_KIO) tells the makefile to include the KIO library from the library directory. For the purposes of KDE on a 64 bit system this will be something like /opt/kde3/lib64. The library itself will be called libkio. with the .o and .so files being the files that are loaded at run time or linked to the project and the .la file being the file that the linker reads. The .la file looks like this,

# libkio.la - a libtool library file

# Generated by ltmain.sh - GNU libtool 1.5a (1.1240 2003/06/26 06:55:19)

#

# Please DO NOT delete this file!

# It is necessary for linking the library.

# The name that we can dlopen(3).

dlname='libkio.so.4'

# Names of this library.

library_names='libkio.so.4.2.0 libkio.so.4 libkio.so'

# The name of the static archive.

old_library=''

# Libraries that this one depends upon.

dependency_libs=' -L/opt/kde3/lib64 -L/usr/lib/qt3/lib64 -L/usr/X11R6/lib64 /opt/kde3/lib64/libkdeui.la -L/usr/lib64 -L/usr/lib64/ -L/usr/X11R6/lib64/ /opt/kde3/lib64/libkdesu.la /opt/kde3/lib64/libkwalletclient.la /opt/kde3/lib64/libkdecore.la /usr/lib64/libstdc++.la /opt/kde3/lib64/libDCOP.la -lresolv -lutil /usr/lib64/libart_lgpl_2.la /usr/lib64/libidn.la /opt/kde3/lib64/libkdefx.la /usr/lib/qt3/lib64/libqt-mt.la -lfreetype -lfontconfig -lXi -lXrandr -lXcursor -lXinerama -lXft /usr/lib64/libfontconfig.la /usr/lib64/libfreetype.la /usr/lib64/libexpat.la -ldl -lpng -lXext -lX11 -lSM -lICE -lpthread -lXrender -lz /usr/lib64/libfam.la /usr/lib64/libstdc++.la'

# Version information for libkio.

current=6

age=2

revision=0



# Is this an already installed library?

installed=yes



# Should we warn about portability when linking against -modules?

shouldnotlink=no



# Files to dlopen/dlpreopen

dlopen=''

dlpreopen=''

# Directory that this library needs to be installed in:

libdir='/opt/kde3/lib64'

As you can see this is one of those files that is only complicated if you have to try and write it yourself. It is simply a list of what the names for the library are, what files it needs to be present to work properly and some version and location details.

Selecting A Directory.

Now that we have all the necassaries out of the way we can get on with getting the program to do something. The first task is to get allow the user to add select a directory which they do by clicking on the Select A Directory button.

The code for the slot directoryButton_clicked() looks like,

bool bTest = true;
KURL kurlDir;
        
/// The Qt Way
///
/*      
kurlDir = QFileDialog::getExistingDirectory();
setDirectory( kurlDir.pathOrURL() );
if( bTest == true )
{
   KMessageBox::information( this, directory(), "Qt version" );
} 
*/

/// The KDE KFileDialog Way
/// 
        
        
KFileDialog *ptrFileDlg = new KFileDialog( QString::null, QString::null, this, "KDE KFileDialog Version", true );
if( ptrFileDlg == 0 )
{
   KMessageBox::error( this, "Unable to allocate the file dialog", "KDE KFileDialog Version" );
   return;
}
         
ptrFileDlg->setMode( KFile::Directory );
if( ptrFileDlg->exec() == KDialog::Accepted )
{
   kurlDir = ptrFileDlg->selectedURL();
   setDirectory( kurlDir.pathOrURL() );
   if( bTest == true )
   {
      KMessageBox::information( this, directory(), "KDE KFileDialog Version" );
   }
}
        
delete ptrFileDlg;
        
        
fillViews();

As you can see there are different ways to select a directory implemented in the function. Each of them display a standard dialog for selecting the directory and store the result in QString strDirectory which is a private member of the class through the setDirectory function. The first way demonstrated is the Qt way as it should be noted that although we are using KDevelop and programming for KDE at the moment we are using very little of the KDE libraries and it wouldn't be too difficult to alter all the examples so far so that they were stand alone Qt applications.

If you try running the seperate versions the dialogs look different,


is the Qt version and


is the KDE version, personally I prefer the Qt version when selecting directories and the KDE version when selecting files. As usual it is a matter of personal preference.

Functionally the only difference you will notice is that the Qt method opens the Documents folder by default whereas the KDE methods open the current directory that the program is running from unless you specify a directory in the constructor. The bool variable bTest is provided so that you can see what string is being placed in the strDirectory string while testing the program.

Filling The Views

The views are filled in with the data in the fill views function. which starts with,

QDir dir( directory() );
const QFileInfoList *fileInfoList = dir.entryInfoList();

First of all we create a QDir by passing in the saved directory and then call entryInfoList to get all the entries in the given directory which are stored in the returned QFileInfoList then all we need to do is set up the mechanism for cycling through the QFileInfoList.

QFileInfoListIterator it( *fileInfoList );
QFileInfo *ptrFileItem;
        
                
while( ( ptrFileItem = it.current() ) != 0 )

which is done through the creation of an iterator to move through the list and a QFileInfo pointer to identify each item. It is then simply a matter of moving through the list and then extracting the information that we want to put in each view.

The following code is for the QListView,

QListViewItem *listViewItem = new QListViewItem( listView );
KURL fileURL( ptrFileItem->absFilePath() );
KFileItem fileItem( KFileItem::Unknown, KFileItem::Unknown, fileURL, true );
listViewItem->setPixmap( ColumnOne, fileItem.pixmap( 0 ) );
listViewItem->setText( ColumnTwo, ptrFileItem->fileName() );
if( ptrFileItem->isSymLink() == true )
    listViewItem->setText( ColumnThree, "true" );
else
    listViewItem->setText( ColumnThree, "false" );
if( ptrFileItem->isDir() == true )
    listViewItem->setText( ColumnFour, "true" );
else
    listViewItem->setText( ColumnFour, "false" );
if( ptrFileItem->isFile() == true )
    listViewItem->setText( ColumnFive, "true" );
else
    listViewItem->setText( ColumnFive, "false" );
if( ptrFileItem->isReadable() == true )
    listViewItem->setText( ColumnSix, "true" );
else
    listViewItem->setText( ColumnSix, "false" );
if( ptrFileItem->isWritable() == true )
    listViewItem->setText( ColumnSeven, "true" );
else
    listViewItem->setText( ColumnSeven, "false" );
if( ptrFileItem->isHidden() == true )
    listViewItem->setText( ColumnEight, "true" );
else
    listViewItem->setText( ColumnEight, "false" );
               
++it;

We create a QListViewItem that has the current QListView as its parent and then to make getting the icon image easier a KFileItem is created which will give us a QPixmap of the files icon when we call pixmap( 0 ). The rest of the code simply tests for the required properties and adds true or false to the QListViewItem depending on their presence.

One thing to note codewise is the ending of the loop for the table

        
table->adjustColumn( ColumnOne );
table->adjustColumn( ColumnTwo );
table->adjustColumn( ColumnThree );
table->adjustColumn( ColumnFour );
table->adjustColumn( ColumnFive );

The calls to adjustColumn at the end automatically set the table column width so that it can accommodate the largest item that it needs to display.

What we end up with looks like this,




Summary

This brings us to the end of the containers and views in which we looked at how to set up some of the graphical views and containers that are available in the KDevelop GUI toolkit. We also and perhaps more importantly for future development saw how to add libraries that are not included by default into the project.