C++ STL & Qt. Занятие 03

Preview:

Citation preview

Темы лекции: Введение в Qt. Программирование GUI.

Практическое задание: GUI приложение на Qt.

Тренер: Игорь Шкулипа, к.т.н.

С++ Библиотеки STL и Qt. Занятие 3

http://www.slideshare.net/IgorShkulipa 2

Библиотека Qt

Библиотека QT предназначена для разработки GUI, разработаннаякомпанией Trolltech AS. Qt была представлена в 1996 году.

Qt является кроссплатформенной, есть реализации библиотеки дляMS/Windows, Unix/X11, Macintosh и Embedded платформ.

Библиотека является объектно-ориентированной, базирующейся накомпонентах и имеет богатое разнообразие различных визуальныхэлементов - виджетов (widgets), предоставляемых в распоряжениепрограммиста.

Библиотека включает в себя :

• Среду для разработки графического интерфейса.• Компилятор мета-объектов.• Набор классов для работы.

http://www.slideshare.net/IgorShkulipa 3

Типы в Qt

Для переносимости кода

qint8 8-битное знаковое целое

quint8 8-битное беззнаковое целое

qint16 16-битное знаковое целое

quint16 16-битное беззнаковое целое

qint32 32-битное знаковое целое

quint32 32-битное беззнаковое целое

qint64 64-битное знаковое целое

quint64 64-битное беззнаковое целое

quintptr Беззнаковый указатель (32 или 64 бита)

qptrdiff Знаковый указатель (32 или 64 бита)

qreal Везде double; float только для архитектуры ARM

Для краткой записи типовuchar unsigned charuint unsigned intulong unsigned longushort unsigned short

qlonglong long long int или __int64

qulonglong unsigned long long int или unsigned __int64

http://www.slideshare.net/IgorShkulipa 4

Регистрация типов

Для эффективной работы с данными (в частности, в контейнерах)определенному коду требуется информация о типах. В Qt ее можноуказать при помощи Q_DECLARE_TYPEINFO:

Q_DECLARE_TYPEINFO (Type, Flags)

где Type – тип, Flags – флаг:

• Q_PRIMITIVE_TYPE – примитив без конструктора и деструктора;• Q_MOVABLE_TYPE – тип с конструктором и/или деструктором,

который можно перемещать в памяти при помощи memcpy();• Q_COMPLEX_TYPE – сложный тип с конструктором и/или

деструктором, который нельзя перемещать в памяти.

http://www.slideshare.net/IgorShkulipa 5

Обзор классов библиотеки

http://www.slideshare.net/IgorShkulipa 6

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

Для эффективной работы с классами на стадии выполнения в Qtиспользуется специальная объектная модель, расширяющая модельC++. В частности, добавляются следующие возможности:

• древовидные иерархии объектов;• аналог dynamic_cast для библиотеки, не использующий RTTI;• взаимодействие объектов через сигналы и слоты;• свойства объектов.

Многие объекты определяются значением сразу нескольких свойств,внутренними состояниями и связями с другими объектами. Онипредставляют собой индивидуальные сущности, и для них не имеетсмысла операция копирования, а также разделение данных в памяти.В Qt эти объекты наследуют свойства QObject.

Инструментарий спроектирован так, что для QObject и всех его потомковконструктор копирования и оператор присваивания недоступны – ониобъявлены в разделе private через макрос Q_DISABLE_COPY():

class SomeClass : public QObject

{

private:

Q_DISABLE_COPY(SomeClass)

};

http://www.slideshare.net/IgorShkulipa 7

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

Таким образом, не стоит использовать конструкцию:SomeClass c1 = SomeClass (c);

вместо:SomeClass c1 (c);

Другие объекты (например, контейнеры и строки) полностьюопределяются представляемыми данными, поэтому в соответствующихклассах имеются операция присваивания и конструктор копирования.Кроме того, объекты, представляющие одинаковые данные, могутпрозрачно для программиста разделять их в памяти.

http://www.slideshare.net/IgorShkulipa 8

Метаобъекты

Часть расширений реализована стандартными методами C++, однако Qtиспользует и более сложные синтаксические расширения, поэтому ониспользует автоматическую генерацию кода.

Для этого в C++ реализован механизм шаблонов, но он не предоставляетвсех необходимых Qt возможностей, плохо совместим с динамическойобъектной моделью и в полной мере не поддерживается всемиверсиями компиляторов.

В сложных ситуациях Qt использует свой компилятор метаобъектов(moc), преобразующий код с расширениями в стандартный код C++.Для обозначения того, что класс использует метаобъектныевозможности (и, соответственно, должен обрабатываться moc), вразделе private нужно указать макрос Q_OBJECT.

Во избежание ошибок Q_OBJECT лучше использовать во всех классах,наследуемых от QObject (косвенно либо напрямую).

class SomeClass: public QObject {

Q_OBJECT

public:

SomeClass();

}

http://www.slideshare.net/IgorShkulipa 9

qobject_cast

Для динамического приведения QObject используется функция

T qobject_cast (QObject *object);

Она работает как стандартная операция dynamic_cast в C++, но нетребует поддержки со стороны системы динамической идентификациитипов (RTTI).

http://www.slideshare.net/IgorShkulipa 10

Свойства

Свойство – составляющая часть объекта, доступ к которойосуществляется как к члену объекта, но таковым не является(реализуют принцип инкапсуляции для членов объекта).

В некоторых объектно-ориентированных языкахпрограммирования (например, в C++) свойства, как элементязыка, отсутствуют.

В этом случае в класс добавляют методы, посредством которыхосуществляется доступ к необходимым переменным класса.

В Qt свойства реализованы с помощью макроса Q_PROPERTY().

http://www.slideshare.net/IgorShkulipa 11

Свойства

Чтобы объявить свойство, необходимо использовать макросQ_PROPERTY() в классе, который унаследован от QObject.

Q_PROPERTY(type name

READ getFunction

[WRITE setFunction]

[RESET resetFunction]

[NOTIFY notifySignal]

[DESIGNABLE bool]

[SCRIPTABLE bool]

[STORED bool]

[USER bool]

[CONSTANT]

[FINAL])

Пример:

Q_PROPERTY(bool focus READ hasFocus)

Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)

http://www.slideshare.net/IgorShkulipa 12

Свойства в Qtclass ExampleClass1 : public QObject

{

Q_OBJECT

Q_PROPERTY(

QString Priority READ getPriority WRITE setPriority)

private:

QString priority;

public:

ExampleClass1(QObject *parent = 0);

~ExampleClass1();

void setPriority(QString prior);

QString getPriority();

};

void ExampleClass1::setPriority(QString prior) {

this->priority= prior;

}

QString ExampleClass1::getPriority() {

return this->priority;

}

http://www.slideshare.net/IgorShkulipa 13

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

#include "exampleclass1.h"

#include <QApplication>

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

MainWindow w;

w.show();

ExampleClass1 exc1(NULL);

exc1.setProperty("Priority", "High");

return a.exec();

}

http://www.slideshare.net/IgorShkulipa 14

Q_ENUMS

Данный макрос регистрирует один или несколько типов перечислений вметаобъектной системе.

class ExampleClass1 : public QObject

{

Q_OBJECT

Q_PROPERTY

(Priorities Priority READ getPriority WRITE setPriority)

Q_ENUMS(Priorities)

private:

Priorities priority;

public:

ExampleClass1(QObject *parent = 0);

~ExampleClass1();

void setPriority(Priorities prior);

Priorities getPriority();

enum Priorities {High, Low, VeryHigh, VeryLow};

};

http://www.slideshare.net/IgorShkulipa 15

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

void ExampleClass1::setPriority(Priorities prior) {

this->priority= prior;

}

Priorities ExampleClass1::getPriority() {

return this->priority;

}

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

MainWindow w;

w.show();

ExampleClass1 exc1(NULL);

exc1.setProperty("Priority", "High");

exc1.setProperty("Priority", ExampleClass1::High);

return a.exec();

}

http://www.slideshare.net/IgorShkulipa 16

Добавление дополнительной информации в класс

Прикреплённые к системе свойств дополнительным макросом,Q_CLASSINFO(), который может использоваться для присоединениядополнительных пар имя--значение к мета-объекту класса, например:

Q_CLASSINFO("Version", "3.0.0")

Как и другие мета-данные, информация класса доступна во времявыполнения через мета-объект.

