Qt实现漏斗图
程序员文章站
2022-05-26 21:41:26
...
利用Qt的QPainter实现漏斗图。本例子采用了两种不同的方式,一种是按照高度比例,一个按照宽度比例。
效果如下:
代码如下:
cfunnelplot.h
#ifndef CFUNNELPLOT_H
#define CFUNNELPLOT_H
#include <QtGui/QWidget>
#include <QPainter>
#include <QMap>
#include <QPolygonF>
//
//漏洞图的实现
//只实现3-4(为了好看)
//
typedef struct FunnelData
{
QString titlestr;
float fvalue;
QColor color;
}FunnelData;
class CFunnelPlot : public QWidget
{
Q_OBJECT
public:
CFunnelPlot(QWidget *parent = 0, Qt::WFlags flags = 0);
~CFunnelPlot();
void setTitle(QString titlestr,int pox = 0); //0为上,1为下 -1为不显示(其他值也不显示)
void appendData(float v, QString title ,QColor color);
void appendData(float v,QString title);
void setType(int type = 0); // 类型0 为按照宽度(m_width)划分比例,1 按照高度(m_height)划分比例
void setLegendPos(int pos = 0); //0中间 1 右侧 -1 左侧
private:
inline void initdata();
inline float getSum();
protected:
void paintEvent(QPaintEvent *);
void paintByWidth(QPainter &painter);
void paintByHeigth(QPainter &painter);
void painterLegend(QPainter &painter);
void painterTitle(QPainter &painter);
private:
int m_width, m_heigth;
QPointF m_topcertp;
QMap<int,FunnelData> m_datamap;
QList<QColor> m_colorlist;
int m_type;
int m_legendpos;
QString m_titlestr;
int m_titlepos;
};
#endif // CFUNNELPLOT_H
cfunnelplot.cpp
#include "cfunnelplot.h"
CFunnelPlot::CFunnelPlot(QWidget *parent, Qt::WFlags flags)
: QWidget(parent, flags)
{
//////////////////////////////////////////////////////////////////////////
m_colorlist.append(QColor("#B8B06C"));
m_colorlist.append(QColor("#BD2799"));
m_colorlist.append(QColor("#F6BD0E"));
m_colorlist.append(QColor("#05AA67"));
m_colorlist.append(QColor("#3408AF"));
m_colorlist.append(QColor("#980A0A"));
m_colorlist.append(QColor("#007CF8"));
m_colorlist.append(QColor("#7A6864"));
m_colorlist.append(QColor("#4D84AF"));
m_colorlist.append(QColor("#39B708"));
m_colorlist.append(QColor("#F6BD0E"));
m_colorlist.append(QColor("#D64646"));
//////////////////////////////////////////////////////////////////////////
setType(1);
setLegendPos(0);
setTitle("2333sikdasa",0);
//测试
appendData(100,"test1");
appendData(90,"test2");
appendData(50,"test3");
appendData(20,"test4");
}
CFunnelPlot::~CFunnelPlot()
{
}
void CFunnelPlot::setType( int type /*= 0*/ )
{
m_type = type;
}
void CFunnelPlot::setLegendPos( int pos /*= 0*/ )
{
m_legendpos = pos;
}
void CFunnelPlot::appendData( float v , QString title)
{
int index = m_datamap.count();
if (index > m_colorlist.count())
{
appendData(v,title,m_colorlist.at(0));
}
else
appendData(v,title,m_colorlist.at(index));
}
void CFunnelPlot::appendData( float v, QString title ,QColor color )
{
int index = m_datamap.count();
FunnelData d;
d.color = color;
d.fvalue = v;
d.titlestr = title;
m_datamap.insert(index,d);
}
void CFunnelPlot::setTitle( QString titlestr,int pox /*= 0*/ )
{
m_titlestr = titlestr;
m_titlepos = pox;
}
//////////////////////////////////////////////////////////////////////////
void CFunnelPlot::initdata()
{
m_width = width()*0.8;
m_heigth = height()*0.8;
m_topcertp = QPointF(width()/2,height()*0.1);
}
void CFunnelPlot::paintEvent( QPaintEvent * )
{
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing);
//painter.setPen(Qt::NoPen);
initdata();
if (m_type == 0)
{
paintByWidth(painter);
}else
{
paintByHeigth(painter);
painterLegend(painter);
}
painterTitle(painter);
}
float CFunnelPlot::getSum()
{
float sum;
for (int i = 0; i < m_datamap.count(); ++i)
{
sum += m_datamap.value(i).fvalue;
}
return sum;
}
void CFunnelPlot::paintByWidth( QPainter &painter )
{
int pcount = m_datamap.count();
if (pcount == 0) return;
int h = m_heigth/pcount;
float sum = getSum();
float topw = m_width;
float bottomw = 0;
QFont font;
font.setPointSize(h/5);
painter.setFont(font);
for (int i = 0 ; i < pcount ; ++i)
{
painter.save();
FunnelData d = m_datamap.value(i);
bottomw = d.fvalue*m_width/sum;
QPointF Lefttopp(m_topcertp.x()-topw/2,m_topcertp.y()+h*i);
QPointF righttopp(m_topcertp.x()+topw/2,m_topcertp.y()+h*i);
QPointF Leftbottomp(m_topcertp.x()-bottomw/2,m_topcertp.y()+h*i+h);
QPointF rightbottomp(m_topcertp.x()+bottomw/2,m_topcertp.y()+h*i+h);
QPolygonF poly;
poly << Lefttopp << Leftbottomp << rightbottomp << righttopp;
painter.setBrush(d.color);
painter.drawPolygon(poly);
QRect trect(m_topcertp.x()-m_width/2,Lefttopp.y(),m_width,h);
painter.drawText(trect,Qt::AlignCenter,d.titlestr);
painter.restore();
topw = bottomw;
}
}
void CFunnelPlot::paintByHeigth( QPainter &painter )
{
int pcount = m_datamap.count();
if (pcount == 0) return;
int h = m_heigth/pcount;
float sum = getSum();
float toph = 0;
int h3 = m_heigth*0.65;
int w3 = m_width*0.4;
QFont font;
font.setPointSize(h/5);
painter.setFont(font);
QPointF midleftp(m_topcertp.x()-w3/2,m_topcertp.y()+h3);
QPointF midrightp(m_topcertp.x()+w3/2,m_topcertp.y()+h3);
float oldw = (m_width-w3)/2;
for (int i = 0 ; i < pcount ; ++i)
{
painter.save();
FunnelData d = m_datamap.value(i);
float bottomh = d.fvalue*m_heigth/sum;
float tmph = h3 - toph - bottomh;
float tmpw = tmph/h3*(m_width-w3)/2;
QPolygonF poly;
QRect trect;
if (toph > h3)
{
QPointF Lefttopp(m_topcertp.x()-w3/2,m_topcertp.y()+toph);
QPointF righttopp(m_topcertp.x()+w3/2,m_topcertp.y()+toph);
QPointF Leftbottomp(m_topcertp.x()-w3/2,m_topcertp.y()+toph+bottomh);
QPointF rightbottomp(m_topcertp.x()+w3/2,m_topcertp.y()+toph+bottomh);
poly << Lefttopp << Leftbottomp << rightbottomp << righttopp;
trect = QRect(m_topcertp.x()-m_width/2,Lefttopp.y(),m_width,bottomh);
}
else if ( toph+bottomh > h3 && toph < h3)
{
QPointF Lefttopp(m_topcertp.x()-w3/2-oldw,m_topcertp.y()+toph);
QPointF righttopp(m_topcertp.x()+w3/2+oldw,m_topcertp.y()+toph);
QPointF Leftbottomp(m_topcertp.x()-w3/2,m_topcertp.y()+toph+bottomh);
QPointF rightbottomp(m_topcertp.x()+w3/2,m_topcertp.y()+toph+bottomh);
poly << Lefttopp << midleftp << Leftbottomp << rightbottomp << midrightp << righttopp;
trect = QRect(m_topcertp.x()-m_width/2,Lefttopp.y(),m_width,bottomh);
}
else
{
QPointF Lefttopp(m_topcertp.x()-w3/2-oldw,m_topcertp.y()+toph);
QPointF righttopp(m_topcertp.x()+w3/2+oldw,m_topcertp.y()+toph);
QPointF Leftbottomp(m_topcertp.x()-w3/2-tmpw,m_topcertp.y()+toph+bottomh);
QPointF rightbottomp(m_topcertp.x()+w3/2+tmpw,m_topcertp.y()+toph+bottomh);
poly << Lefttopp << Leftbottomp << rightbottomp << righttopp;
trect = QRect(m_topcertp.x()-m_width/2,Lefttopp.y(),m_width,bottomh);
}
painter.setBrush(d.color);
painter.drawPolygon(poly);
//painter.drawText(trect,Qt::AlignCenter,d.titlestr);
painter.restore();
oldw=tmpw;
toph += bottomh;
}
}
void CFunnelPlot::painterLegend( QPainter &painter )
{
int pcount = m_datamap.count();
if (pcount == 0) return;
int h = m_heigth/pcount;
float sum = getSum();
float toph = 0;
int mid_h = m_heigth*0.65;
int mid_w = m_width*0.4;
painter.save();
QFont font;
font.setPointSize(h/5);
painter.setFont(font);
int strlenth = font.pointSize();
float oldw = (m_width-mid_w)/2;
for (int i = 0 ; i < pcount ; ++i)
{
FunnelData d = m_datamap.value(i);
float bottomh = d.fvalue*m_heigth/sum;
float tmph = mid_h - toph - bottomh;
float tmpw = tmph/mid_h*(m_width-mid_w)/2;
int wlength = 0;
QPointF starp = QPointF(m_topcertp.x(),m_topcertp.y()+toph);
if (toph > mid_h)
{
;
}
else if ( toph+bottomh > mid_h && toph < mid_h)
{
wlength = oldw/2+tmpw/2;
}
else
{
wlength = oldw/2+tmpw/2;
}
if (m_legendpos == 1)
{
QRect nrect(starp.x()+mid_w+tmpw/2,starp.y(),m_width*0.1+strlenth,bottomh);
painter.drawText(nrect,Qt::AlignVCenter,d.titlestr);
QPointF midp(m_topcertp.x()+mid_w/2+wlength,nrect.topLeft().y()+nrect.height()/2);
QPointF midp2(nrect.x(),nrect.topLeft().y()+nrect.height()/2);
painter.drawLine(midp,midp2);
}
else if (m_legendpos == -1)
{
QRect nrect(starp.x()-m_width/2-tmpw/2-strlenth,starp.y(),m_width*0.1+strlenth,bottomh);
painter.drawText(nrect,Qt::AlignLeft|Qt::AlignVCenter,d.titlestr);
QPointF midp(starp.x()-mid_w/2-wlength,nrect.topLeft().y()+nrect.height()/2);
QPointF midp2(nrect.topRight().x(),nrect.topLeft().y()+nrect.height()/2);
painter.drawLine(midp,midp2);
}
else
{
QRect nrect(starp.x()-m_width/2,starp.y(),m_width,bottomh);
painter.drawText(nrect,Qt::AlignCenter ,d.titlestr);
}
oldw=tmpw;
toph += bottomh;
}
painter.restore();
}
void CFunnelPlot::painterTitle( QPainter &painter )
{
painter.save();
int h = height()*0.05;
QFont font;
font.setPointSize(h);
painter.setFont(font);
if (m_titlepos == 0) //上
{
QRect rect(0,0,width(),height()*0.09);
painter.drawText(rect,Qt::AlignCenter, m_titlestr);
}
else if (m_titlepos == 1) //为下
{
QRect rect(0,height()*0.905,width(),height()*0.1);
painter.drawText(rect,Qt::AlignCenter, m_titlestr);
}
painter.restore();
}
上一篇: markdown的基础语法