- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания QT 4 программирование GUI на С++ Жасмин Бланшет
Шрифт:
Интервал:
Закладка:
12 statusBar(), SLOT(showMessage(const QString &)));
13 connect(&thread, SIGNAL(finished()),
14 this, SLOT(allTransactionsDone()));
15 setCurrentFile("");
16 }
Интересной частью конструктора ImageWindow являются два соединения сигнал—слот. В обоих случаях сигнал генерируется объектом TransactionThread, который мы вскоре рассмотрим.
01 void ImageWindow::flipHorizontally()
02 {
03 addTransaction(new FlipTransaction(Qt::Horizontal));
04 }
Слот flipHorizontally() создает транзакцию зеркального отражения и регистрирует ее при помощи закрытой функции addTransaction(). Функции flipVertically(), resizeImage(), convertTo32Bit(), convertTo8Bit() и convertTo1Bit() реализуются аналогично.
01 void ImageWindow::addTransaction(Transaction *transact)
02 {
03 thread.addTransaction(transact);
04 openAction->setEnabled(false);
05 saveAction->setEnabled(false);
06 saveAsAction->setEnabled(false);
07 }
Функция addTransaction() добавляет транзакцию в очередь транзакций вторичного потока и отключает команды Open, Save и Save As на время обработки транзакций.
01 void ImageWindow::allTransactionsDone()
02 {
03 openAction->setEnabled(true);
04 saveAction->setEnabled(true);
05 saveAsAction->setEnabled(true);
06 imageLabel->setPixmap(QPixmap::fromImage(thread.image()));
07 setWindowModified(true);
08 statusBar()->showMessage(tr("Ready"), 2000);
09 }
Слот allTransactionsDone() вызывается, когда очередь транзакций TransactionThread становится пустой.
Теперь давайте рассмотрим класс TransactionThread:
01 class TransactionThread : public QThread
02 {
03 Q_OBJECT
04 public:
05 void addTransaction(Transaction *transact);
06 void setImage(const QImage &image);
07 QImage image();
08 signals:
09 void transactionStarted(const QString &message);
10 protected:
11 void run();
12 private:
13 QMutex mutex;
14 QImage currentImage;
15 QQueue<Transaction *> transactions;
16 };
Класс TransactionThread содержит список обрабатываемых транзакций, которые выполняются по очереди в фоновом режиме.
01 void TransactionThread::addTransaction(Transaction *transact)
02 {
03 QMutexLocker locker(&mutex);
04 transactions.enqueue(transact);
05 if (!isRunning())
06 start();
07 }
Функция addTransaction() добавляет транзакцию в очередь транзакций и запускает поток транзакции, если он еще не выполняется. Доступ к переменной—члену transactions защищается мьютексом, потому что главный поток мог бы ее модифицировать функцией addTransaction() во время прохода по транзакциям transactions вторичного потока.
01 void TransactionThread::setImage(const QImage &image)
02 {
03 QMutexLocker locker(&mutex);
04 currentImage = image;
05 }
06 QImage TransactionThread::image()
07 {
08 QMutexLocker locker(&mutex);
09 return currentImage;
10 }
Функции setImage() и image() позволяют главному потоку установить изображение, для которого будут выполняться транзакции, и получить обработанное изображение после завершения всех транзакций. И вновь мы защищаем доступ к переменной—члену при помощи мьютекса.
01 void TransactionThread::run()
02 {
03 Transaction *transact;
04 forever {
05 mutex.lock();
06 if (transactions.isEmpty()) {
07 mutex.unlock();
08 break;
09 }
10 QImage oldImage = currentImage;
11 transact = transactions.dequeue();
12 mutex.unlock();
13 emit transactionStarted(transact->message());
14 QImage newImage = transact->apply(oldImage);
15 delete transact;
16 mutex.lock();
17 currentImage = newImage;
18 mutex.unlock();
19 }
20 }
Функция run() просматривает очередь транзакций и по очереди выполняет все транзакции путем вызова для них функции apply().
После старта транзакции мы генерируем сигнал transactionStarted() с сообщением, выводимым в строке состояния приложения. Когда обработка всех транзакций завершается, функция run() возвращает управление и QThread генерирует сигнал finished().
01 class Transaction
02 {
03 public:
04 virtual ~Transaction() { }
05 virtual QImage apply(const QImage &image) = 0;
06 virtual QString message() = 0;
07 };
Класс Transaction является абстрактным базовым классом, предназначенным для определения операций, которые пользователь может выполнять с изображением. Виртуальный деструктор необходим, потому что нам приходится удалять экземпляры подклассов Transaction через указатель transaction. (Кроме того, если мы его не предусмотрим, некоторые компиляторы выдадут предупреждение.) Transaction имеет три конкретных подкласса: FlipTransaction, ResizeTransaction и ConvertDepthTransaction. Нами будет рассмотрен только подкласс FlipTransaction; другие два подкласса имеют аналогичное определение.
01 class FlipTransaction : public Transaction
02 {
03 public:
04 FlipTransaction(Qt::Orientation orientation);
05 QImage apply(const QImage &image);
06 QString message();
07 private:
08 Qt::Orientation orientation;
09 };
Конструктор FlipTransaction принимает один параметр, который задает ориентацию зеркального отражения (по горизонтали или по вертикали).
01 QImage FlipTransaction::apply(const QImage &image)
02 {
03 return image.mirrored(
04 orientation == Qt::Horizontal, orientation == Qt::Vertical);
05 }
Функция apply() вызывает QImage::mirrored() для объекта QImage, полученного в виде параметра, и возвращает сформированный объект QImage.
01 QString FlipTransaction::message()
02 {
03 if (orientation == Qt::Horizontal) {
04 return QObject::tr("Flipping image horizontally...");
05 } else {
06 return QObject::tr("Flipping image vertically...");
07 }
08 }
Функция messageStr() возвращает сообщение, отображаемое в строке состояния в ходе выполнения операции. Данная функция вызывается из функции transactionThread::run(), кoгдa гeнepиpyeтcя cигнaл transactionStarted().
Применение классов Qt во вторичных потоках
Функция называется потокозащищенной (thread—safe), если она может спокойно вызываться одновременно из нескольких потоков. Если две такие функции вызываются из различных потоков и совместно используют одинаковые данные, результат всегда будет вполне определенным. Это определение можно расширить на класс, и тогда класс будет называться потокозащищенным, если все его функции могут вызываться одновременно из различных потоков, не мешая работе друг друга, если они даже работают с одним и тем же объектом.
В Qt потокозащищенными являются классы QMutex, QMutexLocker, QReadWriteLock, QReadLocker, QWriteLocker, QSemaphore, QThreadStorage<T>, QWaitCondition и часть программного интерфейса QThread. Кроме того, несколько функций являются потокозащищенными, в частности QObject::connect(), QObject::disconnect(), QCoreApplication::postEvent(), QCoreApplication::removePostedEvent() и QCoreApplication::removePostedEvents().
Большинство классов Qt неграфического интерфейса удовлетворяют менее строгому ограничению: они являются реентерабельными (reentrant). Класс называется реентерабельным, если разные его экземпляры могут одновременно использоваться разными потоками. Однако одновременный доступ к одному реентерабельному объекту при многопоточной обработке недостаточно надежен и должен контролироваться при помощи мьютекса. Реентерабельность классов отмечается в справочной документации Qt. Обычно любой класс С++, который не использует глобальные переменные (или, другими словами, совместно используемые данные), является реентерабельным.
Класс QObject — реентерабельный, однако не следует забывать о трех ограничениях:
• Дочерние объекты QObject должны создаваться их родительским потоком. В частности, это означает, что созданные во вторичном потоке объекты нельзя создавать с указанием в качестве родительского объекта QThread, потому что этот объект был создан в другом потоке (либо в главном потоке, либо в другом вторичном потоке).
• Все объекты QObject, созданные во вторичном потоке, должны быть удалены до удаления соответствующего объекта QThread. Это можно обеспечить путем создания объектов в стеке функцией QThread::run().
• Объекты QObject должны удаляться в том потоке, в котором они были созданы. Если требуется удалить объект QObject, существующий в другом потоке, мы должны вызвать потокозащищенную функцию QObject::deleteLater(), которая регистрирует событие «отсроченное удаление».