http://www.slideshare.net/IgorShkulipa 17

Варианты

Объединение (union) в C и C++ – это структура, все члены которойрасполагаются по одному и тому же адресу. Таким образом, подобъединение отводится столько места в памяти, сколько занимает егонаибольший член. Никакого контроля за тем, что находится вобъединении не ведется, и его членами не могут быть объекты классасо специальным конструктором, деструктором, либо операциейкопирования.

Варианты, реализованные через класс QVariant, могут хранитьодновременно одно значение определенного типа, но являются болееудобными и безопасными, а также не предполагают жесткихограничений, как объединения.

http://www.slideshare.net/IgorShkulipa 18

Пользовательские типы в вариантах

Для хранения пользовательских типов используется класс QMetaType.Размещенные в QVariant типы должны регистрироваться через макросQ_DECLARE_METATYPE:

namespace Namespace1

{

struct Struct1

{

int value1;

char value2;

};

}

Q_DECLARE_METATYPE(Namespace1::Struct1)

// ...

Namespace1::Struct1 st1;

st1.value1 = 123;

st1.value2 = 'a';

QVariant var;

var.setValue<Namespace1::Struct1>(st1);

// ...

Namespace1::Struct1 st2 = var.value<Namespace1::Struct1>();

var.typeName(); // Namespace1::Struct1

http://www.slideshare.net/IgorShkulipa 19

Контейнеры в Qt

QVector<T> – это обычный динамический массив. Его имеет смыслиспользовать, если элементы должны храниться в одном участкепамяти.

QList<T> – наиболее часто используемый контейнер. Вставка элементовв середину списка осуществляется за O(n). Для вставки за постоянноевремя в Qt имеется связный список QLinkedList.

QLinkedList<T> – связный список. Он отличается от QList<T> тем, чтопри работе для доступа к элементам нужно использовать итераторы.При этом вставка элементов в середину происходит за постоянноевремя O(1) и не приводит к порче итератора, указывающего нанекоторый другой элемент. Доступ по индексу осуществляется за O(n).

Стек QStack<T> реализован через наследование от QVector<T> сдобавлением методов доступа к стеку.

Очередь QQueue<T> реализована через наследование от QList<T> сдобавлением методов head, enqueue, dequeue.

http://www.slideshare.net/IgorShkulipa 20

Контейнеры с доступом по ключу

QHash<K,T> – хэш-таблица, отображающая ключи типа K в значениятипа T.

QMultiHash<K,T> наследует QHash<K,T> и ориентирован на структуры,в которых одному ключу может соответствовать несколько значений.

QMap<K,T> – ассоциативный массив, отображающий ключи типа K взначения типа T.

QMultiMap<K,T> наследует QMap<K,T> и ориентирован на структуры, вкоторых одному ключу может соответствовать несколько значений.

QSet<T> – неупорядоченное множество, основанное на хэш-таблице.Множество позволяет быстро получать и добавлять значения

Множества

http://www.slideshare.net/IgorShkulipa 21

Указатели

Когда объект, на который ссылается указатель, разрушается, указательстановится «повисшим», т.е. содержащим адрес, по которому уже нетобъекта. Это часто служит источником ошибок.

В Qt имеется защищенный указатель QPointer<T>, которыйавтоматически принимает значение 0 при разрушении связанного сним объекта. Объект должен наследовать от QObject.

В остальном QPointer<T> работает как T*. Он автоматически приводитсяк T*, перегружаются операторы * и -> для разыменования, а такжеприсваивание =.

Конструкторы QPointer<T>:

QPointer();

QPointer (T *p);

QPointer (const QPointer<T> &p);

http://www.slideshare.net/IgorShkulipa 22

Жесткие ссылки

Обычный указатель типа T* можно «обернуть» в объектQSharedPointer<T>, который послужит жесткой ссылкой. Указательбудет удален в тот момент, когда последняя ссылка выйдет за областьдействия, и для нее будет вызван деструктор QsharedPointer<T>.Такая ссылка конструируется из обычного указателя:

QSharedPointer<Class1> sp0(new Class1);

Если указатель на объект передан конструктору QSharedPointer<T>, тообъект нельзя самостоятельно уничтожать либо создавать из него ещеодин QSharedPointer<T>. Новые жесткие ссылки создаются черезкопирование и присваивание.

