Chapter One :- Introducing KDevelop
In this chapter we will look at the default Hello World application generated by KDevelop and some of the tools that we will be using in future chapters. The aim of this chapter is to give the reader an understanding of how the default Hello World application works to the point where they would be able to start developing on the basic framework. It should be noted that throughout we will be treating different libraries as part of the same development environment. Putting it simply you can't develop KDE programs the way we are in KDevelop without relying on the Qt libraries and at some point probably on the Standard Template Library or on other libraries that come as part of the system. These libraries form the development environment that we are working with and as such will be treated as a whole development environment and not as separate libraries.
Your initial view of the KDE Development Environment will probably look something like this.
Take a good look as this is probably the last time you will see the KDE environment looking this simple as the KDE environment is configured to automatically open the previous project on opening there will normally be files open in the main window.
The Top Menu
The menu's at the top contain the standard options for a windowed environment with all the file, save, edit etc. options that should be familiar to anyone that has actually used a computer before. The main ones of interest for us at the moment are the Project menu and the Settings menu the Project menu because it will allow us to create our first project and the Settings menu so that we can configure KDevelop to use the tab spaces, colouring, fonts, etc. that we are used to. As these are entirely personal preferences anyway I'll leave you to play around with them.
The Left Side Bar
There are initially three buttons on the left hand side of the application that are, reading down, New File, File List and File Selector. The most important of these is the New File option. If you click on it you will see,
This is initially empty but later on will allow us to create new files to be added to the projects that we are working on.
The File List button shows the files that are currently open within the development environment and the File Selector option is a quick access file manager that will allow you to open files in the Development Environment.
The Right Side Bar
There are initially two buttons on the right side bar these are the Documentation and the Code Snippets buttons.
The Documentation when clicked looks like,
This lists all the programming materials that are installed as part of the set-up. and can be searched whenever you are looking for function references etc.
The Code Snippets button is a place set aside where you can place pieces of reusable code that can then be inserted into projects at will. This is something we will use as we go along.
There are also a number of buttons at the bottom of the screen which for now we can ignore as they are mostly output windows and knowing everything about them is not particularly necessary at this point.
The First Project.
The above dialog is how we are going to start all the programs that are developed here, you can get to it by clicking on Project/New Project and then by clicking on C++/KDE and scrolling down until you reach the Simple Designer based KDE Application. All we need to do in this dialog is set our source code directory, in my case it will be off the KDE folder and type in the name of our application, which in this case is ChapterOneHelloWorld. Once this is done click the active Next button.
The next dialog sets up the project options and looks like this,
For this application we set up the Author and the email address. These will be set to defaults when the dialog opens but you have the option to change them here. This license information will be written to the top of all the project files that are created within the project. The licensing options default to the GPL which is fine for our purposes.
Version Control
When we are happy with the setting we can move on to the version control options. the original dialog looks like this,
It should probably be noted here that when working on single person projects version control systems are largely unnecessary unless you develop a lot of libraries or do a lot of experimental code and using a version control on a single development computer is kind of defeating the object. We are however, going to use one here just to get used to it, so that development with version control systems will become as it should be second nature when developing projects. Also with this being Linux there is more of a chance that readers will go on to develop parts of the system which will require them to be comfortable with version control systems.
For this application we are going to set up a CVS version control. Why CVS? Simply because we have a gui to make life easy for with Suse under Development/Revision Control/CVS Frontend ( Cervisia ) from the system menu.
Once we have selected CVS and told KDevelop to create a module in the repository by checking the available box we need a location for our version control. The above image
At this point there are two ways of doing things these being the to initialise the repository or to create one if one doesn't already exist.
Creating A Repository
To Create a repository for your source code open up Cervisia and click Repository/Create
The image above shows Cervisia as it starts up from a clean install when no repositories at all are set on the system. As with KDevelop this is probably the last time you will see it looking like this as it will automatically load the last open project on start up.
When you click on Repository Start you will be asked to select a directory to save your versions to, I've chosen to create the main CVS directory off the Documents folder. You are then given a simple dialog which lists the current available repositories on the system which you can see just behind the dialog that has the focus. This is currently empty so we need to add one. The name you choose is entirely up to you, just type something in and click OK.
Another way to create a repository is to go to Repository/Repositories which will allow you to add new repositories to you system as shown below.
Viewing The Files
By far the quickest and easiest way to view the files in Cervisia is to open Konqueror and move to the folder where you told KDevelop to create the project, then right click on the folder and move down to Open With and Click Cervisia.
Cervisia comes with its own handbook that can be accessed via the help, we will return to Cervisia to look at some of the more common operations as we go but for now we'll get back to KDevelop and the project files.
Initialising The Repository
If we already have a repository set up and we want to use it for our new project we simply click on the “Init Local Repository” button and we will be asked for the location of our CVS Repository which in this case is Home/pseudonym67/Documents
It should be noted that these days KDE developers use the Subversion or SVN version control and that there is a frontend for it on the Suse 10 disc called KDESVN. This wont affect the programming in this book in any way as we are concentrating on writing programs on KDE not on developing KDE itself.
KDE Project Files
In keeping with the windows type approach and the idea that we are using KDevelop as a development tool to develop our own programs, we will be concentrating on the files available to us through the Automake Manager to the right of the screen which is where the files important to our project are listed.
Upon creation of our first project we should be able to see this,
We get this view by clicking on the Automake Manager tab to the right of the screen and then on the src folder. Here we can see the files generated by KDevelop for our first project. The main source files for our project are contained in the chapteronehelloworld section which contains four files that we will look at in a moment, First of all we will look at the support files which are contained in the other sections.
The first section is the Data in shelldesktop. This contains the file chapteronehelloworld.desktop
[Desktop Entry] Encoding=UTF-8 Name=ChapterOneHelloWorld Exec=chapteronehelloworld Icon=chapteronehelloworld Type=Application Comment=A simple KDE Application Comment[br]=Ur meziant eeun evit KDE Comment[ca]=Una aplicació KDE simple Comment[da]=Et simpelt KDE program Comment[de]=Eine einfache KDE-Anwendung Comment[el]=Μια απλή εφαρμογή του KDE Comment[es]=Una aplicación de KDE sencilla Comment[et]=Lihtne KDE rakendus Comment[eu]=KDE aplikazio simple bat Comment[fr]=Une application simple pour KDE Comment[ga]=Feidhmchlár Simplí KDE Comment[hi]=एक सादा केडीई अनुप्रयोग Comment[hu]=Egyszerű KDE-alkalmazás Comment[is]=Einfalt KDE forrit Comment[it]=Una semplice applicazione KDE Comment[ja]=シンプルな KDE アプリケーション Comment[nb]=Et enkelt KDE-program Comment[nl]=Een eenvoudige KDE-toepassing Comment[pl]=Prosty program KDE Comment[pt]=Uma aplicação simples do KDE Comment[pt_BR]=Um simples Aplicativo do KDE Comment[ru]=Простое приложение KDE Comment[sl]=Preprost program za KDE Comment[sr]=Једноставан KDE програм Comment[sr@Latn]=Jednostavan KDE program Comment[sv]=Ett enkelt KDE-program Comment[ta]=ஒரு சாதாரண கெடிஇ பயன்பாடு Comment[tg]=Гузориши оддиKDE Comment[tr]=Basit bir KDE Uygulaması Comment[zh_CN]=一个简单的KDE应用程序
As the name suggests and we can see from the file this is the configuration for the file that is used by the desktop when displaying short cuts/a link to the file or when it is running it. This includes information on the text encoding the name given to the application. The name of the executable for the application and the name of the icon for the application And the bulk of the file contains language specific information.
The next section is the Data in shellrc selection which also contains a single file, the chapteronehelloworld.rc file.
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> <kpartgui name="chapteronehelloworld" version="1"> <MenuBar> <Menu name="custom"><text>C&ustom</text> <Action name="custom_action" /> </Menu> </MenuBar> </kpartgui>
This file is part of the KGUIXMLClient system and works as a dynamic menu system. Basically the idea is that when you are writing a system where the menu options may vary depending on system state or file types then the menu options are stored here for all states that are catered for. As this is an advanced topic we will not be dealing with it in this project.
The next section, header in noinst, contains the main C++ header files for our project. These are the chapteronehelloworld.h file and the chapteronehelloworldwidget.h file.
The chapteronehelloworld.h file contains the following class declaration.
/** * @short Application Main Window * @author pseudonym67 <pseudonym67@hotmail.com> * @version 0.1 */ class ChapterOneHelloWorld : public KMainWindow { Q_OBJECT public: /** * Default Constructor */ ChapterOneHelloWorld(); /** * Default Destructor */ virtual ~ChapterOneHelloWorld(); }
This declaration is for our main form window that we will look at soon. The only thing that this class contains is the constructor and destructor for our C++ class and the Q_OBJECT macro. The function of the Q_OBJECT macro is to include the code for Qt windowing system that all our gui programming is based on. This macro will automatically be included with any graphical element we create as it is needed to implement the signals and slots mechanism that allows us to make the user interface responsive through the use of button clicks etc. Putting it simply a slot is a normal function in all ways except for the fact that it can be fired by a signal as well as being called normally. And a signal is basically what it sounds like, in Windows terms it would be called a message that fires the function from the Windows message loop.
The chapteronehelloworldwidget.h file contains the following class declaration,
class ChapterOneHelloWorldWidget : public ChapterOneHelloWorldWidgetBase { Q_OBJECT public: ChapterOneHelloWorldWidget(QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); ~ChapterOneHelloWorldWidget(); /*$PUBLIC_FUNCTIONS$*/ public slots: /*$PUBLIC_SLOTS$*/ virtual void button_clicked(); protected: /*$PROTECTED_FUNCTIONS$*/ protected slots: /*$PROTECTED_SLOTS$*/ };
We will look at the relationship between the header files shortly in the next bit but for now we have another class declaration that is pretty standard except for the fact that we have the declaration for the implementation for a slot function so we can safely assume at this point that our hello world application will respond to a button click as long as the function is implemented in the corresponding cpp file. One final point about the header file is the comments that start with /*$ are place holders for the KDevelop generated declarations so it is probably a good idea to leave them as they are.
The next section is the Icon data in kde_icon. This contains the icons for the application with both the 32 and 16 bit icons These should be straight forward but I haven't managed to find any applications that can open them.
Now we come to the chapteronehelloworld section which contains the main implementation files for our hello world project. This contains four files, three C++ files and a ui file. If we click on the ui file we get this
What we are looking at now is a standard form editing environment, where we can drag and drop user interface components on to our forms and set up responses to the buttons being pressed or default data that will be entered into our components or widgets.
Here we can see the chapteronehelloworld form with a label and a button with click me written on it. If we build the application now, Build/Build Project. We will be told by the environment that there is no make file for the project.
Click yes and the messages window will open. The only thing about the messages we are concerned with here is if the Automake is successful or not and if not why not. Pretty much the only reason why this should fail to work at this point which to be honest is not a valid reason at all but is one that we are going to have to live with is that when first starting this project I named the base folder for it as “Beginning KDE Programming”. This is a big no no as it appears that spaces are bad. So if you want you projects to build get rid of spaces in the names. It's probably best to make sure that there are no spaces in your project or your file names just to be on the safe side.
If we run the program through Debug/Start we get,
If we click the button we get,
Not very exciting but it's a start. A start that can show us how everything else works so that we now what we are doing when we move on to more interesting programs. So the question is how does it work? If we look at our chapteronehelloworld.ui file as a utf-8 file. By right clicking on the ui file and going to Open With/Open as UTF-8, note the form must be closed or KDevelop wont open the file as a text file.
<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> <class>ChapterOneHelloWorldWidgetBase</class> <widget class="QWidget"> <property name="name"> <cstring>chapteronehelloworldwidgetbase</cstring> </property> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>220</width> <height>133</height> </rect> </property> <property name="caption"> <string></string> </property> <grid> <property name="name"> <cstring>unnamed</cstring> </property> <widget class="QPushButton" row="1" column="0"> <property name="name"> <cstring>button</cstring> </property> <property name="text"> <string>Click Me!</string> </property> </widget> <widget class="QLabel" row="0" column="0"> <property name="name"> <cstring>label</cstring> </property> <property name="text"> <string></string> </property> </widget> </grid> </widget> <connections> <connection> <sender>button</sender> <signal>clicked()</signal> <receiver>chapteronehelloworldwidgetbase</receiver> <slot>button_clicked()</slot> </connection> </connections> <slots> <slot>button_clicked()</slot> </slots> <layoutdefaults spacing="6" margin="11"/> </UI>
What we get is a not very pretty print out of a file that we could read if we were feeling really like making work for ourselves but seeing as we don't we'll just notice that it's an xml file and open it with KXML Editor instead as this can open both .ui and rc.ui files.
Now that we have the ui file in the KXML Editor we can get an easier view of what's going on. If we look at the objects side of the KXML Editor we see
The first thing we see in the file is a class object which refers to the class ChapterOneHelloWorldWidgetBase and while we may not have a file called ChapterOneHelloWorldWidgetBase we do have on called ChapterOneHelloWorldWidget which has both a header and a C++ implementation file. If we look at the header again we notice something new.
class ChapterOneHelloWorldWidget : public ChapterOneHelloWorldWidgetBase { Q_OBJECT public: ChapterOneHelloWorldWidget(QWidget* parent = 0, const char* name = 0, WFlags fl = 0 ); ~ChapterOneHelloWorldWidget(); /*$PUBLIC_FUNCTIONS$*/ public slots: /*$PUBLIC_SLOTS$*/ virtual void button_clicked(); protected: /*$PROTECTED_FUNCTIONS$*/ protected slots: /*$PROTECTED_SLOTS$*/ };
Our ChapterOneHelloWorldWidget class inherits directly from the ChapterOneHelloWorldWidgetBase class which if we read the documentation we know inherits from QWidget. Although we are given a big clue when we look at the xml text/code in the KXML Editor,
Basically for all intents and purposes the ChapterOneHelloWorldClassWidgetBase exists in name only it is a mechanism for associating the controls/widgets we have placed on the form with the class in our project and providing the inheritance from QWidget. In chapter two we will look at the base classes and where they come from.
You may also have noticed that we have a slot declaration in the header file that says that this class will handle what happens when the button is clicked. If we look at the implementation file we can see how it is implemented.
ChapterOneHelloWorldWidget::ChapterOneHelloWorldWidget(QWidget* parent, const char* name, WFlags fl) : ChapterOneHelloWorldWidgetBase(parent,name,fl) {} ChapterOneHelloWorldWidget::~ChapterOneHelloWorldWidget() {} /*$SPECIALIZATION$*/ void ChapterOneHelloWorldWidget::button_clicked() { if ( label->text().isEmpty() ) { label->setText( "Hello World!" ); } else { label->clear(); } }
The button_clicked function simply checks to see if the label has any text. If it does it clears the box if it doesn't then the text “Hello World” is added to the label. So if we look at the xml again we can see how this is done.
In the connections section we can see that there is a single connection set up in the ui file. The connection has a sender which is a button and a signal which is clicked. It should be noted here that a sender will send a signal that it has been told to send regardless of if any object has registered to receive the signal. In order for a signal to be received by an object it must first register to receive the signal by declaring a slot to receive the signal. If an object does not register itself as a receiver it will never know anything about the transmitted signal. We can see from the xml that the registered receiver is the chapteronehelloworldwidgetbase class which we are overriding with the ChapterOneHelloWorldWidget class and we are in fact handling the signal when the button is clicked and the signal is sent.
You may be wondering why the xml lists the slots separately in a slots section. The reason for this is that we could have another widget that wants to receive the same signal and this is perfectly acceptable as the only thing tying the receiver to the sender is the fact that it has registered to receive a signal, there is nothing to stop another object registering to receive the same signal.
We are now in a position where we have a user interface or ui file described in an xml document that is then subclassed and implemented by our ChapterOneHelloWorldWidget class that is derived from QWidget. This is effectively what in Windows programming terms would be considered a control as the Widget we have is not a main window and doesn't have a menu or anything that we have come to associate with the main part of a windowed environment. So let's have a look at the remaining files and see how our widget is implemented in the rest of the program.
To start with we have only one remaining header file and this is the ChapterOneHelloWorld.h file which looks like this,
class ChapterOneHelloWorld : public KMainWindow { Q_OBJECT public: /** * Default Constructor */ ChapterOneHelloWorld(); /** * Default Destructor */ virtual ~ChapterOneHelloWorld(); };
As you can see there is literally nothing here beyond the inheritance from KMainWindow. If you highlight KMainWindow and right click on it you will be able to look it up in the help and you will get,
Left clicking KMainWindow in the finder index will open the KMainWindow class reference page in the help. A quick look at the inheritance and the collaboration diagrams at the top of the page shows us what we need to know and that is that KMainWindow inherits from QMainWindow and as such is a top level window. This means that KMainWindow will control the implementation of menu's, status bar etc. and the ChapterOneHelloWorldWidget class will control what happens within the window view. Diagrammatically it looks something like this.
The ChapterOneHelloWorld class inherits from KMainWindow and is the main window for the application and contains the ChapterOneHelloWorldWidget object which controls everything that happens within the main window area of our application. We can see this clearly when we look at the implementation of the ChapterOneHelloWorld class,
ChapterOneHelloWorld::ChapterOneHelloWorld() : KMainWindow( 0, "ChapterOneHelloWorld" ) { setCentralWidget( new ChapterOneHelloWorldWidget( this ) ); } ChapterOneHelloWorld::~ChapterOneHelloWorld() { }
The call to setCentralWidget in the constructor of the ChapterOneHelloWorld class sets a new object of ChapterOneHelloWorld application as the main widget for the form using the this pointer to tell the ChapterOneHelloWorldWidget class that the ChapterOneHelloWorld class object is its parent window.
The KDE Application Class
To a large extent we wont be focusing on the KApplication class a great deal but we will be relying on it to do it's job in every program we write and there is on important aspect of KApplication that we need to bear in mind. This is aspect is inherited from QApplication and it is the fact that QApplication works as a sort of garbage collector for widgets.
This means that all widget objects within the program should be defined as pointers and allocated on the the heap i.e.
WidgetDerivedClass *object; object = new WidgetDerivedClass;
For the most part we will only be adding new widget objects through the form developer and the code will be automatically added for us, with KApplication ( well its parent class QApplication ) taking care of the clean up code, But it should be noted in case you find yourself hand coding widgets.
Summary
In this chapter we have walked through all but one of the generated files in order to show in a line by line fashion the way the files interact with each other providing an overview of how the widgets or windows of a KDE application interact and how a KDE application is composed of separate widgets.