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);