Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering Qt  5

You're reading from   Mastering Qt 5 Create stunning cross-platform applications using C++ with Qt Widgets and QML with Qt Quick

Arrow left icon
Product type Paperback
Published in Aug 2018
Publisher Packt
ISBN-13 9781788995399
Length 534 pages
Edition 2nd Edition
Languages
Tools
Arrow right icon
Authors (2):
Arrow left icon
Robin Penea Robin Penea
Author Profile Icon Robin Penea
Robin Penea
Guillaume Lazar Guillaume Lazar
Author Profile Icon Guillaume Lazar
Guillaume Lazar
Arrow right icon
View More author details
Toc

Table of Contents (16) Chapters Close

Preface 1. Get Your Qt Feet Wet FREE CHAPTER 2. Discovering qmake Secrets 3. Dividing Your Project and Ruling Your Code 4. Conquering the Desktop UI 5. Dominating the Mobile UI 6. Even Qt Deserves a Slice of Raspberry Pi 7. Third-Party Libraries without a Headache 8. Animations - Its Alive, Alive! 9. Keeping Your Sanity with Multithreading 10. Need IPC? Get Your Minions to Work 11. Having Fun with Multimedia and Serialization 12. You Shall (Not) Pass with QTest 13. All Packed and Ready to Deploy 14. Qt Hat Tips and Tricks 15. Other Books You May Enjoy

Custom QWidget

We now have to create the Task class that will hold our data (task name and completed status). This class will have its form file separated from MainWindow. Qt Creator provides an automatic tool to generate a base class and the associated form.

Click on File | New File or Project | Qt | Qt Designer Form Class. There are several form templates; you will recognize Main Window, which Qt Creator created for us when we started the todo app project. Select Widget and name the class Task, then click on Next. Here is a summary of what Qt Creator will do:

  1. Create a Task.h file and a Task.cpp file
  2. Create the associated Task.ui and do the plumbing to connect to Task.h
  3. Add these three freshly-created files to todo.pro so they can be compiled

Finish and voilà, the Task class is ready to be filled. We will jump into Task.ui first. Start by dragging and dropping checkbox (objectName = checkbox) and Push Button (objectName = removeButton):

This layout looks great, let's ship it to the customers! Unless you have a pixel-perfect eye, your items are not very well aligned. You need to indicate how your widgets should be laid out and how they should react when the window geometry changes (for example, when the user resizes the window). For this, Qt has several default layout classes:

  • Vertical Layout: Widgets are vertically stacked
  • Horizontal Layout: Widgets are horizontally stacked
  • Grid Layout: Widgets are arranged in a grid that can be subdivided into smaller cells
  • Form Layout: Widgets are arranged like a web form, a label, and an input

A basic layout will try to constrain all its widgets to occupy equal surfaces. It will either change the widgets' shape or add extra margins, depending on each widget's constraints. Check Box will not be stretched but Push Button will.

In our Task object, we want this to be horizontally-stacked. In the Form Editor tab, right-click on the window and select Lay out | Lay out Horizontally. Each time you add a new widget in this layout, it will be arranged horizontally.

Now add a Push Button (objectName = editButton) just after the checkbox object.

The Form Editor window offers a realistic preview of how your UI will render. If you stretch the window now, you can observe how each widget will react to this event. When resizing horizontally, you can note that the push buttons are stretched. It looks bad. We need something to "hint" to the layout that these buttons should not be stretched. Enter the Spacer widget. Take Horizontal Spacer in the widget box and drop it after the checkbox object:

A spacer is a special widget that tries to push (horizontally or vertically) adjacent widgets to force them to take up as little space as possible. The editButton and removeButton objects will take up only the space of their text and will be pushed to the edge of the window when resized.

You can add sub layouts of any type in a form (vertical, horizontal, grid, form) and create a complex-looking application with a combination of widgets, spacers, and layouts. These tools are targeted at designing a good-looking desktop application that can react properly to different window geometries.

The Designer part is finished, so we can switch to the Task source code. Since we created a Qt Designer Form class, Task is closely linked to its UI. We will use this as a leverage to store our model in a single place. When we create a Task object, it has to have a name:

#ifndef TASK_H 
#define TASK_H 
 
#include <QWidget> 
#include <QString> 
 
namespace Ui { 
class Task; 
} 
 
class Task : public QWidget 
{ 
    Q_OBJECT 
 
public: 
    explicit Task(const QString& name, QWidget *parent = 0); 
    ~Task(); 
 
    void setName(const QString& name); 
    QString name() const; 
    bool isCompleted() const; 
     
private: 
    Ui::Task *ui; 
}; 
 
#endif // TASK_H 

The constructor specifies a name and, as you can see, there are no private fields storing any state of the object. All of this will be done in the form part. We also added some getters and setters that will interact with the form. It's better to have a model completely separated from the UI, but our example is simple enough to merge them. Moreover, the Task implementation details are hidden from the outside world and can still be refactored later on. Here is the content of the Task.cpp file:

#include "Task.h" 
#include "ui_Task.h" 
 
Task::Task(const QString& name, QWidget *parent) : 
        QWidget(parent), 
        ui(new Ui::Task) 
{ 
    ui->setupUi(this); 
    setName(name); 
} 
 
Task::~Task() 
{ 
    delete ui; 
} 
 
void Task::setName(const QString& name) 
{ 
    ui->checkbox->setText(name); 
} 
 
QString Task::name() const 
{ 
    return ui->checkbox->text(); 
} 
 
bool Task::isCompleted() const 
{ 
   return ui->checkbox->isChecked(); 
} 

The implementation is straightforward; we store the information in ui->checkbox and both the name() and the isCompleted() getters take their data from ui->checkbox.

You have been reading a chapter from
Mastering Qt 5 - Second Edition
Published in: Aug 2018
Publisher: Packt
ISBN-13: 9781788995399
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image