http://www.slideshare.net/IgorShkulipa 23

Слабые ссылки

Для слабых ссылок QWeakPointer<T> не задано разыменование. Ониприменяются только для того чтобы проверить, не был ли указательудален. Аналогично, имеется метод isNull(), приведение к bool иоператор !. Слабые ссылки можно копировать, присваивать исравнивать.

Допускается преобразование жесткой ссылки в слабую и наоборот:

QWeakPointer<T> QSharedPointer::toWeakRef() const;

QSharedPointer<T> QWeakPointer::toStrongRef() const;

http://www.slideshare.net/IgorShkulipa 24

Итераторы

Итераторы в стиле STL эффективно реализованы, и через них работаюталгоритмы <QtAlgorithms>.

В каждом контейнере есть два типа итераторов: const_iterator сдоступом только для чтения и iterator с доступом для чтения и записи

Контейнер Итератор для чтенияИтератор для чтения и

записи

QList<T>, QQueue<T> QList<T>::const_iterator QList<T>::iterator

QLinkedList<T> QLinkedList<T>::const_iterator QLinkedList<T>::iterator

QVector<T>,

QStack<T>QVector<T>::const_iterator QVector<T>::iterator

QSet<T> QSet<T>::const_iterator QSet<T>::iterator

QMap<T>,

QMultiMap<T>QMap<T>::const_iterator QMap<T>::iterator

QHash<K,T>,

QMultiHash<K,T>QHash<K,T>::const_iterator QHash<K,T>::iterator

http://www.slideshare.net/IgorShkulipa 25

foreach

Для прохода по всем элементам контейнера в Qt имеется ключевое словоforeach.

QList<int> list;

list << 0 << 1 << 2 << 3;

foreach (int x, list)

{

qDebug() << x;

}

В foreach на каждом шаге числу x будет присваиваться значениеочередного элемента списка. При этом возможные изменения x небудут затрагивать содержимое списка. Для изменения содержимогонеобходимо использовать итераторы.

http://www.slideshare.net/IgorShkulipa 26

Обработка событий

События позволяют классу или объекту уведомлять другие классы илиобъекты о возникновении каких-либо ситуаций. Класс, отправляющий(или вызывающий) событие, называется издателем, а классы,принимающие (или обрабатывающие) событие, называютсяподписчиками.

Для связывания событий, происходящий с объектами, и функций,предназначенных для обработки этих событий, в библиотеке Qtиспользуется интересный механизм сигналов и слотов.

Сигнал - это сообщение о том, что произошло какое-либо событие,например, нажатие на кнопку или выбор пункта меню. Всяинформация о событии сохраняется в полях экземплярасоответствующего класса. У сигнала есть источник (например,кнопка) и приёмник (объект, метод которого будет обрабатывать этособытие).

Слот - это сама функция-обработчик события. Связь между всемичетырьмя перечисленными элементами задаётся с помощью методаconnect.

http://www.slideshare.net/IgorShkulipa 27

connect

bool QObject::connect (

const QObject *sender, // Источник события.

const char *signal, // Сигнал.

const QObject *receiver, // Объект-приёмник сигнала.

const char *method, // Функция-обработчик.

Qt::ConnectionType type = Qt::AutoConnection

) const

Последний параметр определяет режим обработки:

• Qt::DirectConnection -- событие обрабатывается сразу;• Qt::QueuedConnection -- событие ставится в общую очередь и

будет обработано только после всех сообщений, уже имеющихся вэтой очереди;

• Qt::AutoConnection -- если источник события находится в том жепотоке, что и приёмник, то будет использован режимQt::DirectConnection, в противном случае -- Qt::QueuedConnection.

http://www.slideshare.net/IgorShkulipa 28

Макросы SIGNAL и SLOT

Для определения сигнала и слота используются макросы SIGNAL и SLOT.

QObject::connect(

scrollBar, // Источник события.

SIGNAL(valueChanged(int)), // Сигнал.

label, // Объект-приёмник сигнала.

SLOT( setNum(int) ) ); // Функция-обработчик.

Параметрами сигнала и слота являются типы, а не переменные.

