Get Involved/development/Tutorials/Using Qt Designer: Difference between revisions

From KDE Community Wiki
(link the Qt documentation: how to use ui files)
(reframe the article and use the direct approach instead of the single inheritance approach)
Line 4: Line 4:
(UIs) created with Qt Designer, into your KDE project.   
(UIs) created with Qt Designer, into your KDE project.   


=== Designing the UI ===
== Designing the UI ==


[http://www.trolltech.com/products/qt/features/designer Qt Designer] is a  
[http://www.trolltech.com/products/qt/features/designer Qt Designer] is a  
Line 13: Line 13:
for now this article will leave most of that to the Designer manual itself.
for now this article will leave most of that to the Designer manual itself.


=== Adding the UI File to Your KDE Project ===
== Adding the UI File to Your KDE Project ==


For our purposes, the most important part of using Designer is the  
For our purposes, the most important part of using Designer is the  
Line 35: Line 35:
defines the UI.  The generated file will be named <tt>ui_mydialog.h</tt>.
defines the UI.  The generated file will be named <tt>ui_mydialog.h</tt>.


=== Using the UI in Your Code ===
== Using the UI in Your Code ==


The <tt>ui_mydialog.h</tt> file defines a class named  
The <tt>ui_mydialog.h</tt> file defines a class named  
"<tt>Ui_MyDialog</tt>", that contains all of the widgets you created in  
"<tt>Ui_MyDialog</tt>", that contains all of the widgets you created in  
Designer as public members of the class.  It also contains the public function
Designer as public members of the class.  It also contains the public function
"<tt>setupUi(QWidget*)</tt>", which instantiates all of the widgets,  
"<tt>setupUi(QWidget *parent)</tt>", which instantiates all of the widgets,  
sets up their properties, and inserts them into layout managers, all according  
sets up their properties, and inserts them into layout managers, all according  
to what you specified in Designer.
to what you specified in Designer.
Line 56: Line 56:
same class.
same class.


Now, on to actually using the generated UI in your code. There are [http://doc.trolltech.com/latest/designer-using-a-component.html a few ways]  
Now, on to actually using the generated UI in your code. The Qt documentation
to do this; here only one method is discussed, in which we create a class
shows three ways of [http://doc.trolltech.com/latest/designer-using-a-component.html how to use ui-files];
that inherits from both <tt>Ui::MyDialog</tt> and a Qt container class
here only the ''direct approach'' is discussed. The goal is to create a KDialog
like {{qt|QFrame}}. Create a class definition file named
which embeds the UI from the ui-file. First, we have to subclass MyDialog from
"<tt>mydialog.h</tt>", and add the following:
KDialog and add a pointer to Ui::MyDialog. The header file of
"<tt>mydialog.h</tt>" looks like the following:


<code cppqt>
<code cppqt>
Line 67: Line 68:


#include <KDialog>
#include <KDialog>
#include "ui_mydialog.h"


class MyDialogUI : public QFrame, public Ui::MyDialog
namespace Ui {
{
    // forward declaration of Ui::MyDialog. This way we work
     Q_OBJECT
     // around the #include "ui_mydialog.h"
     public:
     class MyDialog;
        MyDialogUI( QWidget *parent=0 );
}
};


class MyDialog : public KDialog
class MyDialog : public KDialog
Line 87: Line 86:


     private:
     private:
         MyDialogUI *ui;
         // pointer to the ui. we can access all gui elements
        // specified in Designer. If mydialog.ui contains a
        // button "myButton", we will be able to access it
        // with ui->myButton in the cpp file.
        Ui::MyDialog *ui;
};
};


Line 93: Line 96:
</code>
</code>


So we have defined two classes.  <tt>MyDialogUI</tt> is simply a
Now we are going to look at the implementation of MyDialog, which is in the file
{{qt|QFrame}} with your UI elements placed inside it. 
"<tt>mydialog.cpp</tt>".
<tt>MyDialog</tt> is a {{class|KDialog}} window, whose main
widget will be the <tt>MyDialogUI</tt> instance named
<tt>ui</tt> above.  Here is the "<tt>mydialog.cpp</tt>"  
C++ definition file:


<code cppqt>
<code cppqt>
Line 104: Line 103:
#include <KMessageBox>
#include <KMessageBox>


// include the header file of the dialog
#include "mydialog.h"
#include "mydialog.h"


MyDialogUI::MyDialogUI( QWidget *parent )
// include the automatically generated header file for the ui-file
: QFrame( parent )
#include "ui_mydialog.h"
{
    setupUi( this );
}


MyDialog::MyDialog( QWidget *parent )
MyDialog::MyDialog( QWidget *parent )
: KDialog( parent )
: KDialog( parent )
{
{
     ui = new MyDialogUI( this );
    QWidget *widget = new QWidget( this );
     setMainWidget( ui );
 
    // create the user interface, the parent widget is "widget"
     ui = new Ui::MyDialog();
    ui->setupUi(widget); // this is the important part
 
    // set the widget with all its gui elements as the dialog's
    // main widget
     setMainWidget( widget );
 
    // other KDialog options
     setCaption( i18n("This is my Dialog window!") );
     setCaption( i18n("This is my Dialog window!") );
     setButtons( KDialog::Close );
     setButtons( KDialog::Close );
Line 122: Line 128:
     // Example Signal/Slot connection using widgets in your UI.
     // Example Signal/Slot connection using widgets in your UI.
     // Note that you have to prepend "ui->" when referring
     // Note that you have to prepend "ui->" when referring
     // to your UI widgets.
     // to your UI elements.
     connect( ui->MyButton, SIGNAL( clicked() ),
     connect( ui->myButton, SIGNAL( clicked() ),
             this, SLOT( slotButtonClicked() ) );
             this, SLOT( slotButtonClicked() ) );
}
}
Line 129: Line 135:
MyDialog::~MyDialog()
MyDialog::~MyDialog()
{
{
     delete ui;
     // no need to delete the user interface.
    // QObject derived classes automatically delete their children.
}
}


Line 142: Line 149:
</code>
</code>


So, basically, we call <tt>setupUi(this)</tt> in the <tt>MyDialogUI</tt>  
So, basically, we create a new Ui::MyDialog and then call
constructor, which places your UI elements into that widget. Then, in the  
<tt>ui->setupUi(widget)</tt> in the constructor of <tt>MyDialog</tt>. This
<tt>MyDialog</tt> constructor, we create the <tt>MyDialogUI</tt>
places the UI elements into the given widget. Then we set the parent-widget
instance named <tt>ui</tt> and set it to be our dialog's main widget.
as the KDialog's main widget. We can then interact with all of the UI elements
We can then interact with all of the UI elements by prepending  
by prepending "<tt>ui-></tt>" to their names, just like it is often done
"<tt>ui-></tt>" to their names.
with the prefix "<tt>m_</tt>".


=== Troubleshooting ===
== Final Thoughts ==
If you get errors similar to
<code>
mydialog.h:9: error: expected class-name before ‘{’ token
</code>


recheck the names of the dialog in the mydialog.ui file (should be "MyDialog"), the pushButton ("MyButton") and any other objects you've designed.
The cascade of files and classes in this tutorial may seem daunting at
first, but the naming scheme layed out here has one nice intuitive
feature: the source code files that you will be editing directly (either as
text or with Designer) are all named with the same scheme:
* '''mydialog.ui''': the user interface, created with Designer
* '''ui_mydialog.h''': auto-generated by moc, Qt's meta object compiler
* '''mydialog.h/cpp''': the dialog implementation
The steps in short are
# create <tt>mydialog.ui</tt>
# create <tt>mydialog.h/cpp</tt>
# add forward declaration and member variable Ui::MyDialog *ui; in <tt>mydialog.h</tt>
# call <tt>ui = new Ui::MyDialog(); ui->setupUi(widget);</tt>
# use the ui with <tt>ui-></tt>


=== Final Thoughts ===
== Qt Documentation ==


The cascade of files and classes in this tutorial may seem daunting at
The Qt documentation contains a good article about
first, but the naming scheme layed out here has one nice intuitive
[http://doc.trolltech.com/latest/designer-using-a-component.html Using a Component in Your Application].
feature: the three source code files that you will be editing
directly (either as text or with Designer) are all named with the same
simple filename stem: <tt>mydialog.ui</tt>, <tt>mydialog.h</tt>, and
<tt>mydialog.cpp</tt>. Just remember that you'll be using the
<tt>MyDialog</tt> class almost exclusively.  Setting up the
<tt>MyDialogUI</tt> class is easy (it only contains a one-line
constructor), and once it's set up you can pretty well ignore it.
[[Category:C++]]
[[Category:C++]]
[[Category:KDE4]]
[[Category:KDE4]]

Revision as of 20:43, 21 November 2007

Qt Designer User Interfaces in KDE

In this tutorial, we will explore how to programatically insert user interfaces (UIs) created with Qt Designer, into your KDE project.

Designing the UI

Qt Designer is a graphical program which allows you to easily build user interfaces, using an intuitive "drag n drop" interface. Designer has its own excellent user documentation. It might make sense to provide a brief example of using Designer here, but for now this article will leave most of that to the Designer manual itself.

Adding the UI File to Your KDE Project

For our purposes, the most important part of using Designer is the *.ui file that it creates. This is simply an XML file that encodes the user interface in a machine-readable (and human-readable!) way.

Let's imagine that you've created a UI named "MyDialog" with Designer, and saved it as the file mydialog.ui. To add this UI to your KDE project, simply add a command like the following to your CMakeLists.txt file:

kde4_add_ui_files(myapp_SRCS mydialog.ui)

Replace "myapp_SRCS" with the name of the main block in your CMakeLists.txt file, defining all of the source code files. It is usually the name of your application, with "_SRCS" appended.

When you do this, the build system will run the Qt program uic on mydialog.ui, to auto-generate a C++ header file that defines the UI. The generated file will be named ui_mydialog.h.

Using the UI in Your Code

The ui_mydialog.h file defines a class named "Ui_MyDialog", that contains all of the widgets you created in Designer as public members of the class. It also contains the public function "setupUi(QWidget *parent)", which instantiates all of the widgets, sets up their properties, and inserts them into layout managers, all according to what you specified in Designer.

Note that setupUi() takes a QWidget* argument. This argument represents the parent container widget, into which all of the widgets in your UI will be inserted. In other words, Ui_MyDialog is not itself derived from QWidget, and it does not contain a toplevel widget itself. You have to supply the toplevel widget when you call setupUi(). This is an important point.

One more important semantic detail: the Ui_MyDialog class also creates a Ui namespace, which simply creates an alias for the class. So you can use Ui::MyDialog to refer to the same class.

Now, on to actually using the generated UI in your code. The Qt documentation shows three ways of how to use ui-files; here only the direct approach is discussed. The goal is to create a KDialog which embeds the UI from the ui-file. First, we have to subclass MyDialog from KDialog and add a pointer to Ui::MyDialog. The header file of "mydialog.h" looks like the following:

  1. ifndef MYDIALOG_H
  2. define MYDIALOG_H
  1. include <KDialog>

namespace Ui {

   // forward declaration of Ui::MyDialog. This way we work
   // around the #include "ui_mydialog.h"
   class MyDialog;

}

class MyDialog : public KDialog {

   Q_OBJECT
   public:
       MyDialog( QWidget *parent=0 );
       ~MyDialog();
   private slots:
       void slotButtonClicked();
   private:
       // pointer to the ui. we can access all gui elements
       // specified in Designer. If mydialog.ui contains a
       // button "myButton", we will be able to access it
       // with ui->myButton in the cpp file.
       Ui::MyDialog *ui;

};

  1. endif

Now we are going to look at the implementation of MyDialog, which is in the file "mydialog.cpp".

  1. include <KLocale>
  2. include <KMessageBox>

// include the header file of the dialog

  1. include "mydialog.h"

// include the automatically generated header file for the ui-file

  1. include "ui_mydialog.h"

MyDialog::MyDialog( QWidget *parent )

KDialog( parent )

{

   QWidget *widget = new QWidget( this );
   // create the user interface, the parent widget is "widget"
   ui = new Ui::MyDialog();
   ui->setupUi(widget); // this is the important part
   // set the widget with all its gui elements as the dialog's
   // main widget
   setMainWidget( widget );
   // other KDialog options
   setCaption( i18n("This is my Dialog window!") );
   setButtons( KDialog::Close );
   // Example Signal/Slot connection using widgets in your UI.
   // Note that you have to prepend "ui->" when referring
   // to your UI elements.
   connect( ui->myButton, SIGNAL( clicked() ),
            this, SLOT( slotButtonClicked() ) );

}

MyDialog::~MyDialog() {

   // no need to delete the user interface.
   // QObject derived classes automatically delete their children.

}

void MyDialog::slotButtonClicked() {

   KMessageBox::information( this, 
                             i18n("You pressed the button!" ),
                             i18n( "Hooray!" ) );

}

  1. include "mydialog.moc"

So, basically, we create a new Ui::MyDialog and then call ui->setupUi(widget) in the constructor of MyDialog. This places the UI elements into the given widget. Then we set the parent-widget as the KDialog's main widget. We can then interact with all of the UI elements by prepending "ui->" to their names, just like it is often done with the prefix "m_".

Final Thoughts

The cascade of files and classes in this tutorial may seem daunting at first, but the naming scheme layed out here has one nice intuitive feature: the source code files that you will be editing directly (either as text or with Designer) are all named with the same scheme:

  • mydialog.ui: the user interface, created with Designer
  • ui_mydialog.h: auto-generated by moc, Qt's meta object compiler
  • mydialog.h/cpp: the dialog implementation

The steps in short are

  1. create mydialog.ui
  2. create mydialog.h/cpp
  3. add forward declaration and member variable Ui::MyDialog *ui; in mydialog.h
  4. call ui = new Ui::MyDialog(); ui->setupUi(widget);
  5. use the ui with ui->

Qt Documentation

The Qt documentation contains a good article about Using a Component in Your Application.