Development/Tutorials/Using Qt Designer: Difference between revisions

    From KDE TechBase
    (Posting tutorial on using UI files)
     
    No edit summary
    (45 intermediate revisions by 13 users not shown)
    Line 1: Line 1:
    == Qt Designer User Interfaces in KDE ==
    == Qt Designer User Interfaces in KDE ==


    Line 4: Line 6:
    (UIs) created with Qt Designer, into your KDE project.   
    (UIs) created with Qt Designer, into your KDE project.   


    === Designing the UI ===
    == Designing the UI ==
     
    Qt Designer is a graphical program which allows you to easily build user interfaces, using a ''drag n drop'' interface. Here is a short example how it can go, for more information read the [http://qt.nokia.com/doc/designer-manual.html user documentation].
     
    ;Step 0:
    Call Qt Designer
    <syntaxhighlight lang="bash">
    designer
    </syntaxhighlight>
    ;Note:
    You can also use Qt Designer from within the [http://en.wikipedia.org/wiki/Qt_Creator QtCreator] [http://en.wikipedia.org/wiki/Integrated_development_environment IDE] [[Development/Tutorials/Using_Qt_Creator|(here is how)]].
    ;Step 1:
    Add the widgets you want by drag-and-drop
     
    [[File:Designer-step1.png|200px]]
    ;Step 2:
    Select the mainwindow. This is the one un-intuitive step. To lay out the objects in the mainwindow, you do not select the objects in the mainwindow, but the mainwindow itself.
     
    [[File:Designer-step2.png|200px]]
    ;Step 3:
    Select Form -> Lay Out in a <u>G</u>rid
     
    [[File:Designer-step3.png|200px]]
    ;Result:
    You get a decent look, and if you resize the window, the widgets resize as well.


    [http://www.trolltech.com/products/qt/features/designer Qt Designer] is a
    [[File:Designer-result.png|200px]]
    graphical program which allows you to easily build user interfaces, using an
    intuitive "drag n drop" interface.  Designer has its own excellent
    [http://doc.trolltech.com/4.2/designer-manual.html user documentation]
    It might make sense to provide a brief example of using Designer here, but
    for now I will leave most of that to the Designer manual itself.


    === Adding the UI File to Your KDE Project ===
    === Adding a toolbar ===
    To add a toolbar, right-click on the UI and choose "Add Toolbar". Then you can set icons and text in your mainwindow's constructor with code like this:
    <syntaxhighlight lang="cpp-qt">
    ui->toolBar->addAction(QIcon("/usr/share/icons/oxygen/22x22/apps/ktip.png"),"hello world");
    </syntaxhighlight>
     
    == 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 23: Line 50:
    project, simply add a command like the following to your CMakeLists.txt file:
    project, simply add a command like the following to your CMakeLists.txt file:


    <code>
    <syntaxhighlight lang="cmake">
    kde4_add_ui_files(myapp_SRCS myialog.ui)
    kde4_add_ui_files(myapp_SRCS mydialog.ui)
    </code>
    </syntaxhighlight>


    Replace "<tt>myapp_SRCS</tt>" with the name of the main block in  
    Replace "<tt>myapp_SRCS</tt>" with the name of the main block in  
    Line 35: Line 62:
    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 83:
    same class.
    same class.


    Now, on to actually using the generated UI in your code. There are a few ways
    Now, on to actually using the generated UI in your code. The Qt documentation
    to do this; for now I will only discuss one method, in which we create a class
    shows three ways of [http://qt.nokia.com/doc/latest/designer-using-a-ui-file.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 member variable of type Ui::MyDialog. The header file of
    "<tt>mydialog.h</tt>" looks like the following:


    <code cppqt>
    <syntaxhighlight lang="cpp-qt">
    #ifndef MYDIALOG_H
    #ifndef MYDIALOG_H
    #define MYDIALOG_H
    #define MYDIALOG_H


    #include <kdialog.h>
    #include <KDialog>
     
    // include the automatically generated header file for the ui-file
    #include "ui_mydialog.h"
    #include "ui_mydialog.h"
    class MyDialogUI : public QFrame, public Ui::MyDialog
    {
        Q_OBJECT
        public:
            MyDialogUI( QWidget *parent=0 );
    };


    class MyDialog : public KDialog
    class MyDialog : public KDialog
    Line 87: Line 110:


         private:
         private:
             MyDialogUI *ui;
             // accessor 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;
    };
    };


    #endif
    #endif
    </code>
    </syntaxhighlight>


    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 {{kde: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>
    <syntaxhighlight lang="cpp-qt">
    #include <klocale.h>
    #include <KLocale>
    #include <kmessagebox.h>
    #include <KMessageBox>


    // include the header file of the dialog
    #include "mydialog.h"
    #include "mydialog.h"
    MyDialogUI::MyDialogUI( QWidget *parent )
    : QFrame( parent )
    {
        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.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 );


         //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 to your UI widgets.
         // Note that you have to prepend "ui." when referring
         connect( ui->MyButton, SIGNAL( clicked() ), this, SLOT( slotButtonClicked() ) );
        // to your UI elements.
         connect( ui.myButton, SIGNAL( clicked() ),
                this, SLOT( slotButtonClicked() ) );
    }
    }


    MyDialog::~MyDialog()
    MyDialog::~MyDialog()
    {
    {
        delete ui;
    }
    }


    void MyDialog::slotButtonClicked()  
    void MyDialog::slotButtonClicked()  
    {
    {
         KMessageBox::information( this, i18n("You pressed the button!" ), i18n( "Hooray!" ) );
         KMessageBox::information( this,  
                                  i18n("You pressed the button!" ),
                                  i18n( "Hooray!" ) );
    }
    }


    #include "mydialog.moc"
    #include "mydialog.moc"
    </code>
    </syntaxhighlight>
     
    So, basically, we create a new Ui::MyDialog and then call
    <tt>ui.setupUi(widget)</tt> in the constructor of <tt>MyDialog</tt>. 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 "<tt>ui.</tt>" to their names, just like it is often done
    with the prefix "<tt>m_</tt>".
     
    == 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 uic, Qt's user interface compiler
    * '''mydialog.h/cpp''': the dialog implementation
    The steps in short are
    # create <tt>mydialog.ui</tt>
    # create <tt>mydialog.h/cpp</tt>
    # add variable Ui::MyDialog ui; in <tt>mydialog.h</tt>
    # call <tt>ui.setupUi(widget);</tt>
    # access the ui elements with <tt>ui.</tt>
     
    == Qt Documentation ==


    So, basically, we call <tt>setupUi(this)</tt> in the <tt>MyDialogUI</tt>
    The Qt documentation contains a good article about
    constructor, which places your UI elements into that widget. Then, in the
    [http://qt.nokia.com/doc/latest/designer-using-a-ui-file.html Using a Designer .ui File in Your Application].
    <tt>MyDialog</tt> constructor, we create the <tt>MyDialogUI</tt>
    [[Category:C++]]
    instance named <tt>ui</tt> and set it to be our dialog's main widget.
    [[Category:KDE4]]
    We can then interact with all of the UI elements by prepending
    "<tt>ui-></tt>" to their names.

    Revision as of 12:33, 13 July 2012


    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 a drag n drop interface. Here is a short example how it can go, for more information read the user documentation.

    Step 0

    Call Qt Designer

    designer
    
    Note

    You can also use Qt Designer from within the QtCreator IDE (here is how).

    Step 1

    Add the widgets you want by drag-and-drop

    Step 2

    Select the mainwindow. This is the one un-intuitive step. To lay out the objects in the mainwindow, you do not select the objects in the mainwindow, but the mainwindow itself.

    Step 3

    Select Form -> Lay Out in a Grid

    Result

    You get a decent look, and if you resize the window, the widgets resize as well.

    Adding a toolbar

    To add a toolbar, right-click on the UI and choose "Add Toolbar". Then you can set icons and text in your mainwindow's constructor with code like this:

    ui->toolBar->addAction(QIcon("/usr/share/icons/oxygen/22x22/apps/ktip.png"),"hello world");
    

    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 member variable of type Ui::MyDialog. The header file of "mydialog.h" looks like the following:

    #ifndef MYDIALOG_H
    #define MYDIALOG_H
    
    #include <KDialog>
    
    // include the automatically generated header file for the ui-file
    #include "ui_mydialog.h"
    
    class MyDialog : public KDialog
    {
        Q_OBJECT
        public:
            MyDialog( QWidget *parent=0 );
            ~MyDialog();
    
        private slots:
            void slotButtonClicked();
    
        private:
            // accessor 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;
    };
    
    #endif
    

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

    #include <KLocale>
    #include <KMessageBox>
    
    // include the header file of the dialog
    #include "mydialog.h"
    
    MyDialog::MyDialog( QWidget *parent )
    : KDialog( parent )
    {
        QWidget *widget = new QWidget( this );
    
        // create the user interface, the parent widget is "widget"
        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()
    {
    }
    
    void MyDialog::slotButtonClicked() 
    {
        KMessageBox::information( this, 
                                  i18n("You pressed the button!" ),
                                  i18n( "Hooray!" ) );
    }
    
    #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 uic, Qt's user interface compiler
    • mydialog.h/cpp: the dialog implementation

    The steps in short are

    1. create mydialog.ui
    2. create mydialog.h/cpp
    3. add variable Ui::MyDialog ui; in mydialog.h
    4. call ui.setupUi(widget);
    5. access the ui elements with ui.

    Qt Documentation

    The Qt documentation contains a good article about Using a Designer .ui File in Your Application.