Количество параметров слота всегда не больше количествапараметров сигнала. Соответствие между ними, как обычно,позиционное: при выполнении программы значением i-го параметраслота становится значение i-го параметра сигнала.

В объявлении класса методы-слоты необходимо указывать в разделеpublic slots или private slots.

Если поместить их вместе с обычными методами класса, то программабудет скомпилирована без ошибок, но при её выполнениинеправильно объявленные методы-слоты вызываться не будут.

http://www.slideshare.net/IgorShkulipa 29

Сигналы

Обычно в программе используются стандартные сигналы, но еслитребуется определить собственные, то их надо объявить в разделеsignals.

class MainWondow : public QMainWindow {

Q_OBJECT

// ...

signals:

void mySignal(); // Сигнал.

private slots:

void onMySignal(); // Слот.

// ...

}

http://www.slideshare.net/IgorShkulipa 30

Соединение сигналов

Сигнал может быть соединён с другим сигналом, например:

connect( myButton,

SIGNAL( clicked() ),

this,

SIGNAL( buttonClicked() ) );

Один и тот же сигнал можно связать с несколькими слотами или другимисигналами.

С одним и тем же слотом можно связать несколько сигналов. Можноуказать несколько одинаковых "соединений": тогда одно событиевызовет генерацию нескольких сигналов и, соответственно,многократное выполнение метода-слота.

Чтобы разорвать связь между сигналом и слотом, используется методdisconnect:

bool QObject::disconnect ( const QObject *sender,

const char *signal,

const QObject *receiver,

const char *method );

http://www.slideshare.net/IgorShkulipa 31

Создание GUI приложение на Qt

http://www.slideshare.net/IgorShkulipa 32

Создание GUI приложение на Qt

http://www.slideshare.net/IgorShkulipa 33

Создание GUI приложение на Qt

http://www.slideshare.net/IgorShkulipa 34

Создание GUI приложение на Qt

http://www.slideshare.net/IgorShkulipa 35

Создание GUI приложение на Qt

http://www.slideshare.net/IgorShkulipa 36

Создание GUI приложение на Qt

http://www.slideshare.net/IgorShkulipa 37

Hello, Qt

http://www.slideshare.net/IgorShkulipa 38

main.cpp

http://www.slideshare.net/IgorShkulipa 39

mainwindow.h

http://www.slideshare.net/IgorShkulipa 40

mainwindow.cpp

http://www.slideshare.net/IgorShkulipa 41

Результат

http://www.slideshare.net/IgorShkulipa 42

Анимация виджетов

QAbstractAnimation Основа всех анимаций

QAnimationGroupАбстрактный базовый класс для групп анимаций

QEasingCurveУпрощение кривой (Easing curves) для управляемой анимации

QParallelAnimationGroup Параллельная группа анимаций

QPauseAnimation Пауза для QSequentialAnimationGroup

QPropertyAnimation Оживляет (Animates) свойства Qt

QSequentialAnimationGroup Последовательная группа анимаций

QTimeLineОтсечки времени (timeline) для управления анимацией

QVariantAnimationАбстрактный базовый класс для анимации

http://www.slideshare.net/IgorShkulipa 43

Пример

http://www.slideshare.net/IgorShkulipa 44

Результат

http://www.slideshare.net/IgorShkulipa 45

Графика в Qt

Ссылка

Основу используемых в Qt средств графики 2D составляет классQPainter.

Этот класс может использоваться для рисования геометрических фигур(точек, линий, прямоугольников, эллипсов, дуг, сегментов и секторовокруж ности, многоугольников и кривых Безье), а также пиксельныхкарт, изображени и текста. Кроме того, QPainter поддерживает такиепродвинутые функции, как сглаживание соединений линий(antialiasing) при начертании фигур и букв в тексте, аль фа-смешение(alpha blending), плавный переход цветов (gradient filling) и цепочкиграфических элементов (vector paths). QPainter также поддерживаетпреобразование координат, что делает графику 2D независимой отразрешающей способности.

В качестве альтернативы классам QPainter можно использовать OpenGIOpenGL является стандартной библиотекой графических средств 2D и3D. Модуль QtOpenGL позволяет очень легко интегрировать OpenGL вприложения Qt.

http://www.slideshare.net/IgorShkulipa 46

Лабораторная работа №3. GUI приложение на Qt