Pull to refresh

Библиотека Qwt: как построить график функции на плоскости?

Reading time 8 min
Views 38K
Скриншот простейшей программы, демонстрирующей использование виджетов Qwt
Уже пять лет я не пишу приложения с GUI, потому предложение зав. кафедрой подготовить для его лекции программу, строящую некие графики, поначалу меня несколько расстроило.

Как настоящий программист я решил найти самый легкий (и полезный для саморазвития) путь.
А именно, это задание оказалось хорошим поводом для того, чтобы познакомиться с Qt и библиотекой Qwt. Заодно я узнал, что приложения с GUI, оказываются, могут быть кроссплатформенными, а их код не менее элегантным, чем у приложений с «интерфейсом в стиле Unix™».

Итак, Qwt — библиотека виджетов для программирования приложений, имеющих техническую направленность. Она содержит набор виджетов, представляющих собой всевозможные слайдеры и дисковые «номеронабиратели», виджеты для построение гистограмм. Но здесь я расскажу, как Qwt применить для построения самых обычных двумерных графиков функций вида y = f(x).

Дальше в данной заметке
  • приводится ссылка на исходный код моего простейшего примера (+ исполняемые файлы) и инструкция по его компиляции;
  • рассказывается, как же в этом примере всё устроено;
  • для новичков описывается компиляция и установка Qwt.


Простейший пример и его компиляция


Для этой заметки я подготовил совсем маленький пример, который можно использовать в качестве стартовой точки при изучении Qwt.

По ссылке для скачивания (308 КБ) можно получить tgz-архив с
  • исходными кодами,
  • исполняемым файлом для Windows (собиралось в WinXP Pro SP3 32-bit);
  • исполняемым файлом для Linux (собиралось в OpenSUSE 11.2 x86-64).

Собрать же эти бинарники из исходников, можно следующими командами:
  • qmake

Linux:
  • make release

Windows:
  • mingw32-make release

Обратите внимание, что в каталоге с исходниками лежит файл qwt.prf из оригинальной поставки. Так как я использую статическую версию библиотеки, то переменной QwtBuild присваивается пустое значение. Кроме того, в разделе win32 значение переменной QwtBase изменено на путь к каталогу, в который у меня установлена библиотека.

Пройдемся по исходникам


В Qwt всё просто. Есть виджет «область рисования» — QwtPlot. С ним можно связать несколько кривых — объекты QwtPlotCurve. Собственно, вот и всё.

Описание класса (файл QwtBeginner.h)

В моем примере окно приложения — экземпляр класса QwtBeginner, который является потомком класса QWidget.

Он включает в себя две области рисования QwtPlot: на funPlot будут отображаться графики функций, на derPlot — графики их производных.

Всего будет построено четыре кривых: функция синуса и кубическая функция(sinFunCurve, cubFunCurve) и их производные (sinDerCurve, cubDerCurve).

Включать и отключать отображение соответствующих графиков будут кнопки sinButton и cubButton, к сигналам которых будут привязаны слоты sinToggled() и cubToggled().
class QwtBeginner : public QWidget<br>{<br>    Q_OBJECT<br><br>public:<br>    QwtBeginner(QWidget *parent = 0);<br><br>private:<br>    QwtPlot *funPlot, *derPlot;<br>    QwtPlotCurve *sinFunCurve, *sinDerCurve;<br>    QwtPlotCurve *cubFunCurve, *cubDerCurve;<br>    QPushButton *sinButton, *cubButton;<br><br>private slots:<br>    void sinToggled(bool checked);<br>    void cubToggled(bool checked);<br>};


Реализация класса (файл QwtBeginner.cpp)

В конструкторе класса
QwtBeginner::QwtBeginner(QWidget *parent)<br>    : QWidget(parent)<br>{

создаются области рисования и задаются их заголовки:
    // Create plots<br>    funPlot = new QwtPlot;<br>    derPlot = new QwtPlot;<br><br>    funPlot->setTitle("Function");<br>    derPlot->setTitle("Derivative");

Зададим «перышки», которыми будем рисовать кривые:
    // Create curves and attach them to plots<br>    QPen sinPen = QPen(Qt::red);<br>    QPen cubPen = QPen(Qt::blue);

Создадим кривые, потребуем, чтобы они были сглаженными (RenderAntialiased), укажем «перышки» (setPen()), и привяжем кривые к соответствующим областям рисования (attach()).
    sinFunCurve = new QwtPlotCurve;<br>    sinFunCurve->setRenderHint(QwtPlotItem::RenderAntialiased);<br>    sinFunCurve->setPen(sinPen);<br>    sinFunCurve->attach(funPlot);<br><br>    sinDerCurve = new QwtPlotCurve;<br>    sinDerCurve->setRenderHint(QwtPlotItem::RenderAntialiased);<br>    sinDerCurve->setPen(sinPen);<br>    sinDerCurve->attach(derPlot);<br><br>    cubFunCurve = new QwtPlotCurve;<br>    cubFunCurve->setRenderHint(QwtPlotItem::RenderAntialiased);<br>    cubFunCurve->setPen(cubPen);<br>    cubFunCurve->attach(funPlot);<br><br>    cubDerCurve = new QwtPlotCurve;<br>    cubDerCurve->setRenderHint(QwtPlotItem::RenderAntialiased);<br>    cubDerCurve->setPen(cubPen);<br>    cubDerCurve->attach(derPlot);

Заполним массивы данных, которые мы хотим отобразить:
    // Set data<br>    const int N = 20;<br>    double x[N+1];<br>    double sinFunData[N+1], sinDerData[N+1];<br>    double cubFunData[N+1], cubDerData[N+1];<br>    for (int i = 0; i <= N; ++i)<br>    {<br>        const double pi = 4.0 * atan(1.0);<br>        double L = 2;<br>        double h = L / N;<br><br>        x[i] = -L/2 + i * h;<br>        sinFunData[i] = sin(x[i] * pi);<br>        sinDerData[i] = cos(x[i] * pi) * pi;<br>        cubFunData[i] = x[i] * x[i] * x[i];<br>        cubDerData[i] = 3 * x[i] * x[i];<br>    }

и свяжем эти данные с кривыми:
    sinFunCurve->setData(x, sinFunData, N+1);<br>    sinDerCurve->setData(x, sinDerData, N+1);<br>    cubFunCurve->setData(x, cubFunData, N+1);<br>    cubDerCurve->setData(x, cubDerData, N+1);

Для начала спрячем кривые:
    // Hide curves<br>    sinFunCurve->setVisible(false);<br>    sinDerCurve->setVisible(false);<br><br>    cubFunCurve->setVisible(false);<br>    cubDerCurve->setVisible(false);

Создадим кнопки и свяжем сигналы со слотами:
    // Create buttons<br>    sinButton = new QPushButton("Sinus"),<br>    cubButton = new QPushButton("Cubic function"),<br><br>    sinButton->setCheckable(true);<br>    cubButton->setCheckable(true);<br><br>    // Connect signals<br>    connect(sinButton, SIGNAL(toggled(bool)), this, SLOT(sinToggled(bool)));<br>    connect(cubButton, SIGNAL(toggled(bool)), this, SLOT(cubToggled(bool)));

Разместим виджеты на форме и раскроем окно на весь экран:
    // Set layouts<br>    QHBoxLayout *plotsLayout = new QHBoxLayout;<br>    plotsLayout->setSpacing(10);<br>    plotsLayout->addWidget(funPlot);<br>    plotsLayout->addWidget(derPlot);<br><br>    QHBoxLayout *buttonsLayout = new QHBoxLayout ;<br>    buttonsLayout->addWidget(sinButton);<br>    buttonsLayout->addWidget(cubButton);<br><br>    QVBoxLayout *widgetLayout = new QVBoxLayout;<br>    widgetLayout->addLayout(plotsLayout);<br>    widgetLayout->addLayout(buttonsLayout);<br><br>    setLayout(widgetLayout);<br>    showMaximized();<br>}

Наконец, реализация слотов:
void QwtBeginner::sinToggled(bool checked)<br>{<br>    sinFunCurve->setVisible(checked);<br>    sinDerCurve->setVisible(checked);<br>    funPlot->replot();<br>    derPlot->replot();<br>} <br><br>void QwtBeginner::cubToggled(bool checked)<br>{<br>    cubFunCurve->setVisible(checked);<br>    cubDerCurve->setVisible(checked);<br>    funPlot->replot();<br>    derPlot->replot();<br>}

Обратите внимание, что мы не только должны изменить признак видимости кривых (setVisible()), но и перерисовать области рисования (replot()).

Функция main() (файл main.cpp)

Здесь всё традиционно:
int main(int argc, char *argv[])<br>{<br>    QApplication app(argc, argv);<br>    QwtBeginner *wnd = new QwtBeginner;<br>    wnd->show();<br>    return app.exec();<br>} <br><br>* This source code was highlighted with Source Code Highlighter.


Для новичков: компиляция и установка Qwt


С официального сайта для скачивания доступны архивы tar.bz2 и zip. На момент написания этой заметки последней версией является 5.2.0.

Итак, скачиваем и распаковываем архив в какую-нибудь временную директорию.

В файл qwtconfig.pri у меня внесены следующие изменения.
  • Закомментирована строчка "CONFIG += QwtDll" (по каким-то причинам в Windows DLL у меня не собирается).
  • Строчка "CONFIG += QwtExamples" раскомментирована.
  • Прописан другой каталог установки "INSTALLBASE".

Теперь можно приступать к сборке и установке.

Windows

  • qmake qwt.pro
  • mingw32-make
  • mingw32-make install

Linux

  • qmake qwt.pro
  • make
  • sudo make install

Заключение


Qwt — удобный кроссплатформенный инструмент для построения графиков функций одной переменной. Предоставляет простой интерфейс и избавляет от необходимости заботиться о деталях, типа масштабирования и меток на осях.

Необходимо еще отметить, что подкаталоге examples/ исходной поставки лежит еще 15 примеров, среди которых и examples/simple_plot, послуживший основой для моей программки.

Буду признателен за критику, комментарии и дополнения, так как пока я не являюсь большим специалистом по Qt.

Спасибо за внимание!

P.S.

Похожие инструменты.
  • Пакет PLplot: поддержка C++, Python (и нескольких других языков), встраивание в Qt, wxWidgets, Gtk+ (и некоторые другие среды) — спасибо gribozavr.
  • Библиотека MathGL: поддержка C++, Python, встраивание в Qt, см. тж. программу UDAV в качестве примера — спасибо toshnya.
Tags:
Hubs:
+31
Comments 41
Comments Comments 41

Articles