В поддержку Qt

статьи в помощь разработчику

   

Главная

Статьи:

Выбор инструментов разработки

Установка MinGW

Установка Qt 4

Установка Qt 5

Сборка Qt 5

Установка Qt Creator

Проблемы Qt 4.8.3

Распараллеливание компиляции

Распараллеливание для Qt 5.0.1

Сборка отладчика GDB

Установка библиотеки Qwt

Плагин Qwt

Установка QwtPolar

Установка QwtPplot3D

Изменение палитры цветов QwtPlot3D

Конфигурация сборки по умолчанию

Сборка Qt Creator из исходников

Пример использования QwtPlot

Масштабирование QwtPlot в стиле TChart

Синхронное масштабирование

Пример использования QwtPolar

Пример использования QwtPlot3D

Редактирование QSplitter

Сборка в Ubuntu для Windows

Установка пакетов без интернета

Установка драйвера NVIDIA

Файлы:

Проект с интерфейсом QChartSynZoom

Проект без сплиттера

Исходники класса QChartSynZoom

 

Главная > Синхронное масштабирование

 

Синхронное масштабирование графиков

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

В ранее опубликованной статье рассмотрен класс QwtChartZoom, обеспечивающий интерфейс масштабирования и перемещения графика QwtPlot в стиле TChart из библиотеки компонентов Delphi и C++Builder. Напомню, что выделение области, определяющей новые границы графика, в этом интерфейсе производится левой кнопкой мыши движением слева направо и сверху вниз. При отпускании левой кнопкой мыши график изменяет свой масштаб. Если попытаться выделить область в противоположном направлении, то при отпускании кнопки мыши границы графика вернутся к исходному состоянию. Перемещение графика (причем в любом направлении) производится при нажатой правой кнопке мыши.

Класс QwtChartZoom и его дополнения был взят за основу при разработке интерфейса синхронного масштабирования нескольких графиков. Разработанный класс получил название QChartSynZoom. Кроме того, имеется два класса – QWheelSynZoomSvc и QAxisSynZoomSvc, выполняющие ту же функцию, что и аналогичные дополнения к классу QwtChartZoom. Первый поддерживает изменение масштаба вращением колеса мыши при нажатой клавише <Ctrl> или <Shift>. Если нажата клавиша <Ctrl>, то масштабирование производится и по вертикольной оси, и по горизонтальной. Если нажат левый <Shift>, то изменяется масштаб только по вертикальной шкале, если правый <Shift>, – только по горизонтальной. Второй – класс QAxisSynZoomSvc – позволяет изменять одну из границ шкалы, путем ее перетаскивания мышью.

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

Поскольку графики с синхронизированной горизонтальной шкалой должны располагаться один под другим, то хорошей, но необязательной к исполнению, идеей является поместить графики в контейнер QSplitter. Класс QChartSynZoom имеет вариант конструктора, в котором указатель на QSplitter присутствует в качестве аргумента. Это дает возможность интерфейсу масштабирования отслеживать дополнительные события от контейнера и корректно настраивать вид графиков. К сожалению в дизайнере форм в палитре компонентов отсутствует QSplitter, поэтому прописывать его в файл формы *.ui приходится вручную. О том, как это сделать, можно прочитать здесь.

Порядок подключения интерфейса QwtChartSynZoom не сильно отличается от порядка подключения QwtChartZoom, поэтому дальнейшие инструкции во многом повторяют приведенные в вышеупомянутой статье.

Пусть на форме главного окна приложения имеется контейнер QSplitter, а в нем размещены 3 графика с именами plot1, plot2 и plot3. (Как уже отмечалось, использовать QSplitter не обязательно.) Ниже приведены заголовочный файл и файл реализации класса MainWindow.

файл "mainwindow.h"

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

Место для размещения дополнительных директив #include

namespace Ui {
  class MainWindow;
}

