By: Ankit Khare
GUI programming for Linux has traditionally been a difficult task. Trolltech
has changed all that by introducing Qt, a platform-independent Object-oriented
library, that allows programmers to create GUIs easily. The Qt library allows
components of the GUI to interact with each other elegantly by using slots and
signals. Qt is in its third avatar, meaning v3.0, and is now a mature library.
It has even branched off as Qtopia, for development of GUI in embedded systems.
The Qt development kit is available commercially for nearly every platform,
including the Mac. For Linux it's under L'GPL.
We'll talk about how to use Qt by building a basic graphical frontend for
mpg123, a popular command line MP3 player for Linux, using C++. Extensions are
also available for using the Qt library in Perl or Python programs. To get
started, install Qt development libraries from your Linux installation CD.
It's not installed by default. You'll find them in PCQ Linux 7.1 CD2 in the
RPMs folder with file names qt-designer and qt-devel.
Hello Qt
To begin on any programming odyssey, a Hello world program is necessary. So,
let's see how to write one in Qt. Simply put the following script in any text
editor and save it in a separate directory.
#include
#include
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QPushButton hello(“Hello world!”, 0 );
hello.resize( 100, 30 );
a.setMainWidget( &hello );
hello.show();
return a.exec();
}
Now for compiling the code we have to take care of the following three steps.
- Create the project file using the qmake —project
- Type qmake at the command prompt to create the makefile
- Compile the source code with the make command. If all your libraries are
installed correctly, an executable file of the same name as the directory
will be created. Execute to see your very first Qt program work.
In the program above, the qapplication header file has the definition of
QApplication class, which is the single most important class in any Qt
application. All Qt applications are instances of this class. The main function
parameters (argc & agrv) are passed to the constructors when creating an
object of this class. QPushButton is a simple push button, which is instantiated
as hello in this example. Two arguments are passed, first the label or the text
to be written on the button and the other a number identifying the parent window
(0 in this case). hello.resize(100,30) is self explanatory. QApplication object
allows us to set a main widget. If the main widget is killed somehow, the
application dies. This is done through a.setMainWiget(&hello).
hello.show() is akin to the VB's visible property. It does nothing but make
the component visible. exec() executes in a loop and passes all events to the
respective components of the GUI. This executes until the application closes or
is explicitly killed.
|
Next step
Now that we have got our feet wet, its time to create a more complex GUI,
which is a very basic frontend for mpg123. We have given the associated source
code for this on our CD in the source code section. In this article, we'll
explain the main elements of the code.
For building the GUI we will use Qt designer for designing the frontend. Fire
up the designer from the command line by giving the designer command or use the
link in the Start Menu. Go to File menu and choose new, which will open a dialog
box asking for file type to be created. Choose dialog and press OK. You will now
see a VB style form on which you can add various components (widgets), just as
you do in VB. For the present context we will restrict ourselves to three types
of widgets: push button, pixmap and a dial. Now, create a simple form by
dragging and dropping the widgets.
This will serve as the GUI for your MP3 player. Save the form you've
created, and the Qt designer will output it as an XML based .ui (user interface)
file. We've given the .ui file for it on the CD. You can preview this
interface using the preview option from the menu. The pixmap label is used to
show the image. Once the interface is done, we have to add functionality to it.
This is where slots and signals come into play. Qt component widgets emit
signals when events occur. For example, a button will emit a 'clicked'
signal when it is clicked. The programmer can choose to connect to a signal by
creating a function (called a slot) and calling the connect () function to
relate the signal to the slot. This can also be done directly in Qt designer
(see picture on the right).
To create the slots, we use the Edit->slots option. Add five slots
fileplay(), filestop(), bye(), volume(int) and filechange() for the five basic
operations in the MP3 player, namely play, stop, quit, change volume and change
song. For connecting slots and signals, the Qt designer provides a very
intuitive method. Press F3 and select the widget emitting the signal and drag
the mouse to the empty space in the form. A dialog window will pop and associate
the required signal to one of the slots. In this fashion associate clicked
signal of each of the push buttons to the four slots (file). Associate the
valueChanged(int) signal of the dial to the volume(int) slot. The valueChanged
signal is emitted whenever the dial is moved. The label on the buttons and the
caption on the windows can be changed from the property editor accessible from
window->view->property editor. After doing all this cosmetic work it's
time to write the actual code. The user interface file is used by uic (user
interface compiler) to generate the corresponding c++ code. This is taken care
of in the makefile generated by qmake in the second step of compiling the Qt
code. So, any modifications to this c++ code will get erased, therefore, more
functionality is added by sub classing. Let's see how this is done.
We created slots for the main form, hence we would be sub classing the same.
We named the Main Form as MP3. We now create a file mp3_player.h having the
definition of the new sub class mp3_player. The c++ code for this is as follows.
#ifndef MP3_PLAYER_H
#define MP3_PLAYER_H
#include “mp3.h”
class mp3_player : public MP3
{
Q_OBJECT
public :
mp3_player( QWidget* parent = 0, const char* name = 0, bool modal = FALSE,
WFlags f = 0 ) : MP3( parent, name, modal, f ) {}
public slots :
virtual void fileplay() ;
virtual void filechange();
virtual void filestop();
virtual void volume(int a);
virtual void bye();
} ;
#endif
Q_OBJECT is used by moc, Meta Object Compiler during the compilation process.
“public slots” are now added using the virtual specifier.
Now let's create the mp3_player.cpp file, which will contain the functional
code. This will contain the code for all the slots. Here, we'll explain two of
them, namely filechange() and fileplay(). The remaining slots are similar to the
filechange() function.
void mp3_player::filechange() {
s = QFileDialog::getOpenFileName(
“/” , “Audio files (*.mp3)” ,
this ,
“open mp3 file “
“choose your mp3” );
}
In the above code, s is a QString type global variable
in which the filename is stored. This is done by calling the static method
getOpenFileName() of the QFileDialog class. The code for fileplay() will be as
follows.
void mp3_player::fileplay() {
QMessageBox::information ( this , “Now Playing “ , s , QMessageBox::Ok ) ;
QString play(“mpg123 “);
QString file=play+”'”+s+”'”+”&” ;
system(file.latin1());
}
In this the variable 's' from the filechange() function is used to create
a command line argument for mpg123 and finally mpg123 is executed using the
system() call.
The working of another slot, namely the volume(int a) is similar to the
fileplay() function, where the dial position 'a' is used to generate
arguments for aumix (audio mixer for Linux) used for controlling the volume.
After all this, we have to write the main.cpp file, similar to the hello
world code, where the main widget is an instance of the mp3_player class.
Compile the code as we explained above. There is one quirk in the program. If
the player is killed explicitly (using a kill command or from the X button), the
song doesn't stop playing. This is because the mpg123 is run as a separate
program in the background and not as a child process. We'll leave the solution
to this to you as an exercise.
Source: PCQuest