作者存档

Qwt样例之tvplot

Qwt的tvplot这个样例主要讲的是如何画柱状图(Histogram)

tvplot

整个过程从继承自QwtPlot的TVPlot开始,建立画布、座标轴、图例,然后在图上画网格线和柱状图

最后进行图像的初始化,确保右边图例的点按状态和图像显示一致

其实也比较简单,用别人的库最重要的是熟悉每个类和成员函数…

main.cpp和tvplot.h可以忽略不计,重点在tvplot.cpp:

#include <stdlib.h>
#include <qpen.h>
#include <qwt_plot_layout.h>
#include <qwt_legend.h>
#include <qwt_legend_item.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_histogram.h>
#include <qwt_column_symbol.h>
#include <qwt_series_data.h>
#include "tvplot.h"

class Histogram: public QwtPlotHistogram
{
public:
    Histogram(const QString &, const QColor &);

    void setColor(const QColor &);
    void setValues(uint numValues, const double *);
};

Histogram::Histogram(const QString &title, const QColor &symbolColor):
    QwtPlotHistogram(title)
{
    setStyle(QwtPlotHistogram::Columns);

    setColor(symbolColor);
}

void Histogram::setColor(const QColor &symbolColor)
{
    QColor color = symbolColor;
    color.setAlpha(180);  // 真烧包,还半透明

    setPen(QPen(Qt::black));
    setBrush(QBrush(color));

    QwtColumnSymbol *symbol = new QwtColumnSymbol(QwtColumnSymbol::Box);
    symbol->setFrameStyle(QwtColumnSymbol::Raised);
    symbol->setLineWidth(2);
    symbol->setPalette(QPalette(color));
    setSymbol(symbol);
}

void Histogram::setValues(uint numValues, const double *values)
{
    // QwtIntervalSeriesData = QwtIntervalSample * n
    // QwtIntervalSample = value + interval
    // interval = minValue + maxValue
    // value,minValue,maxValue : double
    QVector<QwtIntervalSample> samples(numValues);
    for ( uint i = 0; i < numValues; i++ )
    {
        QwtInterval interval(double(i), i + 1.0);
        interval.setBorderFlags(QwtInterval::ExcludeMaximum);

        samples[i] = QwtIntervalSample(values[i], interval);
    }
    setData(new QwtIntervalSeriesData(samples));
}

TVPlot::TVPlot(QWidget *parent):
    QwtPlot(parent)
{
    setTitle("Watching TV during a weekend");

    setCanvasBackground(QColor(Qt::gray));
    plotLayout()->setAlignCanvasToScales(true);

    setAxisTitle(QwtPlot::yLeft, "Number of People");
    setAxisTitle(QwtPlot::xBottom, "Number of Hours");

    QwtLegend *legend = new QwtLegend;
    legend->setItemMode(QwtLegend::CheckableItem);
    insertLegend(legend, QwtPlot::RightLegend);

    populate();

    // 点选图例时,显示相应的图像
    connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)),
        SLOT(showItem(QwtPlotItem *, bool)));

    replot(); // creating the legend items

    // itemList()返回当前attach到plot上的item,参数是类型
    QwtPlotItemList items = itemList(QwtPlotItem::Rtti_PlotHistogram);
    for ( int i = 0; i < items.size(); i++ )
    {
	// items.size()是2,即一个夏天一个冬天
        if ( i == 0 )
        {
	    // 根据item[i]查出相应的图例
            QwtLegendItem *legendItem = 
				(QwtLegendItem *)legend->find(items[i]);
           if ( legendItem )
                legendItem->setChecked(true);

            items[i]->setVisible(true);
        }
        else
            items[i]->setVisible(false);
    }

    setAutoReplot(true);
}

void TVPlot::populate()
{
    QwtPlotGrid *grid = new QwtPlotGrid;
    grid->enableX(false);    // 网格线整体开关
    grid->enableY(true);
    grid->enableXMin(false);
    grid->enableYMin(false);    // 最小刻度网格线
    // 网格线有两种,major和minor(最小刻度)
    // 下面是设置mojor线的样式
    grid->setMajPen(QPen(Qt::black, 0, Qt::DotLine));
    grid->attach(this);

    const double juneValues[] = { 7, 19, 24, 32, 10, 5, 9, 9 };
    const double novemberValues[] = { 4, 15, 22, 34, 13, 8, 4, 5 };

    Histogram *histogramJune = new Histogram("Summer", Qt::red);
    histogramJune->setValues(
        sizeof(juneValues) / sizeof(double), juneValues);
    histogramJune->attach(this);

    Histogram *histogramNovember = new Histogram("Winter", Qt::blue);
    histogramNovember->setValues(
        sizeof(novemberValues) / sizeof(double), novemberValues);
    histogramNovember->attach(this);
}

void TVPlot::showItem(QwtPlotItem *item, bool on)
{
    item->setVisible(on);
}

Qwt安装与初步

Qwt,即”Qt Widgets for Technical Applications”,是一个用来画各种数据图的Qt库

据说写得比较完善,可以帮人省不少代码…类LGPL许可,毕设的画图部分就用这个东西了

安装参考install文件,比较顺利,不过Mac下面还是得稍微折腾下,具体过程:

