About Us

About Us
Lorem Ipsum is simply dummy text of the printing and typesetting industry.

Contact Info

684 West College St. Sun City, United States America, 064781.

(+55) 654 - 545 - 1235

info@corpkit.com

Qt Widgets vs. Qt Quick: Deciding the Best Approach for Your Project

Qt, a versatile framework for cross-platform application development, offers developers two primary approaches for creating user interfaces: Qt Widgets and Qt Quick. In this article, we’ll explore the differences between these two approaches and help you choose the right one for your project.

Qt Widgets are traditional, C++ based components used for creating desktop-style user interfaces. They offer a familiar development workflow for desktop developers and come with an extensive set of pre-built components. Qt Widgets excel in applications requiring complex custom widgets or those targeting traditional desktop platforms.

Simple Button in Qt Widgets example:

#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget app_window;
    app_window.resize(400, 200);

    QPushButton *button = new QPushButton("Click me!");
    QVBoxLayout *layout = new QVBoxLayout();

    layout->addWidget(button);
    app_window.setLayout(layout);
    layout->setAlignment(button, Qt::AlignCenter);

    app_window.show();
    return app.exec();
}

In contrast, Qt Quick is a declarative language designed for building modern, fluid user interfaces. With Qt Quick, developers can create visually appealing UIs with animations and effects using a more intuitive, markup-based approach. Qt Quick is ideal for applications targeting touch-based interfaces, mobile platforms, or those requiring dynamic and interactive UIs. It’s also well-suited for embedded systems and applications that need to have either custom or consistent look and feel across different platforms and devices.

Simple Button in Qt Quick example:

import QtQuick
import QtQuick.Controls

ApplicationWindow {
    width: 400
    height: 200
    visible: true
    title: "QtQuick"

    Button {
        anchors.centerIn: parent
        text: "Click me!"
    }
}

When choosing between Qt Widgets and Qt Quick, developers must consider factors such as development workflow, performance, flexibility, and platform support. Qt Widgets offer a familiar development experience and strong performance on desktop platforms, while Qt Quick provides greater flexibility and is better suited for modern UI design and mobile applications. In more detail:

In a nutshell, Qt Widgets offer exceptional flexibility for component creation. Below, we showcase a collection of star-shaped buttons crafted using Qt Widgets, leveraging the QPolygon type.

//starbutton.h

#ifndef STARBUTTON_H
#define STARBUTTON_H

#include <QPushButton>
#include <QPainter>
#include <QPolygon>
#include <QBrush>
#include <QPen>
#include <QColor>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QMouseEvent>
#include <QRegion>
#include <cmath>

class StarButton : public QPushButton {
    Q_OBJECT

public:
    explicit StarButton(QWidget* parent = nullptr, QColor setColor = Qt::yellow);

protected:
    void paintEvent(QPaintEvent* event) override;
    void resizeEvent(QResizeEvent* event) override;
    void mousePressEvent(QMouseEvent* event) override;

private:
    QColor color;
    QColor initialColor;
    QColor penColor;
    bool status = true;
    QPolygon calculateStarPoints();
    void updateMask();
};

#endif // STARBUTTON_H
//starbutton.cpp

#include "starbutton.h"

StarButton::StarButton(QWidget* parent, QColor setColor)
    : QPushButton(parent),
    color(setColor),
    penColor(Qt::black)
{
    setMinimumSize(50, 50);
    setFocusPolicy(Qt::NoFocus);
    initialColor = setColor;
    updateMask();
}

void StarButton::paintEvent(QPaintEvent* event) {
    QPushButton::paintEvent(event);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setBrush(QBrush(color));
    painter.setPen(QPen(penColor, 2));

    QPolygon starPolygon = calculateStarPoints();

    painter.drawPolygon(starPolygon);
    painter.setPen(QPen(Qt::black));
    painter.drawText(event->rect(), Qt::AlignCenter, text());
}

void StarButton::resizeEvent(QResizeEvent* event) {
    QPushButton::resizeEvent(event);
    updateMask();
}

QPolygon StarButton::calculateStarPoints() {
    int centerX = width() / 2;
    int centerY = height() / 2;
    int outerRadius = std::min(width(), height()) / 2;
    int innerRadius = outerRadius / 2;

    QPolygon starPolygon;
    int numPoints = 10;
    for (int i = 0; i < numPoints; i++) {
        double angle = (i * M_PI) / 5 - M_PI / 2;
        int radius = (i % 2 == 0) ? outerRadius : innerRadius;
        int x = centerX + radius * cos(angle);
        int y = centerY + radius * sin(angle);
        starPolygon << QPoint(x, y);
    }
    return starPolygon;
}

void StarButton::updateMask() {
    QPolygon starPolygon = calculateStarPoints();
    setMask(QRegion(starPolygon));
}

void StarButton::mousePressEvent(QMouseEvent* event) {
    QPushButton::mousePressEvent(event);
    color = status? Qt::blue : initialColor;
    status = !status;
    update();
}

In Qt Quick, achieving similar functionality can be approached through various methods. One simple and straightforward option is to utilize a Button component, as demonstrated earlier, and modify its background to display a star-shaped image. However, it’s important to note that if you choose this option, applying effects like a drop shadow to the star won’t be possible directly. In such cases, you’ll need to export the image with the drop shadow already applied and display it accordingly. Alternatively, one can employ Canvas, Shape, or custom component creation using OpenGL.

In this demonstration, we’ll explore the Canvas approach with a drop shadow, mirroring the Qt Widgets implementation showcased earlier, albeit without utilizing a Polygon, which is not available in QML.

import QtQuick
import QtQuick.Controls
import Qt5Compat.GraphicalEffects

Item {
    id: root
    width: 200
    height: 200

    property string text
    signal clicked()

    Canvas {
        id: canvas
        anchors.fill: parent

        property bool clicked: false
        onClickedChanged: {
            canvas.requestPaint();
        }

        onPaint: {
            var ctx = getContext("2d");
            ctx.clearRect(0, 0, width, height);

            var size = Math.min(width, height);
            var centerX = width / 2;
            var centerY = height / 2;
            var outerRadius = size / 2;
            var innerRadius = outerRadius / 2;

            ctx.beginPath();
            ctx.moveTo(centerX, centerY - outerRadius);
            for (var i = 0; i <= 10; i++) {
                var angle = (i * Math.PI / 5) - (Math.PI / 2);
                var radius = (i % 2 == 0) ? outerRadius : innerRadius;
                ctx.lineTo(centerX + Math.cos(angle) * radius, centerY + Math.sin(angle) * radius);
                ctx.lineTo(centerX + Math.cos(angle) * radius, centerY + Math.sin(angle) * radius);
            }
            ctx.closePath();

            if (canvas.clicked) {
                ctx.fillStyle = "blue";
            } else {
                ctx.fillStyle = "chartreuse";
            }

            ctx.fill();
        }
    }

    DropShadow {
        anchors.fill: canvas
        source: canvas
        radius: 10
        samples: 16
        color: "#000"
        horizontalOffset: 5
        verticalOffset: 5
    }

    Text {
        anchors.centerIn: parent
        text: root.text
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            canvas.clicked = !canvas.clicked;
            root.clicked();
        }
    }
}
import QtQuick
import QtQuick.Controls

//custom QML module
import controls

ApplicationWindow {
    id: root
    width: 1080
    height: 600
    visible: true
    color: "white"
    title: "QtQuick"

    Grid {
        columns: 5
        rowSpacing: 10
        columnSpacing: 10
        anchors.centerIn: parent
        Repeater {
            model: 10
            delegate: StarButton {
                text: "Star\nButton " + (index+1)
                onClicked: {
                    console.log("Star button clicked!");
                }
            }
        }
    }
}

The primary distinctions here lie in code complexity versus flexibility. In Qt Quick, achieving the same component requires only 2 QML files and approximately 110 lines of code, while Qt Widgets demands 5 files and 197 lines of code. Qt Widgets offers a broader range of component options, whereas QML provides a more fluid and simplified development experience.

Regarding performance, it varies depending on the application’s content and context. Qt Quick’s integration with JavaScript and extensive animation capabilities necessitates constant performance monitoring and optimization. Fortunately, tools like the QML profiler are invaluable for such optimizations. You may refer to our older article ‘Mastering the QML Profiler – QtQuick Profiling for All‘ for more insights.

For developers considering transitioning from Qt Widgets to Qt Quick, careful planning is essential. Strategies may include leveraging Qt’s compatibility layers, gradually refactoring existing code, and utilizing Qt’s tooling support for both Qt Widgets and Qt Quick.

Both Qt Widgets and Qt Quick are powerful tools for creating user interfaces in Qt, each with its own strengths and use cases. By understanding the differences between these two approaches and considering the specific requirements of your project, you can choose the right approach to create compelling and effective user interfaces.

Whether you lean towards Qt Widgets or Qt Quick, or find it hard to choose between the two, our team of experts at Extenly is here to help you navigate your UI development journey. Drop us a line, and let’s schedule a call to discuss your project needs!

Comments (2)

  • Reply Mike Trahearn - May 28, 2024

    You may also use the Qt Shapes Module for hardware accelerated drawing of any arbitrary shape, including polygons in Qt Quick, or use QQuickPaintedItem for a CPU based (pixmap cached) approach.

    • Reply Mike Trahearn - December 5, 2024

      And now even using VectorImage – check it out!

Leave a Reply

Your email address will not be published. Required fields are marked*

error: Content is protected !!