Продолжаем рубрику, посвященную Qt. В этой статье рассмотрим процесс построения графиков с использованием Qt и библиотеки Qwt (напомню, что процесс установки библиотеки описан тут). Для начала запускаем Qt Creator и создаем новый проект:
Как только проект создан, сразу же, пока не забыли, идем в .pro файл проекта и подключаем библиотеку Qwt. То есть дописываем строки:
INCLUDEPATH += D:/Documentation/QWT/include LIBS += -LD:/Documentation/QWT/lib–lqwt
Соответственно, пути к файлам библиотеки у каждого свои. Как же мы, собственно, будем рисовать графики?
А для этого нам нужно будет создать объект класса 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 следующих файла в папку с нашим проектом:
В файле 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);
Вот и все, всего лишь пара строчек, запускаем приложение и видим, что теперь можно увеличивать любую часть графика, а также возвращать исходный масштаб нажатием правой кнопки мыши:
На этом все, спасибо за внимание и до скорого 🤝
А удалить zoomer в деструкторе? Ну и plot есть виджет, который добавляется в дерево виджетов, удаление объектов которого берет на себя QT, поэтому удалять его в деструкторе не нужно.
Так ведь?
Вроде все так, спасибо большое за замечания!
Я создал форму
Form* form = new Form();
form->showNormal();
и тепер в етой форме хочу вивести етот plot.
Но у формЫ нет метода setCentralWidget();
Как сделать что бЫ при нажатии на кнопку вилетала новая форма/widget с графиком?
Помогите плз!
Зарание Спасибо!
Все, разобрался. Спасибо за статью.
Спасибо за статью! =) Только у меня ошибки лезут, и так на каждый вызов всех функций Qwt'а:
D:\Programming\QtProjects\QtDPS\mainwindow.cpp:-1: ошибка: undefined reference to `QwtPlotCurve::setSamples(double const*, double const*, int)'
Подскажите, что может быть? Путь в Path прописал
В общем, и студия, и Creator ругаются на эти вызовы, мол, не объявлялись, неразрешённые внешние символы, как любит студия...
Видимо, qwt почему то не подцепилась к проекту..
Только начал изучение Qt. Работаю с Qt 5.3.
Библиотеку qwt поставил. При сборке проекта получаю сообщение :
"QWidget: Must construct a QApplication before a QWidget
Invalid parameter passed to C runtime function."
Прошу помощи.
Возможно, qwt собрана в debug, а приложение в release?
Сделал сборку приложения в 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 заново пересобирать ?!
Ага, придется пересобирать
При добавлении файлов scrollbar и scrollzoomer вылезает следующая ошибка:
error LNK2001: неразрешенный внешний символ ""public: static struct QMetaObject const QwtPlotZoomer::staticMetaObject" (?staticMetaObject@QwtPlotZoomer@@2UQMetaObject@@B)" moc_scrollzoomer.obj Project 1
Остальные вызовы Qwt работают нормально.
Aveal, "LIBS += -LD:/Documentation/QWT/lib -lqwt" я так полагаю это "косячит движок кода на сайте" :))
Как в методе void MainWindow::setGraphData() не создавать отдельный массив, это возможно? Ну т. е. к примеру в заголовочном файле MainWindow.h объявить указатель, затем передать в объект этого класса адрес на некоторого массива, а уже в место curve->setSamples(x, y, n); писать что то вроде
curve->setSamples(pointer_x, pointer_y n); Что то подобное возможно?
Ну да, можно так. Это же все в пределах одного класса происходит, поэтому спокойно можем объявить массив в .h файле и передавать в функцию.