cd $QwtDir
qmake -spec macx-g++
make
sudo make install
sudo ln -s /usr/local/qwt-6.0.0/lib/qwt.framework/qwt /usr/lib/qwt

其中$QwtDir是源码文件夹,最后一句ln做符号链接的时候注意版本号要与时俱进

要使用的话在所建工程的.pro文件里加入下面一句:

include(/usr/local/qwt-6.0.0/features/qwt.prf)

而官方文档上的说法,即加入CONFIG += qwt,在我这跑不通…

网上资料很少,只有啃自带的例子,一个最简单的例子

#include <cmath>
#include <qwt_series_data.h>
#include <qwt_plot_curve.h>
#include <qwt_plot.h>
#include <qapplication.h>

class SinusData: public QwtSyntheticPointData
// QwtSyntheticPointData包含在qwt_series_data.h
{
public:
    SinusData():
        QwtSyntheticPointData(100)
// 括号里的参数是在一个特定的区间所计算的点的数目
// 自然,数字越大画出来的图越平滑
    {
    }
    virtual double y(double x) const
    {
        return qSin(x);
    }
};

int main(int argc, char **argv)
{
    QApplication a(argc, argv);

    QwtPlot plot;
    plot.setAxisScale(QwtPlot::xBottom, 0.0, 10.0);
    plot.setAxisScale(QwtPlot::yLeft, -1.0, 1.0);

    QwtPlotCurve *curve = new QwtPlotCurve("y = sin(x)");
    curve->setData(new SinusData());
    curve->attach(&plot); //把曲线附加到图上
			// Qwt貌似是这样,先建立画图区域plot,然后往上面添加曲线和点

    plot.show();
    return a.exec();
}

上面的注释是我加的,因为也是刚刚接触没多久,所以用了很多”貌似”

以后准备把看过的样例发个注释版出来…

参考了

做遵纪守法的好公民

今天早上翻一本讲MySQL的书,看到许可证的问题时,明白了为什么Qt没把MySQL的driver打包进去

书上的原文是这样的:

可一旦把开发的解决方案销售给别人,许可证问题就来了.

(MySQL 5权威指南,p10)

因为诺基亚不知道你是要把Qt拿去干嘛,为了规避不必要的麻烦,就把这个麻烦丢给用户了…= =b…

MySQL是双许可的,GPL和MySQL Network,后者是一个商业许可.Qt也是,LGPL和一个商业许可.

GNU的这两个协议都是有传染性的,”出来混,迟早要还”,用了开源界的东西,就要把自己的代码也贡献给出去…LGPL稍微宽松一点,允许链接到库文件的程序不被”感染”

也就是说,基于Qt库开发的程序是允许商业发布的,而MySQL就不行,所以果断改用SQLite,因为据研究生学长说那个项目是拿去卖的…

SQLite比较共产主义,直接把代码丢到Public domain了…这是何等的觉悟啊:

The author disclaims copyright to this source code. In place of a legal notice, here is a blessing:
May you do good and not evil.
May you find forgiveness for yourself and forgive others.
May you share freely, never taking more than you give.

其它常见的许可还有BSD和Apache,都允许商业开发,没有传染性(不要求开源),只需做必要的说明和致谢就可以了…

 

Mac OS X下Qt的mySQL driver编译安装

装个插件装一天的人你伤不起啊!

其实说起来过程也简单…但是因为文档和实际情况有出入,折腾了这么久…

下面是step by step:

1.下载Qt的源代码,假设放在$QtDir里.并且确保电脑上已经装上mySQL了,如果你和我一样用安装包安装的话,mySQL应该是装在/usr/local/mysql的.要搞清楚这些文件的存放位置,下面要用到

2.在终端上定位到$QtDir/src/plugins/sqldrivers/mysql/下,输入(根据mySQL的安装位置不同,下面的include和libs的路径可能需要修改):

qmake "INCLUDEPATH+=/usr/local/mysql/include" "LIBS+=-L/usr/local/mysql/lib -lmysqlclient_r" mysql.pro -spec macx-g++ CONFIG+=build_all
make
make install

编译时可能会有类似这样的warning:

ld: warning: directory '/tmp/qt-stuff-6474/source/qt-everywhere-opensource-src-4.7.0/lib' following -L not found
ld: warning: directory '/tmp/qt-stuff-6474/source/qt-everywhere-opensource-src-4.7.0/lib' following -F not found

但这确实只是个warning而已

3.定位到/Developer/Applications/Qt/plugins/sqldrivers,这个也是用安装包安装时Qt的SQL driver默认位置(按情况修改),输入:

rm libqsqlmysql_debug.dylib
install_name_tool -change libmysqlclient.16.dylib /usr/local/mysql/lib/libmysqlclient.16.dylib libqsqlmysql.dylib

上面mySQL client的版本也要按需更改,需要的版本这样查看:

otool -L libqsqlmysql.dylib

完毕.

主要的经验有,以后在mac下用qmake要加参数-spec macx-g++,明确了各种include和libs的位置在哪里,以及…mac用户真是伤不起啊!windows有各种详细的step by step,linux用户估计直接apt-get神马的就可以…

好了,现在mac用户也有了…

读到第几句你心动了?看到哪里让你泪流满面?

参考了1,2,3