Qt实现漏斗图

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






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QT是一个跨平台的图形用户界面开发框架,可以用于实现各种应用程序,包括图形图像编辑器。 首先,我们可以使用QT的图形视图框架来构建图形图像编辑器的界面。可以使用QT自带的控件来实现工具栏、菜单栏、绘图区域等界面元素。通过QT的信号槽机制,可以实现用户对界面的操作响应,例如点击菜单项或者按钮时触发相应的功能。 其次,为了实现图形图像编辑的功能,需要基于QT提供的绘图API进行开发。通过使用QT的绘图函数,可以实现在绘图区域上绘制各种图形,如直线、矩形、圆形等。可以通过监听鼠标事件、键盘事件等来捕捉用户的操作,例如拖动鼠标绘制直线或者移动图形。 此外,图形图像编辑器还可以提供一些额外的功能,如选择、变换、编辑等。可以通过使用QT的图形视图框架来实现图形的选择、移动、缩放等操作。可以使用QT的图像处理函数,如旋转、裁剪、滤镜等来实现图像的编辑功能。 最后,为了提升用户体验,可以结合QT的其他功能,如撤销/重做功能、多文档支持、拖放操作等。这些功能可以通过使用QT的相关类库或者自定义类来进行开发。 总而言之,QT提供了丰富的工具和功能,可以方便地实现图形图像编辑器。通过使用QT的图形视图框架、绘图API和其他相关功能,可以创建一个功能完善的图形图像编辑器,满足用户的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值