Main Page | Recent changes | View source | Page history

Printable version | Disclaimers | Privacy policy

Not logged in
Log in | Help
 

CPP GUI RAD Development

From KDevelop

Contents

Overview

The KDevelop IDE provides several features that assist in the development of GUI applications using the cross-platform Qt GUI framework. This document provides an overview of the features and provides some guidance on how to use them.

If you are new to the Qt framework, I suggest reading the Qt Whitepaper and skimming the Qt tutorial. Also, have a look at this KDevelop TechNote that contains a nice walkthrough (see Troubleshooting below for a discussion of how to save the form).

In this document, I have avoided using Qt's terminology for event handling ("signals" and "slots") and instead prefer the terms "events" and "event handlers," since I think those would be more familiar to my target audience: developers experienced with RAD tools such as C Builder, Delphi, or Visual Studio.

Unless otherwise noted, this document covers KDevelop 3.2.2 and Qt 3.3.

Introduction to Qt and KDevelop

KDevelop provides a GUI builder that lets you design Qt forms and widgets graphically using drag-and-drop. The GUI builder is an integrated version of Trolltech's Qt Designer tool, and I will refer to this integrated designer simply as the "designer."

To develop GUI applications in KDevelop using the designer, you need to understand the code generated by the designer. In this section, I will attempt to explain this by describing the code generated for this KDevelop TechNote.

Let's begin by looking at the code as it appears at the end of the tutorial. For each .ui file in your project, a corresponding C .h and .cpp file are generated during the build. The tutorial has you create a form in a file named mainbase.ui. When you build the project, the Qt moc tool processes mainbase.ui and generates mainbase.h and mainbase.cpp. These files do not get added to your project, but you'll find them in your project's src directory after you build the project.

Here is mainbase.h:

mainbase.h

 ...
 #include <qvariant.h>
 #include <qwidget.h>
 
 class QVBoxLayout;
 class QHBoxLayout;
 class QGridLayout;
 class QSpacerItem;
 class QPushButton;  
 
 class MainBase : public QWidget
 {
     Q_OBJECT
 
 public:
     MainBase( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
     ~MainBase();
 
     QPushButton* pushButton1;
 
 public slots:
     virtual void pushButton1_clicked();
 
 protected:
 
 protected slots:
     virtual void languageChange();
 
 };
 ...

This file defines a class named using the name of the widget defined in the corresponding .ui file. In the tutorial, you changed the name of the form from Form1 to MainBase.

For each event handler ("slot") defined in the .ui file, the moc tool generates a corresponding method in the .h file.

I won't show mainbase.cpp, because you usually don't need to concern yourself with it. Like mainbase.h, it is automatically generated during the project build. It contains code to construct the form at runtime, as well as a default implementation for each event handler method declared in mainbase.h. Note that you should not put your event handling code in mainbase.cpp, because each time you build the project, mainbase.h and mainbase.cpp may get regenerated, and any changes you may have made will be lost.

In the tutorial, you create a pushButton1_clicked() event handler. You write the implementation for that event handler in a subclass of MainBase named MainImpl, generated using a KDevelop wizard. Let's look at the header and implementation files of this subclass:

mainimpl.h

 ...  
 #include "mainbase.h"
 
 class MainImpl: public MainBase {
 Q_OBJECT
 public:
     MainImpl(QWidget *parent = 0, const char *name = 0);
 public slots:
     virtual void pushButton1_clicked();
 };
 ...

mainimpl.cpp

 #include "mainimpl.h"
 
 MainImpl::MainImpl(QWidget *parent, const char *name)
     :MainBase(parent, name)
 {
 }
 
 
 void MainImpl::pushButton1_clicked()
 {
   // event handling code for pushButton1 here
   qWarning("Hello");
 }

The MainImpl subclass overrides the pushButton1_clicked event handler method defined in MainBase, and defines an implementation for it. Since mainimpl.h and mainimpl.cpp are created once, using a wizard, and are not regenerated during the project build, this is the place to add custom code.

By the way, if you have used the standalone Qt Designer 3.x, and are used to putting code in .ui.h files, you can't take that approach with KDevelop. You must put event handling code and other customizations in subclasses of the class representing the widget.

To conclude this section, let's review what we've covered:

Here is a list of all of the files related to mainbase.ui:

Filename Description
mainbase.h Autogenerated on project build. Defines MainBase class. Look here to see which widgets are on the form.
mainbase.cpp Autogenerated on project build. Contains code to build the form. Look here for #include lines to copy to your mainimpl.cpp.
mainimpl.h Generated once by KDevelop subclassing wizard. Defines MainImpl class as a subclass of MainBase.
mainimpl.cpp Contains event handler implementations. This is where you put event handling code.
moc_mainbase.cpp Autogenerated on project build. Contains Qt "plumbing" for the MainBase class.
moc_mainimpl.cpp Autogenerated on project build. Contains Qt "plumbing" for the MainImpl class.


Practical Issues

Now that you have a basic understanding of how the GUI code is organized, before you dive in to write applications, there are a few practical considerations you need to know, particularly if you are new to the Qt framework. I'll address these in a question and answer form.

How do I manipulate widgets in an event handler?

Event handling code often needs to access and modify widget properties, and call widget methods. For example, let's say that your pushButton1_clicked() handler needs to change the text of the button. Here's the Qt code to make that happen:

 void MainImpl::pushButton1_clicked()
 {
   // event handling code for pushButton1 here
   pushButton1->setText("You clicked me!");
 }

If you make that change and then compile, the compile will fail. Look closely at mainbase.h to see why. The pushButton1 instance variable has type QPushButton, but the full QPushButton class declaration, defined in qpushbutton.h, is not available to the compiler. Instead, the moc tool generates a forward declaration in mainbase.h:

 class QPushButton;
 

To interact with pushButton1 in your event handler, you must add the following to the top of mainimpl.cpp:

 #include <qpushbutton.h>
 

This provides the full definition of the QPushButton class to the compiler, and permits you to invoke methods on the QPushButton widgets on your form.

You must #include the appropriate header file in your implementation class .cpp file for each type of widget you need to manipulate in an event handler.

Tip: To save you time trying to figure out what header files need to be included in mainimpl.cpp file, simply copy the #include lines from the moc-generated mainbase.cpp file and and paste them into mainimpl.cpp.

How do I get code completion for widgets I access in event handler?

KDevelop provides a handy code completion feature. To use it with GUI development, begin by creating a Code Completion database for the Qt library:

  1. Choose Project > Project Options to access the KDevelop Project Options dialog.
  2. In the C Specific section, on the Code Completion tab, click Add to add a Code Completion database.
  3. Pick the KDevelop Qt PCS Importer, click Next, select the qt library installed on your system, and finish the wizard.

Now, you can type the first few letters of a global Qt function and press Ctrl Space to get completion. For example, in an event handler method, try typing qW and pressing Ctrl Space. You should see a suggested completion for the qWarning function.

However, if you try typing pushB and press Ctrl Space, expecting to see pushButton1 listed, all you'll get is a suggestion for the event handler method pushButton1_clicked, and if you type pushButton1-> you won't get suggestions for methods you can invoke on pushButton1. To get this kind of code completion, here are some suggestions:

Automake projects

If your project is an Automake project (for example, you started it using the Simple Designer based KDE Application template), you can get code completion for your widgets by adding a link to the moc-generated .h file to your project. Here's how:

  1. Build the project to generate a .h file from your form's .ui file. This file will be placed in your project's debug/src folder.
  2. In the Automake manager, right-click the "Header in noinst" section and choose Add Existing Files.
  3. Browse to your project's debug/src folder, select the generated .h file, click Add Selected, then click OK.
  4. KDevelop will warn you that the selected file is not in the src directory. Choose Link (the recommended option).

Thanks to teatime for this suggestion.

QMake projects

If your project is a QMake project (you started it using a QMake project template), don't try to add the moc-generated .h file to your project to get code completion. The project will fail to build if you do this.

Consider creating a Code Completion database for your project's src directory:

  1. In the Code Completion section of the Project Options, click Add to add a Code Completion database.
  2. Choose KDevelop Custom Directory PCS Importer
  3. Enter a name for the database (your project name is a good one), and browse to select your project's src directory.
  4. Click Add to add the src directory to the database. Click Next, then Finish.

Note: You have to delete and re-create the code completion database anytime you change your form by adding, deleting, or renaming any widgets. This is certainly not a desirable solution; if you know a better way, please edit this document and provide your suggestion.

Tips

Here are some thoughts on how to use KDevelop most efficiently when developing C GUI applications.

  1. Begin by designing your form as completely as possible. Give good names to all widgets that you will need to access in event handlers.
  2. Define the event handlers in the designer. Use the wizard to generate a subclass.
  3. Build the project. This generates .h files for the next step.
  4. If you want code completion, and you're working with an Automake-based project, add a link to the generated .h file to your project. For a QMake-based project, add a code completion database for the project's src directory.
  5. Write the event handlers.

For a QMake-based project, if you add, delete, or rename any components in the form designer, you must delete the code completion database and repeat steps 3-4.


Troubleshooting

I'm having problems with KDevelop not saving my form design.

This is a known problem (Bug #101268) due to incomplete integration of the designer into KDevelop. The KDevelop designer will save changes only when it has focus. When you have several files open in KDevelop, using File > Save All won't save changes in the designer, and switching to the designer and clicking Save won't work either, unless you explicitly click on your form in the designer first. Worse, if you close the form designer without saving, it will close without warning you that you have unsaved changes that will be lost.

The following procedure will save the form:

  1. Switch to your form in KDevelop
  2. Click on the form in the designer to give the designer focus (you'll see the toolbars change when you do that)
  3. Click Save.

The designer will save the form, although in some cases the tab icon may still show an icon indicating it is not saved.

Retrieved from "http://kdevelop.org/mediawiki/index.php/CPP_GUI_RAD_Development"

This page has been accessed 15,686 times. This page was last modified 17:24, 29 June 2007. Content is available under GNU Free Documentation License 1.2.


[Main Page]
Main Page
Community portal
Current events
Recent changes
Help
Donations

View source
Discuss this page
Page history
What links here
Related changes

Special pages
Bug reports