KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Жасмин Бланшет - QT 4: программирование GUI на С++

Жасмин Бланшет - QT 4: программирование GUI на С++

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Жасмин Бланшет, "QT 4: программирование GUI на С++" бесплатно, без регистрации.
Перейти на страницу:

051 void Plotter::setCurveData(int id, const QVector<QPointF> &data)

052 {

053 curveMap[id] = data;

054 refreshPixmap();

055 }

Функция setCurveData() устанавливает данные для кривой с заданным идентификатором. Если в curveMap уже имеется кривая с таким идентификатором, ее данные заменяются новыми значениями; в противном случае просто добавляется новая кривая. Переменная—член curveMap имеет тип QMap<int, QVector<QPointF> >.

056 void Plotter::clearCurve(int id)

057 {

058 curveMap.remove(id);

059 refreshPixmap();

060 }

Функция clearCurve() удаляет заданную кривую из curveMap.

061 QSize Plotter::minimumSizeHint() const

062 {

063 return QSize(6 * Margin, 4 * Margin);

064 }

Функция minimumSizeHint() напоминает sizeHint(); в то время как функция sizeHint() устанавливает идеальный размер виджета, minimumSizeHint() задает идеальный минимальный размер виджета. Менеджер компоновки никогда не станет задавать виджету размеры ниже идеального минимального размера.

Мы возвращаем значение 300 × 200 (поскольку Margin равен 50) для того, чтобы можно было разместить окаймляющую кромку по всем четырем сторонам и обеспечить некоторое пространство для самого графика. При меньших размерах считается, что график будет слишком мал и бесполезен.

065 QSize Plotter::sizeHint() const

066 {

067 return QSize(12 * Margin, 8 * Margin);

068 }

В функции sizeHint() мы возвращаем «идеальный» размер относительно константы Margin, причем горизонтальный и вертикальный компоненты этого размера составляют ту же самую приятную для глаза пропорцию 3:2, которую мы использовали для minimumSizeHint().

Мы завершаем рассмотрение открытых функций и слотов построителя графиков Plotter. Теперь давайте рассмотрим защищенные обработчики событий.

069 void Plotter::paintEvent(QPaintEvent * /* event */)

070 {

071 QStylePainter painter(this);

072 painter.drawPixmap(0, 0, pixmap);

073 if (rubberBandIsShown) {

074 painter.setPen(palette().light().color());

075 painter.drawRect(rubberBandRect.normalized()

076 .adjusted(0, 0, -1, -1));

077 }


078 if (hasFocus()) {

079 QStyleOptionFocusRect option;

080 option.initFrom(this);

081 option.backgroundColor = palette().dark().color();

082 painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);

083 }

084 }

Обычно все действия по рисованию выполняются функцией paintEvent(). Но в данном случае вся диаграмма уже нарисована функцией refreshPixmap(), и поэтому мы можем воспроизвести весь график, просто копируя пиксельную карту в виджет в позицию (0, 0).

Если резиновая лента должна быть видимой, мы рисуем ее поверх графика. Мы используем светлый («light») компонент из текущей цветовой группы виджета в качестве цвета пера для обеспечения хорошего контраста с темным («dark») фоном. Следует отметить, что мы рисуем непосредственно на виджете, оставляя нетронутым внеэкранное изображение на пиксельной карте. Вызов QRect::normalized() гарантирует наличие положительных значений ширины и высоты прямоугольника резиновой ленты (выполняя обмен значений координат при необходимости), а вызов adjusted() уменьшает размер прямоугольника на один пиксель, позволяя вывести на экран его контур шириной в один пиксель.

Если Plotter получает фокус, вывод фокусного прямоугольника выполняется с использованием функции drawPrimitive(), задающей стиль виджета, с передачей QStyle::PE_FrameFocusRect в качестве первого аргумента и объекта QStyleOptionFocusRect в качестве второго аргумента. Опции рисования фокусного прямоугольника наследуются от виджета Plotter (путем вызова initFrom()). Цвет фона должен задаваться явно.

Если при рисовании требуется использовать текущий стиль, мы можем либо непосредственно вызвать функцию QStyle, например

style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);

либо использовать QStylePainter вместо обычного QPainter (как мы это делали в Plotter), что делает рисование более удобным.

