Пример "Analog Clock"Файлы:
Пример "Analog Clock" показывает, как отрисовывать содержимое пользовательского виджета. Этот пример также демонстрирует как можно использовать возможности QPainter по преобразованию и масштабированию для облегчения отрисовки пользовательских виджетов. Определение класса AnalogClockКласс AnalogClock предоставляет виджет часов с часовой и минутной стрелками, которые автоматически обновляются через каждые несколько секунд. Создаём подкласс QWidget и переопределим стандартную функцию paintEvent() для отрисовки циферблата часов: class AnalogClock : public QWidget { Q_OBJECT public: AnalogClock(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *event); }; Реализация класса AnalogClockAnalogClock::AnalogClock(QWidget *parent) : QWidget(parent) { QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(update())); timer->start(1000); setWindowTitle(tr("Analog Clock")); resize(200, 200); } При создании виджета мы устанавливаем односекундный таймер для отслеживания текущего времени, и соединяем его со стандартным слотом update(), таким образом циферблат часов обновляется при отправке таймером сигнала timeout(). В заключение, изменяем размеры виджета таким образом, что он отображается в подходящем размере. void AnalogClock::paintEvent(QPaintEvent *) { static const QPoint hourHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -40) }; static const QPoint minuteHand[3] = { QPoint(7, 8), QPoint(-7, 8), QPoint(0, -70) }; QColor hourColor(127, 0, 127); QColor minuteColor(0, 127, 127, 191); int side = qMin(width(), height()); QTime time = QTime::currentTime(); Функция paintEvent() вызывается всякий раз, когда содержимое виджета нужно обновить. Это происходит когда виджет сначала отображается, и когда закрывается затем показывается, но также выполняется когда вызывается слот update() виджета. Поскольку мы соединили сигнал таймера timeout() с этим слотом, он будет вызываться как минимум один раз каждые пять секунд. Перед настройкой рисовальщика и отрисовкой часов, мы сначала объявляем два списка для объектов QPoint и два - для объектов QColor, которые будут использованы для часовой и минутной стрелок. Цвет минутной стрелки имеет альфа-компонент равный 191, что означает 75% непрозрачности. Также мы устанавливаем длину короткой стороны виджета, поэтому мы можем поместить циферблат часов внутрь виджета. Это полезно также для установки текущего времени перед началом отрисовки. QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.translate(width() / 2, height() / 2); painter.scale(side / 200.0, side / 200.0); Содержимое пользовательских виджетов отрисовываются с помощью QPainter. Рисовальщики можно использовать для рисования на любом QPaintDevice, но обычно они используются вместе с вижетами, поэтому мы передаём экземпляр виджета в конструктор рисовальщика. Вызываем QPainter::setRenderHint() с QPainter::Antialiasing для включения сглаживания. Это делает отрисовываемые диагональные линии более гладкими. Преобразование перемещает начало отсчета в центр виджета, а операция масштабирования гарантирует, что последующие операции отрисовки поместятся в виджет. Мы используем масштабный коэффициент, который позволяет использовать x и y координаты между -100 и 100, а также это гарантирует, что они находятся в пределах самой короткой стороны виджета. Чтобы упростить наш код, мы будем рисовать циферблат часов фиксированного размера, который будет располагаться и масштабироваться таким образом, чтобы размещаться по центру виджета. Рисовальщик занимается всеми преобразованиями, выполняемыми во время события рисования, и гарантирует, что всё отрисовывается правильно. Часто разрешение рисовальщику обрабатывать преобразования легче, чем выполнять расчёты для отрисовки содержимого пользовательского виджета вручную. Сначала рисуем часовую стрелку, используя формулу, которая вращает систему координат против часовой стрелки на такое количество градусов, которое зависящий от текущих значений часов и минут. Это означает, что стрелка будет показана повернутой по часовой стрелке на необходимый угол. painter.setPen(Qt::NoPen); painter.setBrush(hourColor); Устанавливаем перо в значение Qt::NoPen поскольку нам не нужно какие-либо контуры, и используем сплошную кисть с цветом, соответствующим отображаемым часам. Кисти используются при заливке многоугольников и других геометрических фигур. painter.save(); painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); painter.drawConvexPolygon(hourHand, 3); painter.restore(); Сохраняем и восстанавливаем матрицу преобразований до и после вращения, поскольку нам нужно разместить минутную стрелку без учёта любых предыдущих вращений. painter.setPen(hourColor); for (int i = 0; i < 12; ++i) { painter.drawLine(88, 0, 96, 0); painter.rotate(30.0); } Рисуем отметки каждого часа по краю циферблата часов. Мы рисуем отметку когда система координат повернется, поэтому рисовальщик готов к выполнению. painter.setPen(Qt::NoPen); painter.setBrush(minuteColor); painter.save(); painter.rotate(6.0 * (time.minute() + time.second() / 60.0)); painter.drawConvexPolygon(minuteHand, 3); painter.restore(); Минутная стрелка вращается таким же образом, что и часовая. painter.setPen(minuteColor); for (int j = 0; j < 60; ++j) { if ((j % 5) != 0) painter.drawLine(92, 0, 96, 0); painter.rotate(6.0); } } Вновь мы рисуем отметки по краю циферблата часов, но теперь уже отображаем минуты. Мы пропускаем значения, кратные 5, чтобы не рисовать минутные отметки поверх часовых отметок. |
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |