сегодня в 14:20
В примерах использованы Qt Creator 3.0.0 (MinGW) и Qwt-6.1.0.
Для понимания этой статьи читателю желательно:
- иметь начальный опыт разработки windows-приложений в среде Qt Creator;
- понимать концепцию «сигнал-слот»;
- познакомиться с частью №1 цикла моих статей про Qwt: http://ift.tt/1foEieX
Qwt – графическая библиотека, позволяющая значительно упростить процесс визуализации данных в программе. Упрощение заключается в следующем: нет необходимости вручную прописывать элементы отображения, такие как шкалы координат, сетки, кривые данных и проч. Следует лишь задавать параметры этих элементов.
В части №1 (постепенно разрастающегося) цикла статей мы:
• подключили Qwt к Qt Creator;
• построили график;
• настроили оси координат;
• изменяли масштаб графика (приближали/удаляли его);
• перемещались по полю графика;
• отображали координаты рядом с курсором по щелчку мышкой.
В части №2 мы расширим функциональность нашего визуализатора:
• добавим строку состояния;
• сохраним координаты клика в переменных и отобразим их в строке состояния;
• добавим кнопку на панель управления;
• добавим на панель управления QwtCounter (поле для номера, значение которого можно изменять стрелками, см. картинку).
• зададим с помощью QwtCounter смещение графика x;
• нажатием на кнопку сместим график на ранее заданную величину х.
Примечание: В рамках этой статьи при добавлении элементов управления GUI не используется.
Важно: если вы создаете новый проект, то не забудьте добавить в .pro файл строчку
CONFIG += qwt
и после этого запустить qmake.
#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:
Ui::MainWindow *ui;
QwtPlot *d_plot;
void setPlot();
QwtPlotGrid *grid;
void setPlotGrid();
QwtPlotCurve *curve;
QwtSymbol *symbol;
void setCurveParameters();
// новый массив точек кривой
double pointArray[5][2];
QPolygonF points;
void addPointsToCurveAndShow();
QwtPlotMagnifier *magnifier;
void enableMagnifier();
QwtPlotPanner *d_panner;
void enableMovingOnPlot();
QwtPlotPicker *d_picker;
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);
// Создать поле со шкалами для отображения графика
setPlot();
// Включить масштабную сетку
setPlotGrid();
// Кривая
setCurveParameters();
addPointsToCurveAndShow();
// Включить возможность приближения/удаления графика
enableMagnifier();
// Включить возможность перемещения по графику
enableMovingOnPlot();
// Включить отображение координат курсора и двух перпендикулярных
// линий в месте его отображения
enablePicker();
}
void MainWindow::setPlot()
{
// (this) - разместить поле на текущем окне
// #include <qwt_plot.h>
d_plot = new QwtPlot( this );
setCentralWidget(d_plot); // привязать поле к границам окна
d_plot->setTitle( "Qwt demonstration" ); // заголовок
d_plot->setCanvasBackground( Qt::white ); // цвет фона
// Параметры осей координат
d_plot->setAxisTitle(QwtPlot::yLeft, "Y");
d_plot->setAxisTitle(QwtPlot::xBottom, "X");
d_plot->insertLegend( new QwtLegend() );
}
void MainWindow::setPlotGrid()
{
// #include <qwt_plot_grid.h>
grid = new QwtPlotGrid();
grid->setMajorPen(QPen( Qt::gray, 2 )); // цвет линий и толщина
grid->attach( d_plot ); // добавить сетку к полю графика
}
void MainWindow::setCurveParameters()
{
//#include <qwt_plot_curve.h>
curve = new QwtPlotCurve();
curve->setTitle( "Demo Curve" );
curve->setPen( Qt::blue, 6 ); // цвет и толщина кривой
curve->setRenderHint
( QwtPlotItem::RenderAntialiased, true ); // сглаживание
// Маркеры кривой
// #include <qwt_symbol.h>
symbol = new QwtSymbol( QwtSymbol::Ellipse,
QBrush( Qt::yellow ), QPen( Qt::red, 2 ), QSize( 8, 8 ) );
curve->setSymbol( symbol );
}
void MainWindow::addPointsToCurveAndShow()
{
// Добавить точки на ранее созданную кривую
// Значения точек записываются в массив, затем считываются
// из этого массива
for (int i = 0; i < 5; i++) {
pointArray[i][0] = 1.0 + 0.5*i;
pointArray[i][1] = 1.0 + 0.5*i;
points << QPointF( pointArray[i][0], pointArray[i][1]);
}
curve->setSamples( points ); // ассоциировать набор точек с кривой
curve->attach( d_plot ); // отобразить кривую на графике
}
void MainWindow::enableMagnifier()
{
// #include <qwt_plot_magnifier.h>
magnifier = new QwtPlotMagnifier(d_plot->canvas());
// клавиша, активирующая приближение/удаление
magnifier->setMouseButton(Qt::MidButton);
}
void MainWindow::enableMovingOnPlot()
{
// #include <qwt_plot_panner.h>
d_panner = new QwtPlotPanner( d_plot->canvas() );
// клавиша, активирующая перемещение
d_panner->setMouseButton( Qt::RightButton );
}
void MainWindow::enablePicker()
{
// #include <qwt_plot_picker.h>
// настройка функций
d_picker =
new QwtPlotPicker(
QwtPlot::xBottom, QwtPlot::yLeft, // ассоциация с осями
QwtPlotPicker::CrossRubberBand, // стиль перпендикулярных линий
QwtPicker::AlwaysOn, // всегда включен
d_plot->canvas() ); // ассоциация с полем
// Цвет перпендикулярных линий
d_picker->setRubberBandPen( QColor( Qt::red ) );
// цвет координат положения указателя
d_picker->setTrackerPen( QColor( Qt::black ) );
// непосредственное включение вышеописанных функций
d_picker->setStateMachine( new QwtPickerDragPointMachine() );
}
MainWindow::~MainWindow()
{
delete ui;
}
void setStatusBar();
Добавляем код в mainwindow.cpp
void MainWindow::setStatusBar()
{
#ifndef QT_NO_STATUSBAR
( void )statusBar();
#endif
}
Вызываем функцию из конструктора MainWindow:
setStatusBar();
Клик – это событие. Следовательно, создадим слот, который будет принимать это событие (сигнал). В mainwindow.h добавим новую приватную секцию и следующий код:
private Q_SLOTS:
void click_on_canvas( const QPoint &pos );
Реализуем слот (функцию) в mainwindow.cpp:
void MainWindow::click_on_canvas( const QPoint &pos )
{
// считываем значения координат клика
double x = d_plot->invTransform(QwtPlot::xBottom, pos.x());
double y = d_plot->invTransform(QwtPlot::yLeft, pos.y());
QString info = "x= " + QString::number(x) +
"; y = " + QString::number(y);
// отображаем информацию в строке состояния
statusBar()->showMessage(info);
}
В конструкторе MainWindow создаем пару «сигнал-слот».
// коннектить нужно именно к d_picker, но не к d_plot!
connect( d_picker, SIGNAL( appended( const QPoint & ) ),
SLOT( click_on_canvas( const QPoint & ) ) );
Откомпилируем и кликнем в любом месте экрана (показан нижний кусочек графика):
Как вы уже поняли, координаты клика, записанные в переменные double, можно использовать как угодно.
QToolBar *toolBar;
Прописываем прототип функции в mainwindow.h:
void setToolBar ();
Добавляем код в mainwindow.cpp
void MainWindow::setToolBar()
{
toolBar = new QToolBar( this );
addToolBar( toolBar );
}
Вызываем функцию из конструктора MainWindow:
setToolBar();
Результат: в верхней части появилась тонкая полоска — панель инструментов
(пока пустая).
#include <QToolButton>
Добавляем приватные переменные в mainwindow.h и приватную функцию-прототип:
QToolButton *toolButton;
void addCorrectionButton();
Добавляем код в mainwindow.cpp
void MainWindow::addCorrectionButton()
{
toolButton = new QToolButton( toolBar );
toolButton->setText( "Change x" );
toolButton->setCheckable( true );
toolBar->addWidget( toolButton ); // добавить кнопку на панель инструментов
}
Вызываем функцию из конструктора MainWindow:
addCorrectionButton();
#include <QHBoxLayout>
#include <qwt_counter.h>
Добавляем приватные переменные в mainwindow.h и приватную функцию-прототип:
QWidget *hBox;
QHBoxLayout *layout;
QwtCounter *cntDamp;
void addQwtCounter();
Добавляем код в mainwindow.cpp
void MainWindow::addQwtCounter()
{
// настраиваем параметры установщика смещения
cntDamp = new QwtCounter();
cntDamp->setRange( -50, 50 );
// шаг изменения числа при нажатии одинарной стрелки
// при нажатии двойной стрелки число изменяется на порядок больше
cntDamp->setSingleStep( 1.0 );
cntDamp->setValue( 0 ); // начальное значение
cntDamp->setEnabled(true);
// Размещение элемента на панели инструментов
// новый виджет
hBox = new QWidget();
// "контейнер", организущий виджеты в горизонтальной последовательности
// ассоциируется с объектом типа QWidget.
layout = new QHBoxLayout( hBox );
// помещаем в контейнер установщик смещения
layout->addWidget(cntDamp);
// без этой строчки установщик смещения будет растянут на всю панель
layout->addWidget( new QWidget(hBox) , 10 ); // spacer
// помещаем виджет на уже имеющуюся панель инструментов
( void )toolBar->addWidget( hBox );
}
Вызываем функцию из конструктора MainWindow:
addQwtCounter();
Результат:
void setPlotCorrection( double coeff );
В mainwindow.h добавим приватную переменную:
double changeXValue;
Реализуем слот (функцию) в mainwindow.cpp:
void MainWindow::setPlotCorrection( double coeff )
{
changeXValue = coeff;
}
В конструкторе MainWindow инициализируем добавленную переменную и создаем пару «сигнал-слот»:
changeXValue = 0.0;
connect( cntDamp, SIGNAL( valueChanged( double ) ),
SLOT( setPlotCorrection( double ) ) );
void changeX();
реализуем слот (функцию) в mainwindow.cpp:
void MainWindow::changeX()
{
// очистить контейнер точек
points.clear();
for (int i = 0; i < 5; i++) {
pointArray[i][0] += changeXValue;
points << QPointF( pointArray[i][0], pointArray[i][1]);
}
curve->setSamples( points ); // ассоциировать набор точек с кривой
d_plot->replot();
}
После добавления этих строчек в нашем коде появляется дублирование. Однако, программа имеет демонстрационный характер, поэтому рефакторинг не производился.
В конструкторе MainWindow создаем пару «сигнал-слот»:
connect( toolButton, SIGNAL(toggled(bool)),
SLOT( changeX() ) );
Примечание: кнопка имеет два различных положения (нажата/не нажата), однако, в программе это состояние не отслеживается.
Выводы:
В данной статье на простом примере показано, как добавлять элементы управления вручную, и с помощью них производить модификацию графика.
Очевидно, добавление управляющих элементов вручную –процесс, требующий дополнительного ручного кодирования. Хотелось бы использовать GUI. Именно этому будет посвящена моя следующая статья.
Спасибо за внимание!
P.S. Просьба оставить комментарии по поводу оформления статьи. Удобно ли было ее читать? Может быть, изменить представление материала? Как?
Ссылки:
Архив с исходниками данного примера: http://ift.tt/NjbexP
Официальный ресурс Qwt: qwt.sourceforge.net
Сборник решений разнообразных пробем c Qwt:
http://ift.tt/1lb7Ccv
Часть №1 цикла статей про Qwt: http://ift.tt/1foEieX
Вариант библиотеки, альтернативный Qwt (спасибо, GooRoo!)
www.qcustomplot.com
Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.
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.
Комментариев нет:
Отправить комментарий