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 средств графики 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.
Рисование при помощи QPainter
Чтобы начать рисовать на устройстве рисования (обычно это виджет), мы просто создаем объект QPainter и передаем ему указатель на устройство. Например: