Приложения QT. Построение графиков.

Продолжаем рубрику приложения QT. В этой статье рассмотрим графики QT, процесс построения графиков с использованием QT и библиотеки QWT (напомню, что процесс установки библиотеки описан тут). Для начала запускаем QT и создаем новый проект.
Новый проект в среде разработки Qt Creator

Как только проект создан, сразу же, пока не забыли, идем в .pro файл проекта и подключаем библиотеку QWT. То есть открываем файл в блокноте и дописываем строки:

INCLUDEPATH += D:/Documentation/QWT/include
LIBS += -LD:/Documentation/QWT/lib -lqwt

Соответственно, пути к файлам библиотеки у каждого свои 😉

Итак, имеем пустой проект. Открываем файл mainwindow.h и подключаем файлы, которые нам понадобятся. Для этого набиваем парочку includ’ов:

#include <QMainWindow>
#include <QWidget>
#include <QtGui>
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <QGlobal.h>

Как же мы, собственно, будем рисовать графики?

А для этого нам нужно будет создать объект класса QwtPlot (если просто объяснять – это что-то типа холста для художника), на который мы поместим объект класса QwtPlotCurve – это непосредственно кривая. Итак, все в том же файле MainWindow.h пишем:

namespace Ui 
{
    class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
 
private:
    QwtPlot *plot;
    QwtPlotCurve *curve;
    Ui::MainWindow *ui;
    void setGraphData();
};

Мы объявили объекты plot и curve, с которыми и будем работать, а также функцию void setGraphData(), которую будем использовать для того, чтобы задать уравнение кривой.

Теперь открываем файл mainwindow.cpp и реализуем конструктор класса MainWindow:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    plot = new QwtPlot();
    plot->setAxisScale(QwtPlot::xBottom, -1, 1);
    plot->setAxisScale(QwtPlot::yLeft, 0, 1);
    curve = new QwtPlotCurve("x(y)");
    curve->setStyle(QwtPlotCurve::Lines);
    curve->setPen(QPen(Qt::blue));
    setGraphData();
    curve->attach(plot);    
    plot->replot();
    this->setCentralWidget(plot);
}

Давайте разбираться, что же тут происходит.

Создаем объект plot:

plot = new QwtPlot();

Задаем интервалы, которые будут отображаться на осях x и y:

plot->setAxisScale(QwtPlot::xBottom, -1, 1);
plot->setAxisScale(QwtPlot::yLeft, 0, 1);

Теперь нужно создать объект класса QwtPlotCurve:

curve = new QwtPlotCurve("x(y)");

Задаем стиль и цвет графика:

curve->setStyle(QwtPlotCurve::Lines);
curve->setPen(QPen(Qt::blue));

Конечно, есть еще множество параметров кривой, с которыми можно поиграться, но нам пока достаточно этого минимума 😉

Идем дальше по коду. В следующей строчке вызываем нашу функцию setGraphData(), ее реализацию напишем чуть попозже. И, наконец, мы добавляем кривую на «полотно», говорим ему «перерисоваться» и устанавливаем объект plot в качестве центрального объекта главного окна приложения:

curve->attach(plot);    
plot->replot();
this->setCentralWidget(plot);

Остается добавить реализацию setGraphData() все в том же файле MainWindow.cpp:

void MainWindow::setGraphData()
{
    const int n = 1000;
    double h = 2.0 / n;
    double x[n];
    double y[n];
    for(int i = 0; i < n; i++)    
    {
         x[i] = -1 + i * h;    
         y[i] = qAbs(x[i]);   
    }    
    curve->setSamples(x, y, n);
}

Берем 1000 точек, задаем шаг изменения переменной x, для каждого значения x вычисляем значение y (кстати, тут строим график функции y = |x|), и вызовом функции setSamples добавляем все полученные точки на график. Осталось почистить все после себя ) Дописываем в деструктор класса MainWindow:

MainWindow::~MainWindow()
{
    delete ui;
    delete curve;
    delete plot;
}

И запускаем сборку приложения. Получается такой вот график:
Пример создания графика
Теперь можно добавить интерфейс для работы с графиком, а именно средства для масштабирования. Для этого нам понадобится класс ScrollZoomer, не входящий в бибилотеку QWT. Но не будем сокрушаться из-за его отсутствия, а спокойно утащим его из примеров, поставляющихся вместе с библиотекой. Находим в папке QWT (не в той папке, в которую установлена библиотека, а в той, которую изначально скачивали) подпапку Examples. Открываем папку с проектом RealTime и забираем оттуда 4 следующих файла в папку с нашим проектом:
Построение графика в QT
В файле MainWindow.h дописываем:

#include "scrollzoomer.h"
#include "scrollBar.h"

А также объявляем объект класса ScrollZoomer:

private:
    QwtPlot *plot;
    QwtPlotCurve *curve;
    Ui::MainWindow *ui;
    ScrollZoomer *zoomer;  //Добавили строку
    void setGraphData();
};

В конструкторе класса MainWindow (файл MainWindow.cpp) добавляем лишь одну строчку:

setGraphData();
curve->attach(plot);
zoomer = new ScrollZoomer(plot->canvas() );  //И еще одну строку добавили ;)
plot->replot();
this->setCentralWidget(plot);

Вот и все, всего лишь пара строчек ) Запускаем приложение и видим, что теперь можно увеличивать любую часть графика, а также возвращать исходный масштаб нажатием правой кнопки мыши:
Изменение масштаба графика
На этом все, теперь мы научились строить графики при помощи QWT, и даже добавили минимальный интерфейс для работы с ними 😉

Понравилась статья? Поделись с друзьями!

Приложения QT. Построение графиков.: 15 комментариев
  1. А удалить zoomer в деструкторе? Ну и plot есть виджет, который добавляется в дерево виджетов, удаление объектов которого берет на себя QT, поэтому удалять его в деструкторе не нужно.
    Так ведь?

  2. Я создал форму
    Form* form = new Form();
    form->showNormal();
    и тепер в етой форме хочу вивести етот plot.
    Но у формЫ нет метода setCentralWidget();
    Как сделать что бЫ при нажатии на кнопку вилетала новая форма/widget с графиком?
    Помогите плз!
    Зарание Спасибо!

  3. Спасибо за статью! =) Только у меня ошибки лезут, и так на каждый вызов всех функций Qwt’а:
    D:\Programming\QtProjects\QtDPS\mainwindow.cpp:-1: ошибка: undefined reference to `QwtPlotCurve::setSamples(double const*, double const*, int)’
    Подскажите, что может быть? Путь в Path прописал

    • В общем, и студия, и Creator ругаются на эти вызовы, мол, не объявлялись, неразрешённые внешние символы, как любит студия…

  4. Только начал изучение Qt. Работаю с Qt 5.3.
    Библиотеку qwt поставил. При сборке проекта получаю сообщение :
    “QWidget: Must construct a QApplication before a QWidget
    Invalid parameter passed to C runtime function.”
    Прошу помощи.

  5. Сделал сборку приложения в release и заработало.
    Приложение – пример этой статьи. Получается у меня qwt собрана в release ? Сборку qwt я делал по инструкции на этом же сйте, т.е. https://microtechnics.ru/qt-ustanovka-biblioteki-qwt/
    По этой инструкции надо добавить в файл
    \..\qwt-6.0.1\designer\designer.pro строку CONFIG += release. В итоге у меня сейчас в этом файле такие строки:
    CONFIG -= debug_and_release
    CONFIG += release
    Получается, если мне надо приложение собрать в debug моде, то надо всю qwt заново пересобирать ?!

  6. При добавлении файлов scrollbar и scrollzoomer вылезает следующая ошибка:
    error LNK2001: неразрешенный внешний символ “”public: static struct QMetaObject const QwtPlotZoomer::staticMetaObject” (?staticMetaObject@QwtPlotZoomer@@2UQMetaObject@@B)” moc_scrollzoomer.obj Project 1
    Остальные вызовы Qwt работают нормально.

  7. Aveal, “LIBS += -LD:/Documentation/QWT/lib -lqwt” я так полагаю это “косячит движок кода на сайте” :))

  8. Как в методе void MainWindow::setGraphData() не создавать отдельный массив, это возможно? Ну т. е. к примеру в заголовочном файле MainWindow.h объявить указатель, затем передать в объект этого класса адрес на некоторого массива, а уже в место curve->setSamples(x, y, n); писать что то вроде
    curve->setSamples(pointer_x, pointer_y n); Что то подобное возможно?

    • Ну да, можно так. Это же все в пределах одного класса происходит, поэтому спокойно можем объявить массив в .h файле и передавать в функцию.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *