欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt实现漏斗图

程序员文章站 2022-05-26 21:41:26
...

利用Qt的QPainter实现漏斗图。本例子采用了两种不同的方式,一种是按照高度比例,一个按照宽度比例。

效果如下:

Qt实现漏斗图


代码如下:

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();
}