В примерах использованы Qt Creator 3.0.0 (MinGW) и Qwt-6.1.0.
Для понимания этой статьи читатель должен иметь начальный опыт разработки windows-приложений в среде Qt Creator, понимать концепцию «сигнал-слот». Также рекомендуется познакомиться с частью №1 и №2 цикла моих статей про Qwt:
habrahabr.ru/post/211204/
habrahabr.ru/post/211867/
Qwt – графическая библиотека, позволяющая значительно упростить процесс визуализации данных в программе. Упрощение заключается в следующем: нет необходимости вручную прописывать элементы отображения, такие как шкалы координат, сетки, кривые данных и проч. Следует лишь задавать параметры этих элементов.
В предыдущих частях цикла статей элементы управления графиком добавлялись ручным кодированием. Думаю, большинство программистов предпочли бы пользоваться средствами Qt Creator.
В части №3 мы сделаем следующее:
• добавим виджет для отображения графика в Designer Form, что позволит использовать элементы управления Qt Creator;
• построим демонстрационную кривую, реализуем базовые удобства работы с графиком: возможность перемещения по полю графика, его приближение/удаление, отобразим координаты курсора при его перемещении;
• отобразим координат клика в строке состояния Designer Form;
• переместим кривую вдоль оси х, используя стандартные элементы управления из Qt Creator.
Содержание этой статьи в некоторой степени дублирует содержание части №2. Это сделано специально, так как хотелось сделать статьи независимыми друг от друга.
2. Открываем редактор формы и находим виджет «Widget». Размещаем его на форме.
3. Изменяем имя добавленного «Widget» на «Qwt_Widget».
4. Правой кнопкой щелкаем на «Qwt_Widget» и выбираем «Promote to…»
5. В поле Promoted class name печатаем «QwtPlot». В поле Header file меняем «qwtplot.h» на «qwt_plot.h». Нажимаем Add и закрываем окно.
Обратите особое внимание на следующее. Раньше мы создавали приватную переменную QwtPlot *d_plot, а затем использовали такую конструкцию, как, например:
d_plot->setTitle( "Qwt demonstration" );
Теперь для настроек свойств графика мы будем использовать следующую конструкцию:
ui->Qwt_Widget->setTitle( "Qwt demonstration" );
Причем, если в коде отсутствуют такие конструкции, то «Qwt_Widget» является пустым. После добавления строчки с настройкой этот виджет начинает отображать поле графика.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <qwt_plot.h>
#include <qwt_plot_grid.h>
#include <qwt_legend.h>
#include <qwt_plot_curve.h>
#include <qwt_symbol.h>
#include <qwt_plot_magnifier.h>
#include <qwt_plot_panner.h>
#include <qwt_plot_picker.h>
#include <qwt_picker_machine.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private Q_SLOTS:
void click_on_canvas( const QPoint &pos );
private:
Ui::MainWindow *ui;
void addPlot();
void addPlotGrid();
QwtPlotCurve *curve;
QPolygonF points;
void addCurve();
void enableMagnifier();
void enableMovingOnPlot();
void enablePicker();
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Создать поле со шкалами для отображения графика
addPlot();
// Включить масштабную сетку
addPlotGrid();
// Кривая
addCurve();
// Включить возможность приближения/удаления графика
enableMagnifier();
// Включить возможность перемещения по графику
enableMovingOnPlot();
// Включить отображение координат курсора и двух перпендикулярных
// линий в месте его отображения
enablePicker();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::addPlot()
{
// #include <qwt_plot.h>
ui->Qwt_Widget->setTitle( "Qwt demonstration" );
ui->Qwt_Widget->setCanvasBackground( Qt::white );
// Параметры осей координат
ui->Qwt_Widget->setAxisTitle(QwtPlot::yLeft, "Y");
ui->Qwt_Widget->setAxisTitle(QwtPlot::xBottom, "X");
ui->Qwt_Widget->insertLegend( new QwtLegend() );
}
void MainWindow::addPlotGrid()
{
// #include <qwt_plot_grid.h>
QwtPlotGrid *grid = new QwtPlotGrid();
grid->setMajorPen(QPen( Qt::gray, 2 )); // цвет линий и толщина
grid->attach( ui->Qwt_Widget );
}
void MainWindow::addCurve()
{
//#include <qwt_plot_curve.h>
curve = new QwtPlotCurve();
curve->setTitle( "Demo Curve" );
curve->setPen( Qt::blue, 6 ); // цвет и толщина кривой
// Маркеры кривой
// #include <qwt_symbol.h>
QwtSymbol *symbol = new QwtSymbol( QwtSymbol::Ellipse,
QBrush( Qt::yellow ), QPen( Qt::red, 2 ), QSize( 8, 8 ) );
curve->setSymbol( symbol );
// Добавить точки на ранее созданную кривую
// Значения точек записываются в массив, затем считываются
// из этого массива
for (int i = 0; i < 5; i++) {
points << QPointF( 1.0 * i, 1.0 * i); // произвольное заполнение
}
curve->setSamples( points ); // ассоциировать набор точек с кривой
curve->attach( ui->Qwt_Widget ); // отобразить кривую на графике
}
void MainWindow::enableMagnifier()
{
// #include <qwt_plot_magnifier.h>
QwtPlotMagnifier *magnifier =
new QwtPlotMagnifier(ui->Qwt_Widget->canvas());
// клавиша, активирующая приближение/удаление
magnifier->setMouseButton(Qt::MidButton);
}
void MainWindow::enableMovingOnPlot()
{
// #include <qwt_plot_panner.h>
QwtPlotPanner *d_panner = new QwtPlotPanner( ui->Qwt_Widget->canvas() );
// клавиша, активирующая перемещение
d_panner->setMouseButton( Qt::RightButton );
}
void MainWindow::enablePicker()
{
// #include <qwt_plot_picker.h>
// настройка функций
QwtPlotPicker *d_picker =
new QwtPlotPicker(
QwtPlot::xBottom, QwtPlot::yLeft, // ассоциация с осями
QwtPlotPicker::CrossRubberBand, // стиль перпендикулярных линий
QwtPicker::AlwaysOn, // всегда включен
ui->Qwt_Widget->canvas() ); // ассоциация с полем
// Цвет перпендикулярных линий
d_picker->setRubberBandPen( QColor( Qt::red ) );
// цвет координат положения указателя
d_picker->setTrackerPen( QColor( Qt::black ) );
// непосредственное включение вышеописанных функций
d_picker->setStateMachine( new QwtPickerDragPointMachine() );
}
Выполненные действия позволяют нам отображать график непосредственно в форме, причем размеры его полотна соответствуют размерам «Qwt_Widget». Попробуйте после компиляции и запуска программы изменить размеры формы. Размеры «Qwt_Widget», естественно, не изменяются. Чтобы это происходило, необходимо воспользоваться «Layout». Эту стандартную (исхоженную и изъезженную) процедуру я решил не описывать в статье.
private Q_SLOTS:
void click_on_canvas( const QPoint &pos );
реализуем слот (функцию) в mainwindow.cpp:
void MainWindow::click_on_canvas( const QPoint &pos )
{
// считываем значения координат клика
double x = ui->Qwt_Widget->invTransform(QwtPlot::xBottom, pos.x());
double y = ui->Qwt_Widget->invTransform(QwtPlot::yLeft, pos.y());
statusBar()->showMessage("x= " + QString::number(x) +
"; y = " + QString::number(y));
}
В функцию enablePicker() добавляем следующую строчку:
connect( d_picker, SIGNAL( appended( const QPoint & ) ),
SLOT( click_on_canvas( const QPoint & ) ) );
Как вариант, можно было бы объявить d_picker приватной переменной класса MainWindow и делать вышеуказанный коннект «сигнал-слот» в конструкторе, либо в специальном методе.
1. Добавим элемент управления «Double Spin box» на форму и переименуем его на «changeXSpinBox».
2. Добавим элемент управления «PushButton» на форму и переименуем его на «moveByXButton». Изменим текст на кнопке на «Change x».
3. Для «moveByXButton» выполним команду «Go to slot»->clicked.
4. Функция должна выглядеть следующим образом:
void MainWindow::on_moveByXButton_clicked()
{
double x = 0.0;
// Выполняется преобразование ',' на '.' для того, чтобы
// текст spinBox мог бы быть преобразован в double
QString spinBoxText = ui->changeXSpinBox->text().replace(
QLocale().decimalPoint(), QLatin1Char('.'));
double xChangeValue = spinBoxText.toDouble();
for (int i = 0; i <points.size(); i++) {
x = points[i].x();
points[i].setX(x + xChangeValue);
}
curve->setSamples(points);
ui->Qwt_Widget->replot();
}
Выводы: мы успешно воспользовались дизайнерскими средствами Qt Creator для создания визуализатора и его демонстрационных элементов управления. С помощью spinBox и кнопки мы можем изменять координату x точек отображаемой кривой.
В части №4 цикла статей мы реализуем дополнительные способы увеличения/уменьшения графика, выборку точек с помощью мышки, средства редактирования отображения графика и кривых, а также экспорт графика.
P.S. Выражаю огромную признательность Riateche за ценные замечания по статьям №1 и №2, которые были учтены при написании этой статьи.
Ссылки:
Исходники:
github.com/VladimirSap/Qwt_Tutorial
Официальный ресурс:
qwt.sourceforge.net
Сборник решений разнообразных пробем c Qwt:
www.qtcentre.org/archive/index.php/f-23.html
Вариант библиотеки, альтернативный Qwt (спасибо, GooRoo)
www.qcustomplot.com/
Ссылки на предыдущие статьи цикла:
Часть 1: habrahabr.ru/post/211204/
Часть 2: habrahabr.ru/post/211867/
Автор: HotFire