понедельник, 10 февраля 2014 г.

Qwt и Qt Creator. Часть 3: график как элемент Designer Form


В примерах использованы Qt Creator 3.0.0 (MinGW) и Qwt-6.1.0.


Для понимания этой статьи читатель должен иметь начальный опыт разработки windows-приложений в среде Qt Creator, понимать концепцию «сигнал-слот». Также рекомендуется познакомиться с частью №1 и №2 цикла моих статей про Qwt:


http://ift.tt/1foEieX

http://ift.tt/1bbSURY


Qwt – графическая библиотека, позволяющая значительно упростить процесс визуализации данных в программе. Упрощение заключается в следующем: нет необходимости вручную прописывать элементы отображения, такие как шкалы координат, сетки, кривые данных и проч. Следует лишь задавать параметры этих элементов.


В предыдущих частях цикла статей элементы управления графиком добавлялись ручным кодированием. Думаю, большинство программистов предпочли бы пользоваться средствами Qt Creator.


В части №3 мы сделаем следующее:


• добавим виджет для отображения графика в Designer Form, что позволит использовать элементы управления Qt Creator;

• построим демонстрационную кривую, реализуем базовые удобства работы с графиком: возможность перемещения по полю графика, его приближение/удаление, отобразим координаты курсора при его перемещении;

• отобразим координат клика в строке состояния Designer Form;

• переместим кривую вдоль оси х, используя стандартные элементы управления из Qt Creator.


Содержание этой статьи в некоторой степени дублирует содержание части №2. Это сделано специально, так как хотелось сделать статьи независимыми друг от друга.


Добавим виджет для отображения графика в Designer Form
1. Создаем проект с Mainwindow. Напомню обязательную процедуру для использования Qwt: добавить строчку «CONFIG += qwt» в файл .pro проекта и запустить qmake через контекстное меню (правой кнопкой мыши на корневую папку проекта).

2. Открываем редактор формы и находим виджет «Widget». Размещаем его на форме.


3. Изменяем имя добавленного «Widget» на «Qwt_Widget».

4. Правой кнопкой щелкаем на «Qwt_Widget» и выбираем «Promote to…»


5. В поле Promoted class name печатаем «QwtPlot». В поле Header file меняем «qwtplot.h» на «qwt_plot.h». Нажимаем Add и закрываем окно.




Построим демонстрационную кривую, реализуем базовые удобства работы с графиком
Ниже приведен код, во многом аналогичный опубликованному в части №2. Код немного улучшен, удалены фрагменты, отвечающие за «ручное» добавление элементов управления.

Обратите особое внимание на следующее. Раньше мы создавали приватную переменную QwtPlot *d_plot, а затем использовали такую конструкцию, как, например:

d_plot->setTitle( "Qwt demonstration" );


Теперь для настроек свойств графика мы будем использовать следующую конструкцию:



ui->Qwt_Widget->setTitle( "Qwt demonstration" );


Причем, если в коде отсутствуют такие конструкции, то «Qwt_Widget» является пустым. После добавления строчки с настройкой этот виджет начинает отображать поле графика.


Содержание файла mainwindow.h


#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





Содержание файла mainwindow.cpp


#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». Эту стандартную (исхоженную и изъезженную) процедуру я решил не описывать в статье.


Отобразим координат клика в строке состояния Designer Form
1. Добавим код в прототип класса MainWindow в файле mainwindow.h

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 и делать вышеуказанный коннект «сигнал-слот» в конструкторе, либо в специальном методе.




Переместим кривую вдоль оси х
Здесь, так как визуализатор добавлен с помощью «Widget», все просто и знакомо:

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, которые были учтены при написании этой статьи.


Ссылки:


Исходники:

http://ift.tt/1bFvleW


Официальный ресурс:

qwt.sourceforge.net


Сборник решений разнообразных пробем c Qwt:

http://ift.tt/1lb7Ccv


Вариант библиотеки, альтернативный Qwt (спасибо, GooRoo)

www.qcustomplot.com/


Ссылки на предыдущие статьи цикла:

Часть 1: http://ift.tt/1foEieX

Часть 2: http://ift.tt/1bbSURY


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий