Qt

One framework. One codebase. Any platform.

  • QNX, Windows, Linux, MacOS
  • VxWorks, Linux Embedded, iOS, Android, tvOS
  • UWP (Windows 10, Mobile, IOT), LGwebOS, integrity

Лицензирование

  • Коммерческая лиценция: ПО под собственной лицензией, изменять Qt и не показывать изменения.
  • GPL - для проектов под лицензией GPL.
  • LGPL - для проектов под лицензией LGPL.

Средства разработки

  • Среда разработки: Qt Creator
  • Компилятор: GCC или Microsoft VC++
  • Отладчик: GDB
  • Qt Designer: WYSIWYG редактор форм.
  • Qt Linguist: локализация интерфейса.
  • Qt Assistant: справочная система.

qmake

  • Описание проекта: .pro файл.
  • Из pro происходит генерация Makefile.
  • Секции: SOURCES, HEADERS, TARGET, CONFIG, QT, FORMS и др.
  • CONFIG: общие опции конфигурации.
  • DESTDIR: директория для результата.
  • FORMS: список файлов для uic.

.pro файл

HEADERS += hello.h
SOURCES += hello.cpp
SOURCES += main.cpp
TARGET = helloworld

config секция

  • release
  • debug
  • warn_on, warn_off, exceptions, exceptions_off
  • c++11, c++14 и др.
  • console
  • и др.

Платформо зависимые определения

CONFIG += debug
HEADERS += hello.h
SOURCES += hello.cpp
SOURCES += main.cpp
win32 {
    SOURCES += hellowin.cpp
}
unix {
    SOURCES += hellounix.cpp
}

Объектная модель

  • QObject - родитель всех классов.
  • Использует объектную модель C++.
  • Сигналы и слоты для взаимодействия объектов.
  • Система для свойств.
  • Система событий (QEvent).
  • Строковая локализация.
  • Система таймеров.

Слоты и сигналы

  • Альтернатива callback функциям (GTK).
  • Сигнал отправляется, когда наступает определенное событие.
  • Слот - функция, которая вызывается при наступлении сигнала.
  • Виджеты имеют много определенных сигналов и слотов.
  • Можно определить свой сигнал и соответственно слот на него.
  • connect - связывает сигнал со слотом.
  • disconnect - отключает сигнал.

Слоты и сигналы. Пример.

#include 

class Counter : public QObject
{
    Q_OBJECT

public:
    Counter() { m_value = 0; }

    int value() const { return m_value; }

public slots:
    void setValue(int value);

signals:
    void valueChanged(int newValue);

private:
    int m_value;
};

Слоты и сигналы. Пример.

void Counter::setValue(int value)
{
    if (value != m_value) {
        m_value = value;
        emit valueChanged(value);
    }
}

Counter a, b;
QObject::connect(&a, &Counter::valueChanged,
                 &b, &Counter::setValue);

a.setValue(12);     // a.value() == 12, b.value() == 12
b.setValue(48);     // a.value() == 12, b.value() == 48

Система для свойств

  • Макрос Q_PROPERTY()
  • READ, WRITE, RESET, NOTIFY и др.
  • Классы QMetaObject, QMetaProperties.
Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)

QPushButton *button = new QPushButton;
QObject *object = button;

button->setEnabled(true);
object->setProperty("enabled", true);

button->hasFocus();

Система событий

  • Сигналы и слоты - организация взаимодействия между виджетами.
  • События - организация взаимодействия между виджетом и системой.
  • Источник события — это объект, состояние которого изменяется.
  • Объект события — это отслеживаемый параметр источника события.
  • Цель события — это объект, который должен быть уведомлен о произошедшем событии.

Система событий. Пример.

void MyCheckBox::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        // handle left mouse button here
    } else {
        // pass on other buttons to base class
        QCheckBox::mousePressEvent(event);
    }
}

Система событий. Пример.

bool MyWidget::event(QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast(event);
        if (ke->key() == Qt::Key_Tab) {
            // special tab handling here
            return true;
        }
    } else if (event->type() == MyCustomEventType) {
        MyCustomEvent *myEvent = static_cast(event);
        // custom event handling here
        return true;
    }

    return QWidget::event(event);
}

Система таймеров

  • Таймер из QObject: QObject::startTimer.
  • Вызывает реализацию метода timerEvent через количество миллисекунд
  • Пока не будет вызван метод killTimer.
  • Класс QTimer

Пример таймера из QObject

class MyObject : public QObject
{
    Q_OBJECT

public:
    MyObject(QObject *parent = nullptr);

protected:
    void timerEvent(QTimerEvent *event) override;
};

MyObject::MyObject(QObject *parent)
    : QObject(parent)
{
    startTimer(50);     // 50-millisecond timer

    // since C++14 we can use std::chrono::duration literals, e.g.:
    startTimer(100ms);
}

void MyObject::timerEvent(QTimerEvent *event)
{
    qDebug() << "Timer ID:" << event->timerId();
}

Пример QTimer

 QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Foo::updateCaption);
timer->start(1000);

Построение интерфейса

  • Qt Widgets (C++).
  • Qt Quick (QML/js).
  • WebEngine (HTML/CSS/js).
  • Qt Charts - набор компонент для построения графиков.
  • Qt Data Visualization - визуализация данных в 3D.

