Кроссплатформенный фреймворк для разработки программного обеспечения на языке программирования C++

Содержание

Слайд 2

Проблемы, направления Промышленные/научные приложения (с/с++, аппаратура, embedded) Нативные приложения Разработка Gui

Проблемы, направления

Промышленные/научные приложения (с/с++, аппаратура, embedded)
Нативные приложения
Разработка Gui MFC и тд.
Веб

должен умереть (проблемы с безопасностью https://habrahabr.ru/post/338880/)
Кроссплатформенность
Слайд 3

Qt представляет собой полный инструментарий для программирования, который состоит из отдельных

Qt представляет собой полный инструментарий для программирования, который состоит из отдельных

модулей и предоставляет:

поддержку двух- и трехмерной графики (фактически, являясь стандартом для платформонезависимого программирования на OpenGL);
возможность интернационализации, которая позволяет значительно расширить рынок сбыта ваших программ;
использование формата XML (extensible Markup Language);
STL-совместимую библиотеку контейнеров;
поддержку стандартных протоколов ввода/вывода;
классы для работы с сетью;
поддержку программирования баз данных, включая Oracle, Microsoft SQL Server, IBM DB2, MySQL, SQLite, Sybase, PostgreSQL;
и многое другое.

Слайд 4

«привязки» графического фреймворка Qt Python — PyQt, PySide Ruby — QtRuby

«привязки» графического фреймворка Qt

Python — PyQt, PySide
Ruby — QtRuby

Java — Qt Jambi
PHP — PHP-Qt
и другие.

PHP-Qt:
$widget = new QWidget;
$widget->show();
qApp::exec();

Слайд 5

Использование Примеры продуктов Autodesk Maya, Skype Telegram Медиапроигрыватель VLC VirtualBox Google

Использование

Примеры продуктов
Autodesk Maya,
Skype
Telegram
Медиапроигрыватель VLC
VirtualBox
Google Планета Земля
Mathematica
2GIS
Viber
KDE

Корпорации:
European Space Agency
DreamWorks
Google
НP
Lucasfilm
Panasonic
Philips
Samsung
Siemens
Volvo
Walt Disney Animation

Studios
Слайд 6

Модуль QtCore контейнерные классы: QList, QVector, QMap, QVariant, QString и т.

Модуль QtCore

контейнерные классы: QList, QVector, QMap, QVariant, QString и т. д.
классы

для ввода и вывода: QiODevice, QTextStream, QFile
классы процесса QProcess и для программирования многопоточности: QThread, QWaitCondition, QMutex
классы для работы с таймером: QBasicTimer и QTimer
классы для работы с датой и временем: QDate и QTime
класс QObject, являющийся краеугольным камнем объектной модели Qt
базовый класс событий QEvent
класс для сохранения настроек приложения Qsettings
класс приложения QCoreApplication, из объекта которого, если требуется, можно запустить цикл событий
классы поддержки анимации: QAbstractAnimation, QVariantAnimation и т. д.
классы для машины состояний: QStateMachine, QState и т. д.
классы моделей интервью: QAbstractltemModel, QStringListModel, QAbstractProxyModel
модуль содержит так же механизмы поддержки файлов ресурсов

Объект класса QCoreApplication :
управление событиями между приложением и операционной системой
передачу и предоставление аргументов командной строки

Слайд 7

Модуль QtGui Предоставляет классы интеграции с оконной системой, с OpenGL и

Модуль QtGui

Предоставляет классы интеграции с оконной системой, с OpenGL и OpenGL

ES.
Содержит класс QWindow, который является элементарной областью с возможностью получения событий пользовательского ввода, изменения фокуса и размеров, а так же позволяющей производить графические операции и рисование на своей поверхности.
Класс приложения этого модуля QGuiApplication. Этот класс содержит механизм цикла событий
получения доступа к буферу обмена
инициализации необходимых настроек приложения — например, палитры для расцветки элементов управления
Слайд 8

Модуль QtWidgets класс Qwidget — это базовый класс для всех элементов

Модуль QtWidgets

класс Qwidget — это базовый класс для всех элементов управления

библиотеки Qt
классы для автоматического размещения элементов: QVBoxLayout,QHBoxLayout
классы элементов отображения: QLabel,QLCDNumber
классы кнопок: QPushButton,QCheckBox,QRadioButton
классы элементов установок: QSlider,QScrollBar
классы элементов ввода: QLineEdit,QSpinBox
классы элементов выбора: QComboBox,QTooiBox
классы меню: QMainwindow и QMenu
классы окон сообщений и диалоговых окон: QMessageBox,Qdialog
классы для рисования: QPainter,QBrush,QPen,QColor
классы для растровых изображений: Qimage,QPixmap
классы стилей отдельному элементу, так и всему приложению может быть присвоен определенный стиль, изменяющий их внешний облик;
класс приложения QApplication,который предоставляет цикл событий.
Слайд 9

Модули Qt

Модули Qt

Слайд 10

Философия объектной модели Класс QObject содержит в себе поддержку: сигналов и

Философия объектной модели

Класс QObject содержит в себе поддержку:
сигналов и слотов (signal/slot);
таймера;
механизма

объединения объектов в иерархии;
событий и механизма их фильтрации;
организации объектных иерархий;
метаобъектной информации;
приведения типов;
свойств.
Слайд 11

Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | MEMBER memberName [(READ getFunction

Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction

| WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])

Свойства

Условные обозначения:
() – обязательное поел
[] – опциональное поле
| – один из варинатов

Слайд 12

class Hero : public QObject { Q_OBJECT Q_PROPERTY(int health READ healt

class Hero : public QObject
{
Q_OBJECT
Q_PROPERTY(int health READ healt WRITE

sethealt) //alt+enter
private:
int m_health;
public:
explicit Hero(QObject *parent = nullptr);
int healt() const
{
return m_health;
}
public slots:
//особый метод для проверки
void sethealt(int health)
{
m_health = health;
}
};

Использование:
Hero hr;
hr.sethealt(100);
hr.healt();

Слайд 13

class Hero : public QObject { Q_OBJECT Q_PROPERTY(int health MEMBER m_health)

class Hero : public QObject
{
Q_OBJECT
Q_PROPERTY(int health MEMBER m_health)
public:
explicit

Hero(QObject *parent = nullptr);
private:
int m_health;
};

Использование:
Hero hr;
hr.setProperty("health",100);
hr.property("health");

Если не нужен собственные «Геттер» и «Сеттер»

Слайд 14

Механизм сигналов и слотов #include int compare_abs(const void *a, const void

Механизм сигналов и слотов

#include
int compare_abs(const void *a, const void *b)

{
int a1 = *(int*)a;
int b1 = *(int*)b;
return abs(a1) - abs(b1);
}
int main() {
int size = 10;
int m[size] = {1, -3, 5, 33, 44};
// сортировка массива m по возрастанию модулей
qsort(m, size, sizeof(int), compare_abs);
return 0;
}

Сейчас в С++ ввели Lambda

Что было до …

Слайд 15

MFC. Карты сообщений class CPhotoStylerApp : public CWinApp { public: CPhotoStylerApp();

MFC. Карты сообщений

class CPhotoStylerApp : public CWinApp {
public:
CPhotoStylerApp();
public:
virtual BOOL Initlnstance();
afx_msg void

OnAppAbout();
afx_msg void OnFileNew));
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CPhotoStylerApp, CWinApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
ON_COMMAND(ID_FILE_NEW, OnFileNew)
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
Слайд 16

Механизм сигналов и слотов Signal Signal 1 – Slot 1 Signal

Механизм сигналов и слотов

Signal

Signal 1 – Slot 1
Signal 2 –

Slot 1
Signal 3 – Slot 2
…..
Слайд 17

Преимущества каждый класс, унаследованный от QObject, может иметь любое количество сигналов

Преимущества

каждый класс, унаследованный от QObject, может иметь любое количество сигналов и

слотов;
сообщения, посылаемые посредством сигналов, могут иметь множество аргументов любого типа;
сигнал можно соединять с различным количеством слотов. Отправляемый сигнал поступит ко всем подсоединенным слотам;
слот может принимать сообщения от многих сигналов, принадлежащих разным объектам;
соединение сигналов и слотов можно производить в любой точке приложения;
сигналы и слоты являются механизмами, обеспечивающими связь между объектами.
Более того, эта связь может выполняться между объектами, которые находятся в различных потоках;
при уничтожении объекта происходит автоматическое разъединение всех сигнально слотовых связей. Это гарантирует, что сигналы не будут отправляться к несуществующим объектам.
Слайд 18

Недостатки сигналы и слоты не являются частью языка C++, поэтому требуется

Недостатки

сигналы и слоты не являются частью языка C++, поэтому требуется запуск

дополнительного препроцессора перед компиляцией программы;
отправка сигналов происходит немного медленнее, чем обычный вызов функции, который осуществляется при использовании механизма функций обратного вызова;
существует необходимость в наследовании класса QObject;
в процессе компиляции не производится никаких проверок: имеется ли сигнал или слот в соответствующих классах или нет; совместимы ли сигнал и слот друг с другом и могут ли они быть соединены вместе. Об ошибке станет известно лишь тогда, когда приложение будет запущено в отладчике или на консоли. Вся эта информация выводится на консоль, поэтому, для того чтобы увидеть ее в Windows, в проектном файле необходимо в секции CONFIG добавить опцию console (для Mac OS X и Linux никаких дополнительных изменений проектного файла не требуется)
Слайд 19

Сигналы Описание: class MySignal : public QObject { Q_OBJECT signals: void

Сигналы

Описание:
class MySignal : public QObject {
Q_OBJECT
signals:
void dolt();
};

Реализация сигнала генерируемая

MOC
void MySignal::doIt()
{
QMetaObject::activate(this, staticMetaObject, 0, 0);
}

class MySignal : public QObject {
Q_OBJECT
public:
void sendSignal()
{
if (выражение)
emit sendString("Info");
}
signals:
void sendString(const QStrings);
};

Слайд 20

Слоты class MySlot : public QObject { Q_OBJECT public: MySlot(); public

Слоты

class MySlot : public QObject {
Q_OBJECT
public:
MySlot();
public slots:
void slot()

{
qDebugO « "I'm a slot";
qDebug() « sender()->objectName( );
}
};

нельзя использовать параметры по Умолчанию — например: slotMethod(int п = 8)
определять слоты как static
слоты по умолчанию public. Если нужно ограничить их вызов как метода, то объявляем private\protected

Слайд 21

Соединение объектов Вид 1 – выявление ошибок соединения на этапе выполнения

Соединение объектов

Вид 1 – выявление ошибок соединения на этапе выполнения
Вид 2

– выявление ошибок соединения на этапе компиляции

Вид 1: QObject::connect(const QObject* sender,
const char* signal,
const QObject* receiver,
const char* slot,
Qt::ConnectionType type = Qt:Autoconnection);

Вид 2: QObject::connect(const QObject* sender,
const QMetaMethods signal,
const QObject* receiver,
const QMetaMethods slot,
Qt::ConnectionType type = Qt:Autoconnection);

Пример:
QObject::connect(pSender, SIGNAL(signalMethod( )),pReceiver, SLOT(slotMethod( )));

Пример:
QObject::connect(pSender, &SenderClass::signalMethod, pReceiver, &ReceiverClass::slotMethod);

Метод connect ( ) после вызова возвращает объект класса Connection

Слайд 22

#include #include "Counter.h" int main (int argc, char** argv) { QApplication

#include
#include "Counter.h"
int main (int argc, char** argv)
{
QApplication app(argc, argv);

QLabel lbl ("0") ;
QPushButton cmd ( "ADD" ) ;
Counter counter;
lbl.show ( ) ;
cmd.show ( ) ;
QObject: :connect (&cmd, SIGNAL (clicked()) , scounter, SLOT (slotInc()));
QObject: :connect (&counter, SIGNAL(counterChanged(int)),&lbl,SLOT(setNum(int)));
QObject: :connect (&counter, SIGNAL(goodbye()), &app, SLOT(quit()));
return app.exec ( ); // запуск бесконечного цикла обработки сообщений
}

#include
class Counter : public QObject {
Q_OBJECT
private:
int m_nValue;
public:
Counter();
public slots:
void slotlncO;
signals:
void goodbye ( );
void counterChanged(int);
};

void Counter::slotlnc()
{
emit counterChanged(++m_nValue);
if (m_nValue == 5) {
emit goodbye();
}
}

Слайд 23

Автоматическое соединение (Auto Connection) (по умолчанию) Если сигнал испускается в потоке,

Автоматическое соединение (Auto Connection) (по умолчанию) Если сигнал испускается в потоке,

с которым объект-получатель имеет родство, то поведение такое же, как и при прямом соединении. В противном случае, поведение аналогично соединению через очередь."
Прямое соединение (Direct Connection) Слот вызывается немедленно при отправке сигнала. Слот выполняется в потоке отправителя, который не обязательно является потоком-получателем. (аналогично: object ->called_SLOT() )
Соединение через очередь (Queued Connection) Слот вызывается, когда управление возвращается в цикл обработки событий в потоке получателя. Слот выполняется в потоке получателя.
Блокирующее соединение через очередь (Blocking Queued Connection) Слот вызывается так же, как и при соединении через очередь, за исключением того, что текущий поток блокируется до тех пор, пока слот не возвратит управление. Замечание: Использование этого типа подключения объектов в одном потоке приведет к взаимной блокировке.
Уникальное соединение (Unique Connection) Поведение такое же, что и при автоматическом соединении, но соединение устанавливается только если оно не дублирует уже существующее соединение. т.е., если тот же сигнал уже соединён с тем же самым слотом для той же пары объектов, то соединение не будет установлено и connect() вернет false.

QObject::connect(const QObject* sender,
const char* signal,
const QObject* receiver,
const char* slot,
Qt::ConnectionType type = Qt:Autoconnection);

Слайд 24

Разъединение объектов disconnect Уничтожение связи при уничтожении объекта (связь это тоже

Разъединение объектов

disconnect
Уничтожение связи при уничтожении объекта (связь это тоже объект принадлежащий

2м «родителям»)

Общий вид:
QObject::disconnect(sender, signal, receiver, slot);

Сокращённые варианты:
disconnect(signal, receiver, slot) // сигнал в текущем объекте, слот в другом объекте(receiver)
disconnect(receiver, slot) // сигнал и слот в текущем объекте

Слайд 25

Объектные иерархии QObject* pobj1 = new QObject; QObject* pobj2 = new

Объектные иерархии

QObject* pobj1 = new QObject;
QObject* pobj2 = new QObject (pobj1)

;
QObject* pobj4 = new QObject (pobj2) ;
QObject* pobj3 = new QObject (pobj2) ;
pobj2->setObjectName ("the first child of pobj1") ;
pobj3->setObjectName ("the first child of pobj2") ;
pobj4->setObjectName ("the second child of pobj2");

Альтернативные решения: Smart pointers (Умные указатели)

Задача: корректное уничтожение динамически создаваемых объектов без утечки памяти

При уничтожении созданного объекта (при вызове его деструктора) все присоединенные к нему объекты-потомки уничтожаются автоматически.

Слайд 26

Перемещение по иерархии объектов: children() – Список потомков parent() – 1

Перемещение по иерархии объектов:
children() – Список потомков
parent() – 1 родитель

Поиск потомка:
QList

plist = pobj1->findChild("the first child of pobj2");
Поиск потомков по шаблону:
QList plist = pobjl->findChildren(QRegExp("th*"));

Вывод иерархии:
pobj1-> dumpObjectTree();
QObject::
QObject::the first child of pobj1
QObject:: the first child of pobj2
QObject:: the second child of pobj2

Слайд 27

Метаобъектная информация (moc) Альтернатива: Метаклассы в С++17 (отказ от MOC, С++/CLI

Метаобъектная информация (moc)

Альтернатива: Метаклассы в С++17 (отказ от MOC, С++/CLI и

C++/CX)

МОС (Meta Object Compiler) генерирует код, инициализирующий мета-объект.
Мета-объект содержит:
имя класса объекта
имя класса родителя
имена всех сигналов
слотов
указатели на их функции
указатели и названия свойств

qDebug() << pobj1->metaObject () ->className() ;

Слайд 28

$class interface { constexpr { compiler.require($interface.variables().empty(), "Никаких данных-членов в интерфейсах!"); for

$class interface {
constexpr
{
compiler.require($interface.variables().empty(),
"Никаких данных-членов в интерфейсах!");

for (auto f : $interface.functions())
{
compiler.require(!f.is_copy() && !f.is_move(),
"Интерфейсы нельзя копировать или перемещать; используйте"
"virtual clone() вместо этого");
if (!f.has_access())
f.make_public(); // сделать все методы публичными!
compiler.require(f.is_public(), "interface functions must be public");
// проверить, что удалось
f.make_pure_virtual(); // сделать метод чисто виртуальным
}
}
// наш интерфейс в терминах С++ будет просто базовым классом,
// а значит ему нужен виртуальный деструктор
virtual ~interface() noexcept { }
};

Кодогеренация в С++17

Слайд 29

Зачем Qmake Сборка простенькой программы из 2х файлов: g++ -c -fno-keep-inline-dllexport

Зачем Qmake

Сборка простенькой программы из 2х файлов:
g++ -c -fno-keep-inline-dllexport -pipe

-g -std=gnu++11 -Wextra -Wall -W -fexceptions -mthreads -DUNICODE -DQT_DEPRECATED_WARNINGS -DQT_QML_DEBUG -DQT_CORE_LIB -I../Test_QT_console -I. -IC:/Qt/5.9/mingw53_32/include -IC:/Qt/5.9/mingw53_32/include/QtCore -Idebug -IC:/Qt/5.9/mingw53_32/mkspecs/win32-g++ -o debug/main.o ../Test_QT_console/main.cpp
g++ -c -fno-keep-inline-dllexport -pipe -g -std=gnu++11 -Wextra -Wall -W -fexceptions -mthreads -DUNICODE -DQT_DEPRECATED_WARNINGS -DQT_QML_DEBUG -DQT_CORE_LIB -I../Test_QT_console -I. -IC:/Qt/5.9/mingw53_32/include -IC:/Qt/5.9/mingw53_32/include/QtCore -Idebug -IC:/Qt/5.9/mingw53_32/mkspecs/win32-g++ -o debug/test_op.o ../Test_QT_console/test_op.cpp
g++ -Wl,-subsystem,console -mthreads -o debug/Test_QT_console.exe debug/main.o debug/test_op.o -LC:/Qt/5.9/mingw53_32/lib C:/Qt/5.9/mingw53_32/lib/libQt5Cored.a

Идея: автоматизируем! –> make, makefile

Слайд 30

Makefile «Универсальный» makefile в рамках конкретного окружения и НЕ сложного проекта:

Makefile

«Универсальный» makefile в рамках конкретного окружения и НЕ сложного проекта:
IDIR

=../include
CC=g++
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
LIBS=-lm
_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
hellomake: $(OBJ)
gcc -o $@ $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~

Преимущества:
Экономия времени на написание команд для сборки проекта ( 1 команда - make)
Отслеживание и перекомпиляция только изменившихся объектов
Кроссплатформенная сборка

Элементарный makefile
hellomake: hellomake.c hellofunc.c
g++ -o hellomake hellomake.c hellofunc.c -I.

Задачи:
Универсальность
Кроссплатформенность
Нужно БОЛЬШЕ (золота, рабов) АВТОМАТИЗАЦИИ

Решение:
Генерация makefile для новых проектов исходя из настроек по умолчанию для текущего окружения/ платформы
Qmake, qbs

Загляните в: build-MyFirstUnit-Desktop_Qt_5_9_0_MinGW_32bit\Makefile

Слайд 31

Qmake Этапы сборки: 1. Автоматическое создание файла настроек проекта (NameOfProject.pro) qmake

Qmake

Этапы сборки:
1. Автоматическое создание файла настроек проекта (NameOfProject.pro)
qmake -project
2. Автоматическое создание

Makefile
qmake NameOfProject.pro -о Makefile
3. Компиляция проекта/программы
make

Содержание NameOfProject.pro
QT += testlib
QT -= gui
TARGET = tst_myfirstunittest
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += tst_myfirstunittest.cpp \
myclass.cpp
HEADERS += \
myclass.h

Слайд 32

Слайд 33

Критика make Традиционная для UNIX система сборки make выдает непозволительно долгое

Критика make

Традиционная для UNIX система сборки make выдает непозволительно долгое время

сборки для больших проектов (особенно для инкрементальных сборок);
Использование рекурсивого вызова make из корневой директории приводит к нарушениям зависимостей между модулями, для устранения которого приходится запускать сборку два или три раза (и увеличение времени сборки, естественно);
Портируемость make сильно раздута, так как make работает не сам по себе, в makefile могут быть указаны десятки других утилит, которые специфичны для платформы;
Неочевидные и откровенно ущербные элементы языка (чего стоят только ifeq, ifneq, ifdef, и ifndef)
Проблемы типов (работа только со строками)
Плохое разрешение зависимостей в случае изменения опций командной строки
Проблемы с одновременным запуском и распараллеливанием
Легко «убить» дерево сборки внезапной остановкой программы.
Слайд 34

Свой, самобытный синтаксис языка. Отсутствие сборки как таковой в qmake. Qmake

Свой, самобытный синтаксис языка.
Отсутствие сборки как таковой в qmake. Qmake

не собирает ваш проект. Название обманчиво. Он лишь генерирует Makefile, а сборку осуществляет одна из утилит Make (*nix — gnu make, win- nmake, jom или mingw-make).
Отсутствие прозрачной поддержки кросс-компиляции, сборки пакетов и деплоймента.

Критика Qmake

DEFINES += QT_NO_CAST_TO_ASCII
!macx:DEFINES += QT_USE_FAST_OPERATOR_PLUS QT_USE_FAST_CONCATENATION
unix {
CONFIG(debug, debug|release):OBJECTS_DIR = $${OUT_PWD}/.obj/debug-shared
CONFIG(release, debug|release):OBJECTS_DIR = $${OUT_PWD}/.obj/release-shared
CONFIG(debug, debug|release):MOC_DIR = $${OUT_PWD}/.moc/debug-shared
CONFIG(release, debug|release):MOC_DIR = $${OUT_PWD}/.moc/release-shared
RCC_DIR = $${OUT_PWD}/.rcc
UI_DIR = $${OUT_PWD}/.uic
}

Слайд 35

Qbs(Qt Build System) Файл сборки простейшего приложения import qbs Product {

Qbs(Qt Build System)

Файл сборки простейшего приложения
import qbs
Product {
type: ["application"]
Depends

{ name: "cpp" }
files: ["main.cpp"]
}

Декларативность — используется QML/JavaScript синтаксис;
Расширяемость — есть возможность писать свои модули для сборки, либо кодогенераторы и т. п.
Скорость;
Сборка напрямую — это не qmake, это не «посредник». Qbs сама вызывает компиляторы, компоновщик, и что там еще понадобится.

Использование JavaScript
---helpers.js---
function planetsCorrectlyAligned()
{
// implementation
return true;
}
---myproject.qbs---
import qbs 1.0
import "helpers.js" as Helpers
Product {
name: "myproject"
Group {
condition: Helpers.planetsCorrectlyAligned()
file: "magic_hack.cpp"
}
}

Слайд 36

Метаобъектный компилятор Препроцессор Кодогенерация(автоматизирует созадние кода из макросов) Пример: сигналы/слоты Компилятор

Метаобъектный компилятор
Препроцессор
Кодогенерация(автоматизирует созадние кода из макросов) Пример: сигналы/слоты
Компилятор ресурсов
Внедрение ресурсов (изображений

и тд.) в исполняемую программу
Файл qrc (Qt Resource Collection)
< ! DOCTYPE RCCXRCC version="1.0">

images/open.png
images/quit .png


Использование:
plbl->setPixmap (QPixmap ( " : /images/open.png" ) ) ;