Уже пять лет я не пишу приложения с 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.
Похожие инструменты.