QML

  • Декларативный язык задания интерфейсов.
  • Qt Quick - библиотека типов QML.
  • Возможность взаимодействия с C++.
  • Визуальные объекты: прямоугольник, изображение. Трансформация.
  • Анимации (fluid UI).
  • Для логики можно использовать JavaScript.

QML. Пример.

import QtQuick 2.3

Rectangle {
    width: 200
    height: 100
    color: "red"

    Text {
        anchors.centerIn: parent
        text: "Hello, World!"
    }

    Keys.onPressed: {
        if (event.key == Qt.Key_Return) {
            color = "blue";
            event.accepted = true;
        }
    }
}

QML. Пример анимации.

Rectangle {
    color: "blue"
    width: 120
    height: 120

    // By setting this SequentialAnimation on x, it and animations 
    // within it will automatically animate
    // the x property of this element
    SequentialAnimation on x {
        id: xAnim
        // Animations on properties start running by default
        running: false
        loops: Animation.Infinite // The animation is set to loop indefinitely
        NumberAnimation { from: 0; to: 200; duration: 500; easing.type: Easing.InOutQuad }
        NumberAnimation { from: 200; to: 0; duration: 500; easing.type: Easing.InOutQuad }
        PauseAnimation { duration: 250 } // This puts a bit of time between the loop
    }

    TapHandler {
        // The animation starts running when you click within the rectangle
        onTapped: xAnim.running = true
    }
}

QML. Пример javascript.

// myscript.js
function getRandom(previousValue) {
    return Math.floor(previousValue + Math.random() * 90) % 360;
}

import QtQuick 2.12
import "myscript.js" as Logic

Item {
    width: 320
    height: 480

    Rectangle {
        color: "#272822"
        width: 320
        height: 480
    }

    TapHandler {
        // This line uses the JS function from the separate JS file
        onTapped: rectangle.rotation = Logic.getRandom(rectangle.rotation);
    }

    Rectangle {
        id: rectangle
        anchors.centerIn: parent
        width: 160
        height: 160
        color: "green"
        Behavior on rotation { RotationAnimation { direction: RotationAnimation.Clockwise } }
    }

}

Qt Widgets

  • Система построения интерфейсов.
  • #include <QtWidgets>
  • QT += widgets

Qt Widgets. Пример.

#include 

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QWidget window;
    window.resize(320, 240);
    window.setWindowTitle
          (QApplication::translate("childwidget", "Child widget"));
    window.show();

    QPushButton *button = new QPushButton(
        QApplication::translate("childwidget", "Press me"), &window);
    button->move(100, 100);
    button->show();
    return app.exec();
}

Работа с файлами и каталогами

  • QFile — предоставляет интерфейс для чтения и записи информации в файлы.
  • QDir — обеспечивает доступ к структуре каталогов и к их содержимому.
  • QFileInfo — предоставляет информацию о файле, включая его имя и расположение в файловой системе, время доступа и изменения, имя владельца файла и текущие разрешения.

Чтение файла

#include <QTextStream>
#include <QFile>
int main() {
  QTextStream out(stdout);
  // Создаём объект
  QFile file("colours.txt");
  // С помощью метода open() открываем файл в режиме чтения
  if (!file.open(QIODevice::ReadOnly)) {
    qWarning("Cannot open file for reading");
    return 1;
  }
  // Создаём входящий поток, из которого будут 
  // считываться данные, и связываем его с нашим файлом
  QTextStream in(&file);
  // Считываем файл строка за строкой
  while (!in.atEnd()) {
    QString line = in.readLine();
    out << line << endl;
  }
  // Закрываем файл 
  file.close();
}

Запись в файл

#include <QTextStream>
#include <QFile>
 
int main() {
    
  QTextStream out(stdout);
    
  // Создаём объект класса QFile и связываем его с указанным именем файла
  QString filename = "distros.txt";
  QFile file(filename);
  
  // Открываем файл в режиме "Только для записи"
  if (file.open(QIODevice::WriteOnly)) {
    QTextStream out(&file); // поток записываемых данных направляем в файл
 
    // Для записи данных в файл используем оператор <<
    out << "Xubuntu" << endl;
    out << "Arch" << endl;
    
  } else {
    qWarning("Could not open file");
  }  
  // Закрываем файл
  file.close(); 
}

Взаимодействие с сетью

  • Qt Network - модуль взаимодействия с сетью.
  • QNetworkAccessManager - класс для выполнения
    QT += network

Взаимодействие с сетью. Пример.

QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished,
        this, &MyClass::replyFinished);

manager->get(QNetworkRequest(QUrl("http://qt-project.org")));

Взаимодействие с сетью. Пример.

QNetworkRequest request;
request.setUrl(QUrl("http://qt-project.org"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");

QNetworkReply *reply = manager->get(request);
connect(reply, &QIODevice::readyRead, this, &MyClass::slotReadyRead);
connect(reply, &QNetworkReply::errorOccurred,
        this, &MyClass::slotError);
connect(reply, &QNetworkReply::sslErrors,
        this, &MyClass::slotSslErrors);