Пример использования виджета QwtPlot из библиотеки Qwt
Оформление графика
Рассмотрим пример создания и оформления графика с использованием
библитеки Qwt. Проект будем разрабатывать с помощью Qt Creator,
постараемся обеспечить возможность его сборки как на разных платформах
(Ubuntu или Windows), так и с разной версией библиотеки Qwt. Для
Вашего удобства готовый проект доступен по ссылке.
Для определения подключаемой к проекту библиотеки используем файл,
содержимое которого приведено ниже
файл "qwt.pri"
#-------------------------------------------------
#
# QwtLibrary configuration file
#
#-------------------------------------------------
# QWT_VER = 5.2.3
QWT_VER = 6.0.2
contains(QWT_VER,^5\\..*\\..*) {
VER_SFX = 5
UNIX_SFX = -qt4
} else {
VER_SFX =
UNIX_SFX =
}
unix {
QWT_PATH = /usr
QWT_INC_PATH = $${QWT_PATH}/include/qwt$${UNIX_SFX}
QWT_LIB = qwt$${UNIX_SFX}
}
win32 {
win32-x-g++ {
QWT_PATH = /usr/qwt$${VER_SFX}-win
} else {
QWT_PATH = C:/Qt/qwt-$${QWT_VER}
}
QWT_INC_PATH = $${QWT_PATH}/include
CONFIG(debug,debug|release) {
DEBUG_SFX = d
} else {
DEBUG_SFX =
}
QWT_LIB = qwt$${DEBUG_SFX}$${VER_SFX}
}
INCLUDEPATH += $${QWT_INC_PATH}
LIBS += -L$${QWT_PATH}/lib -l$${QWT_LIB}
Данный файл обеспечивают включение в проект следующих
вариантов директив
# Платформа Ubuntu
[Переключить]
# Версия библиотеки Qwt 5.2.2
[Переключить]
INCLUDEPATH += /usr/ include/qwt-qt4
LIBS += -L/usr/lib -lqwt-qt4
# Версия библиотеки Qwt 6.0.0
[Переключить]
INCLUDEPATH += /usr/ include/qwt
LIBS += -L/usr/lib -lqwt
# Платформа Windows
[Переключить]
# Версия библиотеки Qwt 5.2.3
[Переключить]
INCLUDEPATH += C:/Qt/qwt-5.2.3/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -LC:/Qt/qwt-5.2.3/lib -lqwt5
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += C:/Qt/qwt-5.2.3/lib/libqwtd5.a
# Версия библиотеки Qwt 6.0.2
[Переключить]
INCLUDEPATH += C:/Qt/qwt-6.0.2/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -LC:/Qt/qwt-6.0.2/lib -lqwt
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -LC:/Qt/qwt-6.0.2/lib -lqwtd
Замечания. Версии библиотеки актуальны на момент написания статьи.
Пути к заголовочным и библиотечным файлам соответствуют рекомендациям
по установке библиотеки Qwt, описанным в посвященной этому вопросу
статье. Для того чтобы выполнить сборку
проекта с другой версией библиотеки, достаточно изменить значение
переменной QWT_VER. Файл"qwt.pri"
предусматривают и такой экзотический случай, как сборка проекта
в Ubuntu для Windows (см. статью),
а конкретнее, в этом случае в файл проекта будут включены варианты
директив
# Версия библиотеки Qwt 5.x.x
[Переключить]
INCLUDEPATH += /usr/qwt5-win/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -L/usr/qwt5-win/lib -lqwt5
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -L/usr/qwt5-win/lib -lqwtd5
# Версия библиотеки Qwt 6.x.x
[Переключить]
INCLUDEPATH += /usr/qwt-win/ include
# Конфигурация сборки Выпуск (Release)
[Переключить]
LIBS += -L/usr/qwt-win/lib -lqwt
# Конфигурация сборки Отладка (Debug)
[Переключить]
LIBS += -L/usr/qwt-win/lib -lqwtd
Создадим в Qt Creator проект с именем demo_qwt.
В дизайнере откроем форму "mainwindow.ui",
удалим из нее главное меню menuBar, панель
инструментов mainToolBar и панель состояния
statusBar, так как они не будут использоваться
в данном приложении. Поместим на форму виджет QwtPlot
и присвоим ему имя myPlot. Активируем компоновщик
Скомпоновать по сетке, который заставит
график занять все свободное пространство формы. Подберем размер
формы, подходящий для отображения графика. В результате получим
форму, изображенную на рисунке. Элемент управления компоновщиком
и индикатор его активного состояния в инспекторе объектов отмечены
на рисунке символом "К".
Откроем файл проекта, его содержимое сгенерировано автоматически
при создании проекта.
файл "demo_qwt.pro"
#-------------------------------------------------
#
# Project created by QtCreator 2012-07-15T23:40:54
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = demo_qwt
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
# Директива, определяющая библиотеку
[Скрыть]
include(qwt.pri)
Поскольку форма нашего проекта содержит виджет QwtPlot,
то для успешной сборки в файле проекта следует прописать директивы,
определяющие библиотеку Qwt
include(qwt.pri)
Кроме того, в папку с проектом необходимо поместить
файл "qwt.pri", содержимое которого
приведено выше.
Теперь проект готов к сборке, но пока что при запуске
приложения отбражается пустой график, займемся его оформлением.
Зададимся целью получить график, представленный на рисунке.
Заглянем исходники проекта
файл "mainwindow.h"
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
// Дополнительные директивы
#include [Скрыть]
#include <qwt_plot_canvas.h>
#include <qwt_legend.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_curve.h>
#include <qwt_symbol.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
// Указатели на элементы графика
[Скрыть]
QwtLegend *leg;
QwtPlotGrid *grid;
QwtPlotCurve *curv1,*curv2;
};
#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);
// Инструкции оформления графика
[Скрыть]
// Заголовок графика
// Платформа Ubuntu
[Переключить]
ui->myPlot->setTitle(QString::fromUtf8("Зависимость U(t)"));
// Платформа Windows
[Переключить]
ui->myPlot->setTitle(QString::fromLocal8Bit("Зависимость U(t)"));
// Легенда
leg = new QwtLegend();
leg->setItemMode(QwtLegend::ReadOnlyItem);
ui->myPlot->insertLegend(leg,QwtPlot::TopLegend);
// Сетка
grid = new QwtPlotGrid;
grid->enableXMin(true);
grid->setMajPen(QPen(Qt::black,0,Qt::DotLine));
grid->setMinPen(QPen(Qt::gray,0,Qt::DotLine));
grid->attach(ui->myPlot);
// Наименование и границы нижней и левой шкалы
// Платформа Ubuntu
[Переключить]
ui->myPlot->setAxisTitle(QwtPlot::xBottom,QString::fromUtf8("t, мкс"));
// Платформа Windows
[Переключить]
ui->myPlot->setAxisTitle(QwtPlot::xBottom,QString::fromLocal8Bit("t, мкс"));
ui->myPlot->setAxisScale(QwtPlot::xBottom,-0.25,8.25);
ui->myPlot->setAxisTitle(QwtPlot::yLeft,QString::fromUtf8("U, В"));
ui->myPlot->setAxisTitle(QwtPlot::yLeft,QString::fromLocal8Bit("U, В"));
ui->myPlot->setAxisScale(QwtPlot::yLeft,-1.25,1.25);
// Первая кривая
curv1 = new QwtPlotCurve(QString("U1(t)"));
curv1->setRenderHint(QwtPlotItem::RenderAntialiased);
curv1->setPen(QPen(Qt::red));
// Маркеры для первой кривой
#if QWT_VERSION < 0x060000
# Версия библиотеки Qwt 5.x.x
QwtSymbol symbol1;
symbol1.setStyle(QwtSymbol::Ellipse);
symbol1.setPen(QColor(Qt::black));
symbol1.setSize(5);
#else
# Версия библиотеки Qwt 6.x.x
QwtSymbol *symbol1 = new QwtSymbol();
symbol1->setStyle(QwtSymbol::Ellipse);
symbol1->setPen(QColor(Qt::black));
symbol1->setSize(4);
#endif
curv1->setSymbol(symbol1);
// Вторая кривая
curv2 = new QwtPlotCurve(QString("U2(t)"));
curv2->setPen(QPen(Qt::darkGreen));
// Выделение памяти под массивы данных
const int N1 = 128;
const int N2 = 262144;
double *X1 = (double *)malloc((2*N1+2*N2)*sizeof(double));
double *Y1 = X1 + N1;
double *X2 = Y1 + N1;
double *Y2 = X2 + N2;
// Данные для первой кривой
double h = 8./(N1-1);
for (int k = 0; k < N1; k++)
{
X1[k] = k*h;
Y1[k] = cos(M_PI*X1[k]-5*M_PI/12);
}
// Данные для второй кривой
h = 8./(N2-1);
for (int k = 0; k < N2; k++)
{
X2[k] = k*h;
Y2[k] = 0.7 * cos(8*M_PI*X2[k]+M_PI/9);
}
// Передача данных кривым
#if QWT_VERSION < 0x060000
# Версия библиотеки Qwt 5.x.x
curv1->setData(X1,Y1,N1);
curv2->setData(X2,Y2,N2);
#else
# Версия библиотеки Qwt 6.x.x
curv1->setSamples(X1,Y1,N1);
curv2->setSamples(X2,Y2,N2);
#endif
// Освобождение памяти
free((void *)X1);
// Помещение кривых на график
curv1->attach(ui->myPlot);
curv2->attach(ui->myPlot);
// Обновление графика
ui->myPlot->replot();
// Назначение курсора для канвы
ui->myPlot->canvas()->setCursor(Qt::ArrowCursor);
}
MainWindow:: ~MainWindow()
{
// Инструкции удаления элементов графика
[Показать]
// Инструкции удаления элементов графика
[Скрыть]
delete leg;
delete grid;
delete curv1;
delete curv2;
delete ui;
}
Поместим в заголовочный файл "mainwindow.h" директивы #include,
которые нам потребуются
#include <qwt_plot_canvas.h>
#include <qwt_legend.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_curve.h>
#include <qwt_symbol.h>
В секции private класса MainWindow
объявляем указатели на используемые элементы графика
QwtLegend *leg;
QwtPlotGrid *grid;
QwtPlotCurve *curv1,*curv2;
Построение графика будем производить в кострукторе главного окна
приложения (в файле "mainwindow.cpp").
Большинство элементов графика создается командой new.
По завершении работы приложения они должны быть удалены командой
delete. Поэтому мы и сделали указатели на
эти элементы членами класса MainWindow,
чтобы иметь доступ кним в деструкторе.
Первым делом устанавливаем заголовок графика (элемент "1"
на рисунке)
// Платформа Ubuntu
[Переключить]
ui-> myPlot->setTitle( QString::fromUtf8( "Зависимость U(t)"));
// Платформа Windows
[Переключить]
ui-> myPlot->setTitle( QString::fromLocal8Bit( "Зависимость U(t)"));
Создаем легенду расшифровку отображаемых кривых по цветам
(элемент "2" на рисунке), запрещаем редактировать легенду,
добавляем ее в верхнюю часть графика.
leg = new QwtLegend();
leg->setItemMode(QwtLegend::ReadOnlyItem);
ui->myPlot->insertLegend(leg,QwtPlot::TopLegend);
Создаем сетку (элемент "3" на рисунке). Разрешаем отображение
линий сетки, соответствующих вспомогательным делениям нижней шкалы.
Назначаем цвета для линий сетки: черный для основных делений и серый
для вспомогательных. Линии сетки будут изображаться пунктирной линией.
Связываем созданную сетку с графиком.
grid = new QwtPlotGrid;
grid->enableXMin(true);
grid->setMajPen(QPen(Qt::black,0,Qt::DotLine));
grid->setMinPen(QPen(Qt::gray,0,Qt::DotLine));
grid->attach(ui->myPlot);
Устанавливаем наименование нижней шкалы, минимальную и максимальную
границы для нее (элементы "4", "5" на рисунке).
Аналогичные установки делаем для левой шкалы (элементы "6",
"7" на рисунке).
// Платформа Ubuntu
[Переключить]
ui-> myPlot->setAxisTitle( QwtPlot:: xBottom, QString::fromUtf8( "t, мкс"));
// Платформа Windows
[Переключить]
ui-> myPlot->setAxisTitle( QwtPlot:: xBottom, QString::fromLocal8Bit( "t, мкс"));
ui-> myPlot->setAxisScale( QwtPlot:: xBottom,- 0.25, 8.25);
ui->myPlot->setAxisTitle(QwtPlot::yLeft,QString::fromUtf8("U, В"));
ui->myPlot->setAxisTitle(QwtPlot::yLeft,QString::fromLocal8Bit("U, В"));
ui-> myPlot->setAxisScale( QwtPlot:: yLeft,- 1.25, 1.25);
Создаем первую кривую (элемент "8" на рисунке) с наименованием
"U1(t)", разрешаем для нее сглаживание
при прорисовке, поскольку предполагается, что точек на этой кривой
не будет очень много, назначаем цвет прорисовки красный.
curv1 = new QwtPlotCurve(QString("U1(t)"));
curv1->setRenderHint(QwtPlotItem::RenderAntialiased);
curv1->setPen(QPen(Qt::red));
На первой кривой каждую точку будем отмечать маркером. Для этого
создаем экземпляр класса QwtSymbol, назначаем
маркерам стиль эллипс, цвет прорисовки черный, размер
4 и прикрепляем его к кривой.
QwtSymbol *symbol1 = new QwtSymbol();
symbol1->setStyle(QwtSymbol::Ellipse);
symbol1->setPen(QColor(Qt::black));
symbol1->setSize(4);
curv1->setSymbol(symbol1);
Если у Вас установлена библиотека Qwt версии 5.x.x,
то приведенный выше код должен выглядеть несколько иначе из-за внесенных
разработчиком изменений
QwtSymbol symbol1;
symbol1.setStyle(QwtSymbol::Ellipse);
symbol1.setPen(QColor(Qt::black));
symbol1.setSize(5);
curv1->setSymbol(symbol1);
Создаем вторую кривую (элемент "9" на рисунке) с наименованием
"U2(t)". Сглаживание при прорисовке
для нее не разрешаем, поскольку предполагается, что количество точек
на этой кривой будет большим, и график может "притормаживать".
Назначаем цвет прорисовки темно-зеленый.
curv2 = new QwtPlotCurve(QString("U2(t)"));
curv2->setPen(QPen(Qt::darkGreen));
Опять же, выделять точки на второй кривой не имеет
смысла из-за большого их количества.
Теперь займемся подготовкой данных для кривых, изображаемых на
графике. Первая кривая будет содержать 128 точек, вторая
262144. Поскольку частота синусоиды второй кривой больше, чем первой,
то и точек на ней должно быть больше.
const int N1 = 128;
const int N2 = 262144;
Объявляем массивы данных: X1 и Y1 для первой кривой, X2 и Y2 для
второй. Выделяем блок памяти под размещение данных (общий для всех
данных), массивы в нем располагаются последовательно так, как показано
на рисунке.
double *X1 = (double *)malloc((2*N1+2*N2)*sizeof(double));
double *Y1 = X1 + N1;
double *X2 = Y1 + N1;
double *Y2 = X2 + N2;
Вычисляем массивы данных для кривых 1 и 2. X принимает значения
от 0 до 8, шаг приращения по X зависит от количества точек на кривой.
Y(X) синусоида с заданными амплитудой, частотой и начальной
фазой (индивидуальные для каждой кривой).
double h = 8./(N1-1);
for (int k = 0; k < N1; k++)
{
X1[k] = k*h;
Y1[k] = cos(M_PI*X1[k]-5*M_PI/12);
}
h = 8./(N2-1);
for (int k = 0; k < N2; k++)
{
X2[k] = k*h;
Y2[k] = 0.7 * cos(8*M_PI*X2[k]+M_PI/9);
}
Далее, передаем кривым подготовленные данные
curv1->setSamples(X1,Y1,N1);
curv2->setSamples(X2,Y2,N2);
В библиотеке Qwt версии 5.x.x для этих целей предусмотрена
другая функция
curv1->setData(X1,Y1,N1);
curv2->setData(X2,Y2,N2);
Освобождаем выделенную память
free((void *)X1);
Помещаем кривые на график
curv1->attach(ui->myPlot);
curv2->attach(ui->myPlot);
Перестраиваем график
ui->myPlot->replot();
В заключение конструктора назначаем тип курсора для канвы графика
(значение по умолчанию Qt::CrossCursor)
ui->myPlot->canvas()->setCursor(Qt::ArrowCursor);
Осталось вставить в деструктор команды удаления объектов, созданных
в конструкторе команодой new
delete leg;
delete grid;
delete curv1;
delete curv2;
Наконец, можем выполнить сборку проекта и запустить приложение.
Замечание.
В Ubuntu вместо функции
QString::fromLocal8Bit()
следует использовать функцию
QString::fromUtf8()
Масштабирование и перемещение графика
В рассмотренном выше примере не хватает интерфейса, позволяющего
изменять масштаб графика (увеличивать отдельные участки), а также
перемещать отображаемую область графика. Возможность с минимальными
затратами реализовать изменение масштаба графика предоставляет входящий
в состав библиотеки Qwt класс QwtPlotZoomer.
Для того чтобы подключить данный интерфейс к графику из приведенного
выше примера, необходимо
1. В заголовочный файл "mainwindow.h"
включить дополнительную директиву #include
#include <qwt_plot_zoomer.h>
2. В секции private
объявить указатель на менеджер масштабирования графика
QwtPlotZoomer *zoom;
3. В конструкторе главного окна приложения (файл
"mainwindow.cpp") создать экземпляр
класса QwtPlotZoomer, и, если надо, переопределить
цвет каймы выделяемой области, задающей новый масштаб графика
zoom = new
QwtPlotZoomer(ui->myPlot->canvas());
zoom->setRubberBandPen(QPen(Qt::white));
4. В деструктор вставить команду удаления еще
одного объекта
delete zoom;
Готовый проект доступен для скачивания по ссылке. После сборки
проекта и запуска приложения можно наблюдать работу интерфейса в
действии.
Левой кнопкой мыши выделяется область, которая определяет новые
границы графика. Рядом с курсором отображаются координаты его текущего
положения (в единицах, соответствующих осям графика).
По окончании выделения график перерисовывается в
соответствии с заданными новыми границами. Для того чтобы вернуться
к прежнему масштабу достаточно кликнуть правой кнопкой мыши на канве
графика.
Замечание. При использовании Qwt 5.x.x наблюдается различное
поведение интерфейса в зависимоти от платформы, для которой собрано
приложение. В Ubuntu выделение новых границ графика осуществляется
до тех пор, пока нажата левая кнопка мыши. При отпускании кнопки
график перерисовывается в новом масштабе. В Windows при нажатии
и отпускании левой кнопки мыши включается режим выделения. Изменение
размеров выделяемой области продолжается при отпущенной кнопке мыши.
Для завершения режима выделения и перерисовки графика в новых границах
необходимо кликнуть левую кнопку мыши еще раз.
В стандартном интерфейсе масштабирования QwtPlotZoomer
не хватает возможности перемещать график. Бывает, что возникает
необходимость перемещаться вдоль кривой графика, просматривая ее
отдельные участки в увеличенном масштабе. Для реализации такой возможности
можно воспользоваться средствами из примера realtime,
поставляемого вместе с библиотекой Qwt.
Рассмотрим подробнее действия, выпоняемые при подключении интерфейса
к нашему примеру.
1. Находим в исходниках библиотеки Qwt 6.x.x
в папке "examples" проект realtime
и копируем в папку со своим проектом файлы
"scrollbar.h"
"scrollzoomer.h"
"scrollbar.cpp"
"scrollzoomer.cpp"
Для того, чтобы проект мог быть собран и с версией
5.x.x библиотеки Qwt, вносим испраления в файл "scrollzoomer.cpp".
Находим в нем строки
if ( o == Qt::Horizontal )
moveTo( QPointF( min, zoomRect().top() ) );
else
moveTo( QPointF( zoomRect().left(), min ) );
и заменяем их следующими
#if QWT_VERSION < 0x060000
if ( o == Qt::Horizontal
)
move(min, zoomRect().top());
else
move(zoomRect().left(), min);
#else
if ( o == Qt::Horizontal )
moveTo( QPointF( min, zoomRect().top() )
);
else
moveTo( QPointF( zoomRect().left(), min
) );
#endif
2. Добавляем скопированные файлы в свой проект,
а именно, в файле проекта сразу после директивы "include(qwt.pri)"
должно быть записано
SOURCES += scrollbar.cpp\
scrollzoomer.cpp
HEADERS += scrollbar.h\
scrollzoomer.h
Дальнейшие действия анологичны тем, что выполнялись
при подключении стандартного интерфейса масштабирования графика
QwtPlotZoomer
3. В заголовочный файл "mainwindow.h"
включаем дополнительную директиву #include
#include "scrollzoomer.h"
4. В секции private
объявляем указатель на менеджер масштабирования и перемещения графика
ScrollZoomer *zoom;
5. В конструкторе главного окна приложения (файл
"mainwindow.cpp") создаем экземпляр
класса ScrollZoomer, и, если необходимо,
переопределяем цвет каймы выделяемой области, задающей новый масштаб
графика
zoom = new
ScrollZoomer(ui->myPlot->canvas());
zoom->setRubberBandPen(QPen(Qt::white));
6. В деструктор вставляем команду удаления объекта
delete zoom;
Готовый проект, содержащий подключенный интерфейс ScrollZoomer,
можно взять по ссылке.
Масштабирование графика ничем не отличается от стандартного интерфейса,
но после перерисовки графика в новом масштабе на канве появляются
полосы прокрутки, с помощью которых можно двигать график. Результат
увеличения масштаба можно увидеть на рисунке. При возвращении графика
к исходным размерам нажатием на правую кнопку мыши, полосы прокрутки
исчезают.
При использовании Qwt 5.x.x в работе интерфейса можно заметить
мелкие огрехи. Например, после перерисовки графика в увеличенном
масштабе линии сетки не совпадают с соответствующими делениями шкалы,
в чем можно убедиться, взглянув на рисунок. Расхождение исправляется,
если подвигать полосы прокрутки или изменить размер окна, содержащего
график. Аналогичная рассинхронизация сетки и шкалы наблюдается при
возвращении графика к исходному масштабу. Кроме того, область канвы,
отведенная под полосы прокрутки, остается незаполненной после их
исчезновения.
В наличии недостатков признаются и сами разработчики. В файле "README"
проекта с примером realtime написано следующее
"...There are a couple of reasons why the implementation
is a hack and therefore the class is not part of the Qwt lib, but
it should be working with all types of QwtPlots..."
Т.е. фактически здесь сказано, что в реализации класса
имеется дефект, поэтому он не включен в состав библиотеки Qwt, а
поставляется в виде файлов из примера.
На мой взгляд, неудачна сама идея двигать график с помощью полос
прокрутки, ведь они позволяют делать это только в горизонтальном
и вертикальном направлении, а иногда хочется перемещать график по
диагонали. На много удобнее интерфейс масштабирования и перемещения
графика у компонента TChart из библиотеки
компонентов Delphi и C++Builder. Реализация подобного интерфейса
описана в статье "Интерфейс масштабирования
и перемещения графика QwtPlot в стиле TChart из библиотеки компонентов
Delphi", готовый проект рассматриваемого примера с подключенным
интерфейсом в стиле TChart доступен по ссылке,
а для сравнения результатов приведен проект
Delphi с аналогичным графиком. Также может представлять интерес
статья на перекликающуюся тему Синхронное
масштабирование графиков.
Надеюсь, сведения, изложенные в данной публикации, будут Вам полезны.
При подготовке материала данной статьи использовались
ресурсы "Библиотека QWT. Простое приложение, использующее
QWT. (Урок 1)" и "Библиотека QWT. Добавляем QwtSymbol, QwtPlotPicker,
Zoomer. (Урок 2)".
|