Функция QWidget::style() возвращает стиль, который будет использован для рисования виджета. В Qt стиль виджета является подклассом QStyle. Встроенными являются стили QWindowsStyle, QWindowsXPStyle, QMotifStyle, QCDEStyle, QMacStyle и OPlastiqueStyle. Все эти стили переопределяют виртуальные функции класса QStyle, чтобы обеспечить корректное рисование в стиле имитируемой платформы. Функция drawPrimitive() класса QStylePainter вызывает функцию класса QStyle с тем именем, которое используется для рисования таких «примитивов», как панели, кнопки и фокусные прямоугольники. Обычно все виджеты используют стиль приложения (QApplication::style()), но в любом виджете стиль может переопределяться с помощью функции QWidget::setStyle().

Путем создания подкласса QStyle можно определить пользовательский стиль. Это можно делать с целью придания отличительных стилевых особенностей одному какому-то приложению или группе из нескольких приложений. Хотя рекомендуется в целом придерживаться «родного» стиля выбранной платформы, Qt предлагает достаточно гибкие средства по управлению стилем тем, у кого большая фантазия.

Встроенные в Qt виджеты при рисовании самих себя почти полностью зависят от QStyle. Именно поэтому они выглядят естественно на всех платформах, поддерживаемых Qt. Пользовательские виджеты могут создаваться чувствительными к стилю либо путем применения QStyle (через QStylePainter) при рисовании самих себя, либо используя встроенные виджеты Qt в качестве дочерних. В Plotter мы используем оба подхода: фокусный прямоугольник рисуется с применением QStyle, а кнопки Zoom In и Zoom Out являются встроенными виджетами Qt.

085 void Plotter::resizeEvent(QResizeEvent * /* event */ )

086 {

087 int x= width() - (zoomInButton->width()

088 + zoomOutButton->width() + 10);

089 zoomInButton->move(x, 5);

090 zoomOutButton->move(x + zoomInButton->width() + 5, 5);

091 refreshPixmap();

092 }

При всяком изменении размера виджета Plotter Qt генерирует событие «изменение размера». Здесь мы переопределяем функцию resizeEvent() для размещения кнопок Zoom In и Zoom Out в верхнем правом углу виджета Plotter.

Мы располагаем кнопки Zoom In и Zoom Out рядом, отделяя их 5-пиксельным промежутком от верхнего и правого краев родительского виджета.

Если бы нам захотелось оставить эти кнопки в верхнем левом углу, который имеет координаты (0, 0), мы бы просто переместили их туда в конструкторе Plotter. Но мы хотим, чтобы они находились в верхнем правом углу, координаты которого зависят от размеров виджета. По этой причине необходимо переопределить функцию resizeEvent() и в ней устанавливать положение кнопок.

Мы не устанавливали положение каких-либо кнопок в конструкторе Plotter. Это сделано из-за того, что Qt всегда генерирует событие изменения размера до первого появления на экране виджета.

В качестве альтернативы переопределению функции resizeEvent() и размещению дочерних виджетов «вручную» можно использовать менеджер компоновки (например, QGridLayout). При применении менеджеров компоновки это выполнить немного сложнее и такой подход потребовал бы больше ресурсов; с другой стороны, это дало бы элегантное решение компоновки справа налево, что необходимо для таких языков, как арабский и еврейский.

В конце мы вызываем функцию refreshPixmap() для перерисовки пиксельной карты с новым размером.

093 void Plotter::mousePressEvent(QMouseEvent *event)

094 {

095 QRect rect(Margin, Margin,

096 width() - 2 * Margin, height() - 2 * Margin);

097 if (event->button() == Qt::LeftButton) {

098 if (rect.contains(event->pos())) {

099 rubberBandIsShown = true;

100 rubberBandRect.setTopLeft(event->pos());

101 rubberBandRect.setBottomRight(event->pos());

102 updateRubberBandRegion();

103 setCursor(Qt::CrossCursor);

104 }

105 }

106 }

Когда пользователь нажимает левую кнопку мышки, мы начинаем отображать на экране резиновую ленту. Для этого необходимо установить флажок rubberBandIsShown на значение true, инициализировать переменную—член rubberBandRect на значение текущей позиции курсора мышки, поставить в очередь событие рисования для вычерчивания резиновой ленты и изменить изображение курсора мышки на перекрестие.

Переменная rubberBandRect имеет тип QRect. Объект QRect может задаваться либо четырьмя параметрами (x, у, w, h), где (x, у) является позицией верхнего левого угла и w × h определяет размеры четырехугольника, либо парой точек верхнего левого и нижнего правого углов. Здесь мы используем формат с парой точек. То место, где пользователь первый раз щелкнул мышкой, становится верхним левым углом, а текущая позиция курсора определяет позицию нижнего правого угла. Затем мы вызываем updateRubberBandRegion() для принудительной перерисовки (небольшой) области, покрываемой резиновой лентой.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*