Библиотека 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
{
Q_OBJECT
public:
QwtBeginner(QWidget *parent = 0);
private:
QwtPlot *funPlot, *derPlot;
QwtPlotCurve *sinFunCurve, *sinDerCurve;
QwtPlotCurve *cubFunCurve, *cubDerCurve;
QPushButton *sinButton, *cubButton;
private slots:
void sinToggled(bool checked);
void cubToggled(bool checked);
}; Реализация класса (файл QwtBeginner.cpp)
В конструкторе класса
QwtBeginner::QwtBeginner(QWidget *parent)
: QWidget(parent)
{ создаются области рисования и задаются их заголовки:
// Create plots
funPlot = new QwtPlot;
derPlot = new QwtPlot;
funPlot->setTitle("Function");
derPlot->setTitle("Derivative"); Зададим «перышки», которыми будем рисовать кривые:
// Create curves and attach them to plots
QPen sinPen = QPen(Qt::red);
QPen cubPen = QPen(Qt::blue); Создадим кривые, потребуем, чтобы они были сглаженными (
RenderAntialiased), укажем «перышки» (setPen()), и привяжем кривые к соответствующим областям рисования (attach()). sinFunCurve = new QwtPlotCurve;
sinFunCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
sinFunCurve->setPen(sinPen);
sinFunCurve->attach(funPlot);
sinDerCurve = new QwtPlotCurve;
sinDerCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
sinDerCurve->setPen(sinPen);
sinDerCurve->attach(derPlot);
cubFunCurve = new QwtPlotCurve;
cubFunCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
cubFunCurve->setPen(cubPen);
cubFunCurve->attach(funPlot);
cubDerCurve = new QwtPlotCurve;
cubDerCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
cubDerCurve->setPen(cubPen);
cubDerCurve->attach(derPlot); Заполним массивы данных, которые мы хотим отобразить:
// Set data
const int N = 20;
double x[N+1];
double sinFunData[N+1], sinDerData[N+1];
double cubFunData[N+1], cubDerData[N+1];
for (int i = 0; i <= N; ++i)
{
const double pi = 4.0 * atan(1.0);
double L = 2;
double h = L / N;
x[i] = -L/2 + i * h;
sinFunData[i] = sin(x[i] * pi);
sinDerData[i] = cos(x[i] * pi) * pi;
cubFunData[i] = x[i] * x[i] * x[i];
cubDerData[i] = 3 * x[i] * x[i];
} и свяжем эти данные с кривыми:
sinFunCurve->setData(x, sinFunData, N+1);
sinDerCurve->setData(x, sinDerData, N+1);
cubFunCurve->setData(x, cubFunData, N+1);
cubDerCurve->setData(x, cubDerData, N+1); Для начала спрячем кривые:
// Hide curves
sinFunCurve->setVisible(false);
sinDerCurve->setVisible(false);
cubFunCurve->setVisible(false);
cubDerCurve->setVisible(false); Создадим кнопки и свяжем сигналы со слотами:
// Create buttons
sinButton = new QPushButton("Sinus"),
cubButton = new QPushButton("Cubic function"),
sinButton->setCheckable(true);
cubButton->setCheckable(true);
// Connect signals
connect(sinButton, SIGNAL(toggled(bool)), this, SLOT(sinToggled(bool)));
connect(cubButton, SIGNAL(toggled(bool)), this, SLOT(cubToggled(bool))); Разместим виджеты на форме и раскроем окно на весь экран:
// Set layouts
QHBoxLayout *plotsLayout = new QHBoxLayout;
plotsLayout->setSpacing(10);
plotsLayout->addWidget(funPlot);
plotsLayout->addWidget(derPlot);
QHBoxLayout *buttonsLayout = new QHBoxLayout ;
buttonsLayout->addWidget(sinButton);
buttonsLayout->addWidget(cubButton);
QVBoxLayout *widgetLayout = new QVBoxLayout;
widgetLayout->addLayout(plotsLayout);
widgetLayout->addLayout(buttonsLayout);
setLayout(widgetLayout);
showMaximized();
} Наконец, реализация слотов:
void QwtBeginner::sinToggled(bool checked)
{
sinFunCurve->setVisible(checked);
sinDerCurve->setVisible(checked);
funPlot->replot();
derPlot->replot();
}
void QwtBeginner::cubToggled(bool checked)
{
cubFunCurve->setVisible(checked);
cubDerCurve->setVisible(checked);
funPlot->replot();
derPlot->replot();
} Обратите внимание, что мы не только должны изменить признак видимости кривых (
setVisible()), но и перерисовать области рисования (replot()).Функция main() (файл main.cpp)
Здесь всё традиционно:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QwtBeginner *wnd = new QwtBeginner;
wnd->show();
return app.exec();
}
* 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.promingw32-makemingw32-make install
Linux
qmake qwt.promakesudo make install
Заключение
Qwt — удобный кроссплатформенный инструмент для построения графиков функций одной переменной. Предоставляет простой интерфейс и избавляет от необходимости заботиться о деталях, типа масштабирования и меток на осях.
Необходимо еще отметить, что подкаталоге
examples/ исходной поставки лежит еще 15 примеров, среди которых и examples/simple_plot, послуживший основой для моей программки.Буду признателен за критику, комментарии и дополнения, так как пока я не являюсь большим специалистом по Qt.
Спасибо за внимание!
P.S.
Похожие инструменты.



комментарии (41)