class MainWindow : public QMainWindow {
  Q_OBJECT

public:
  MainWindow(QWidget *parent = 0);
  ~MainWindow();

private:
  Ui::MainWindow *ui;

Место для размещения для указатей на элементы графика, менеджер масштабирования и его дополнения
}

#endif // MAINWINDOW_H

файл "mainwindow.cpp"

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
  ui->setupUi(this);

Место для размещения инструкций наполнения графика, подключения менеджера масштабирования и его дополнений

}

MainWindow::~MainWindow()
{
Место для размещения инструкций удаления менеджера масштабирования, его дополнений и элементов графика

  delete ui;
}

Если форма разрабатывалась с помощью Qt Designer, то класс MainWindow определен в пространстве имен Ui, и доступ ко всем элементам формы осуществляется через указатель ui: например, ui->plot1. Пустые графики создаются при выполнении инструкции ui->setupUi(this) в конструкторе главного окна приложения. Далее следует наполнение графиков: создаются кривые с данными, устанавливаются свойства шкал и т.п. (пример оформления графика приведен в посвященной этому вопросу статье). После перестроения графиков здесь же в конструкторе создается менеджер синхронного масштабирования – экземпляр класса QChartSynZoom вместе с дополнениями QWheelSynZoomSvc и QAxisSynZoomSvc. Понятно, что в свой проект надо добавить файлы, реализующие эти классы. В деструкторе перед удалением объектов из пространства имен Ui командой delete ui сначала удаляются менеджер масштабирования и его дополнения, а также все элементы графика, созданные в конструкторе командой new. Для того чтобы иметь доступ к этим элементам в деструкторе, указатели на них должны являться членами класса MainWindow и быть объявленными в заголовочном файле.

Таким образом, последовательность подключения интерфейса QChartSynZoom следующая

1. Копируем в папку со своим проектом файлы "qchartsynzoom.h", "qchartsynzoom.cpp", "qwheelsynzoomsvc.h", "qwheelsynzoomsvc.cpp", "qaxissynzoomsvc.h" и "qaxissynzoomsvc.cpp", которые доступны по ссылке. Если какое-то из дополений – QWheelSynZoomSvc или QAxisSynZoomSvc – не планируется использовать в проекте, то понятно, что файлы этого класса копировать не надо.

2. Добавляем скопированные файлы в свой проект

SOURCES += qchartsynzoom.cpp\
  qwheelsynzoomsvc.cpp\
  qaxissynzoomsvc.cpp

HEADERS += qchartsynzoom.h\
  qwheelsynzoomsvc.h\
  qaxissynzoomsvc.h

Опять же, заголовочные файлы и файлы исходного кода классов QWheelSynZoomSvc и QAxisSynZoomSvc необходимо добавлять в проект только в том случае, если запланировано их использовать.

3. В заголовочный файл "mainwindow.h" включаем дополнительные директивы #include

#include "qchartsynzoom.h"
#include "qwheelsynzoomsvc.h" (если надо)
#include "qaxissynzoomsvc.h" (если надо)

4. В секции private объявляем указатели на менеджер масштабирования и перемещения графика

QChartSynZoom *zoom;

и его дополнения

QWheelSynZoomSvc *whlzmsvc; (если надо)
QAxisSynZoomSvc *axzmsvc; (если надо)

5. В конструкторе главного окна приложения (файл "mainwindow.cpp") создаем экземпляр класса QChartSynZoom, и, если необходимо, переопределяем цвет каймы выделяемой области, задающей новый масштаб графика

zoom = new QChartSynZoom(ui->splitter);
zoom->setRubberBandColor(Qt::white);

Обратите внимание на то, что указатель на контейнер QSplitter присутствует в качестве аргумента в конструкторе. Как уже отмечалось, это дает возможность интерфейсу масштабирования отслеживать дополнительные события от него и корректно настраивать вид графиков. Если же класс QSplitter не используется, и графики выровнены один под другим с помощью иных средств, то экземпляр класса QChartSynZoom создается без указания аргумента

zoom = new QChartSynZoom();

Далее графики отдаются под опеку менеджера масштабирования с помощью вызова функции appendPlot()

zoom->appendPlot(ui->plot1);
zoom->appendPlot(ui->plot2);
zoom->appendPlot(ui->plot3);

Здесь же, если запланировано, создаем экземпляр класса QWheelSynZoomSvc, и прикрепляем его к менеджеру масштабирования

whlzmsvc = new QWheelSynZoomSvc();
whlzmsvc->attach(zoom);

Далее, если запланировано, создаем экземпляр класса QAxisSynZoomSvc, и прикрепляем его к менеджеру масштабирования

axzmsvc = new QAxisSynZoomSvc();
axzmsvc->attach(zoom);

6. В деструктор вставляем команды удаления объектов

delete axzmsvc; (если надо)
delete whlzmsvc; (если надо)
delete zoom;

Готовый проект с подключенным интерфейсом доступен по ссылке. Проект, в котором не используется QSplitter, можно взять здесь. Для дополнительной демонстрации в интерфейсе масштабирования в этом проекте включен "легкий" режим.

Перечислим имеющиеся функции управления интерфейсом и его дополнениями

void QChartSynZoom::appendPlot(QwtPlot)
Добавляет под опеку график. Количество опекаемых графиков ограничено только вертикальным размером экрана.

void QChartSynZoom::fixBoundaries()
Фиксирует текущие границы графика в качестве исходных. Отмена масштабирования будет возвращать график имеено к этим границам.

void QChartSynZoom::setRubberBandColor(QColor)
Устанавливает цвет каймы выделяемой области, задающей новый размер графика, (по умолчанию черный).

void QChartSynZoom::setLightMode(bool)
Включает/выключает "легкий" режим перемещения графика (по умолчанию выключен).

void QChartSynZoom::indicateDragBand(QChartSynZoom::QDragIndiStyle)
Задает стиль индикатора перемещения графика в "легком" режиме. Аргумент может принимать значения
QChartSynZoom::disNone     – индикация отключена;
QChartSynZoom::disSimple   – упрощенная индикация;
QChartSynZoom::disDetailed – подробная индикация.
(По умолчанию задан стиль QChartSynZoom::disSimple.)

void QwtChartSynZoom::setDragBandColor(QColor)
Устанавливает цвет индикатора перемещения графика в "легком" режиме (по умолчанию черный).

void QWheelSynZoomSvc::attach(QChartSynZoom *)
Подключает дополнение QWheelSynZoomSvc к интерфейсу масштабирования.

void QWheelSynZoomSvc::setWheelFactor(double)
Задает коэффициент масштабирования графика при вращении колеса мыши (по умолчанию коэффициент равен 1.2).

void QAxisSynZoomSvc::attach(QChartSynZoom *)
Подключает дополнение QAxisSynZoomSvc к интерфейсу масштабирования.

void QAxisSynZoomSvc::setLightMode(bool)
Включает/выключает "легкий" режим изменения границы шкалы (по умолчанию выключен).

void QAxisSynZoomSvc::indicateDragBand(bool)
Включает/выключает индикацию изменения границы шкалы в "легком" режиме (по умолчанию индикация включена).

void QAxisSynZoomSvc::setAxisRubberBandColor(QColor)
Устанавливает цвет индикатора изменения границы шкалы в "легком" режиме (по умолчанию черный).

Как видим, для работы на слабых компьютерах предусмотрен "легкий" режим интерфейса, подобно тому, как это реализовано для класса QChartSynZoom.

Замечание. Если под опеку синхронного менеджера масштабирования добавить всего один график, то внешне все будет выглядеть также как и при использовании класса QwtChartZoom. Более того, опекаемый график можно указать в качестве аргумента непосредственно в при создании экземпляра класса QChartSynZoom, например так

zoom = new QChartSynZoom(ui->myPlot);

Таким образом, класс QwtChartZoom сохраняет право на существование только для того, чтобы сэкономить размер генерируемого кода.