home | login | register | DMCA | contacts | help |      
mobile | donate | ВЕСЕЛКА

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Э Ю Я


my bookshelf | genres | recommend | rating of books | rating of authors | reviews | new | форум | collections | читалки | авторам | add
fantasy
space fantasy
fantasy is horrors
heroic
prose
  military
  child
  russian
detective
  action
  child
  ironical
  historical
  political
western
adventure
adventure (child)
child's stories
love
religion
antique
Scientific literature
biography
business
home pets
animals
art
history
computers
linguistics
mathematics
religion
home_garden
sport
technique
publicism
philosophy
chemistry
close

реклама - advertisement



Обработка событий во время продолжительных процессов

Когда мы вызываем QApplication::exec(), тем самым начинаем цикл обработки событий Qt. При запуске пpилoжeния Qt генерирует несколько событий для отображения на экране виджетов. После этого начинает выполняться цикл обработки событий: постоянно проверяется их возникновение, и эти события отправляются к объектам QObject данного приложения.

Во время обработки события могут генерироваться другие события, которые ставятся в конец очереди событий Qt. Если слишком много времени уходит на обработку одного события, интерфейс пользователя становится невосприимчивым к действиям пользователя. Например, любые сгенерированные оконной системой события во время сохранения файла на диск не будут обрабатываться до тех пор, пока весь файл не будет записан. В ходе записи файла приложение не будет отвечать на запросы оконной системы на перерисовку приложения.

Одно из решений заключается в применении многопоточной обработки: один процесс для работы с интерфейсом пользователя приложения и другой процесс для выполнения операции сохранения файла (или любой другой длительной операции). В этом случае интерфейс пользователя приложения сможет реагировать на события в процессе выполнения операции сохранения файла. Мы рассмотрим способы обеспечения такого режима работы в главе 18.

Более простое решение заключается в выполнении частых вызовов функции QApplication::processEvents() в программном коде сохранения файла. Данная функция говорит Qt о необходимости обработки ожидающих в очереди событий и затем возвращает управление вызвавшей ее функции. Фактически функция QApplication::exec() представляет собой не более чем вызов функции processEvents() в цикле while.

Ниже приводится пример того, как мы можем сохранить работоспособность интерфейса пользователя при помощи функции processEvents(), причем за основу взят программный код сохранения файла в приложении Spreadsheet:

01 bool Spreadsheet::writeFile(const QString &fileName)

02 {

03 QFile file(fileName);

04 …

05 for (int row = 0; row < RowCount; ++row) {

06 for (int column = 0; column < ColumnCount; ++column) {

07 QString str = formula(row, column);

08 if (!str.isEmpty())

09 out << quint16(row) << quint16(column) << str;

10 }

11 qApp->processEvents();

12 }

13 return true;

14 }

При использовании этого метода существует опасность того, что пользователь может закрыть главное окно во время выполнения операции сохранения файла или даже выбрать повторно File | Save, что приведет к непредсказуемому результату. Наиболее простое решение заключается в замене вызова

qApp->processEvents();

на вызов

qApp->processEvents(QEventLoop::ExcludeUserInputEvents);

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

Часто нам хочется показывать индикатор состояния процесса QProgressDialog в ходе выполнения продолжительной операции. QProgressDialog имеет полоску индикатора, информирующую пользователя о ходе выполнения операции приложением. QProgressDialog также содержит кнопку Cancel, которая позволяет пользователю прекратить выполнение операции. Ниже приводится программный код, применяющий данный подход при сохранении файла приложения Электронная таблица:

01 bool Spreadsheet::writeFile(const QString &fileName)

02 {

03 QFile file(fileName);

04 …

05 QProgressDialog progress(this);

07 progress.setLabelText(tr("Saving %1").arg(fileName));

08 progress.setRange(0, RowCount);

09 progress.setModal(true);

10 for (int row = 0; row < RowCount; ++row) {

11 progress.setValue(row);

12 qApp->processEvents();

13 if (progress.wasCanceled()) {

14 file.remove();

15 return false;

16 }

17 for (int column = 0; column < ColumnCount; ++column) {

18 QString str = formula(row, column);

19 if (!str.isEmpty())

20 out << quint16(row) << quint16(column) << str;

21 }

22 }

23 return true;

24 }

Мы создаем QProgressDialog, в котором RowCount является общим количеством шагов. Затем при обработке каждой строки мы вызываем функцию setValue() для обновления состояния индикатора. QProgressDialog автоматически вычисляет процент завершения операции путем деления текущего значения индикатора на общее количество шагов. Мы вызываем функцию QApplication::processEvents() для обработки любых событий перерисовки либо нажатия пользователем кнопки мышки или клавиши клавиатуры (например, чтобы разрешить пользователю нажимать кнопку Cancel). Если пользователь нажимает кнопку Cancel, мы прекращаем операцию сохранения файла и удаляем файл.

Мы не вызываем для QProgressDialog функцию show(), так как индикатор состояния сам делает это. Если оказывается так, что операция выполняется быстро, прежде всего из-за малого размера файла или высокого быстродействия компьютера, QProgressDialog обнаружит это и вообще не станет выводить себя на экран.

Кроме многопоточности и применения QProgressDialog существует совершенно другой способ работы с продолжительными операциями. Вместо выполнения заданной обработки сразу по поступлении запроса пользователя мы можем отложить эту обработку до момента перехода приложения в состояние ожидания. Этим способом можно пользоваться в тех случаях, когда обработку можно легко прерывать и затем возобновлять, поскольку мы не можем предсказать, как долго приложение будет в состоянии ожидания.

В Qt этот подход можно реализовать путем применения 0—миллисекундного таймера. Таймеры этого типа paботают при отсутствии ожидающих событий. Ниже приводится пример реализации функции timerEvent(), которая демонстрирует обработку в состоянии ожидании:

01 void Spreadsheet::timerEvent(QTimerEvent *event)

02 {

03 if(event->timerId() == myTimerId) {

04 while (step < MaxStep &&

05 !qApp->hasPendingEvents()) {

06 performStep(step);

07 ++step;

08 }

09 } else {

10 QTableWidget::timerEvent(event);

11 }

12 }

Если фyнкция hasPendingEvents() возвращает true, мы останавливаем процесс и передаем управление обратно Qt. Этот процесс будет возобновлен после обработки Qt всех своих ожидающих событий.

Глава 8. Графика 2D и 3D

QT 4: программирование GUI на С++

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

QPainter может использоваться для вычерчивания на таких «устройствах рисования», как QWidget, QPixmap или QImage. QPainter удобно применять, когда мы программируем пользовательские виджеты или классы пользовательских графических элементов с особым внешним видом и режимом работы. Класс QPainter можно также использовать совместно с QPrinter для вывода графики на печатающее устройство и для генерации файлов PDF. Это значит, что во многих случаях мы можем использовать тот же самый программный код при отображении данных на экран и при получении напечатанных отчетов.

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


Установка фильтров событий | QT 4: программирование GUI на С++ | Рисование при помощи QPainter