一种使用Qt快速绘图的思路

Qt具有强大的绘图功能,相信熟悉Qt的人都有这个体会,再加上一个基于Qt的绘图库,使得绘制各种图形都更加方便,比如qwt,应该是接触的比较多的。Qt本身的Graphic Model/View,在一些方面更加方便。在此,我想说一下下面这种样式图的画法思路。

一种使用Qt快速绘图的思路_第1张图片

来分析下图,不同像素颜色不同(或者相同)。一般不同像素都有实际意义,或者对应有实际的计算方法,可以取到某个坐标位置的图的颜色(一般取到的是某中强度值,然后根据这个强度值去查颜色表,本篇以后提到坐标对应的值都表示为强度)。并且,一般来说,二维图形都会支持缩放。这样会带来一个问题,不同缩放比例下需要计算对应的实际坐标(我们称之为世界坐标)是不同的。这样就需要一个世界坐标和像素坐标的转换,我们不在此讨论坐标转换的实现问题。假设这种转换关系我们已经知道了,我们现在只关注如何绘制的问题。

先来看下Qt中有哪些可以用的工具。熟悉Qt的人都知道,双缓冲的速度要快。而双缓冲的实现就是依赖于在内存中构建一个QImage(或者QPixmap等)对象,对它进行绘制,然后显示这个对象。我们就这么做,首先构建一个QImage。QImage的大小如何确定?可以取当前视口的设备坐标范围,也就是像素坐标范围。大小有了,就该填充值了。看下QImage的方法:

uchar *	scanLine ( int i )
可以取到一行的像素,数组赋值的速度要快的多,我们就采用此法。

归纳下思路:取适口范围-->转换成世界坐标-->取(强度)值-->数组赋值。

为了加快速度,还可以用Qt的QtConcurrent来分多线程填充像素。

QFuture QtConcurrent::run ( Function function, ... )

Runs function in a separate thread. The thread is taken from the global QThreadPool. Note that the function may not run immediately; the function will only be run when a thread is available.

这种按照像素填充的方式适用的地方还是挺多的。

再考虑一下,如果转换的代价很大(比如很耗时),可以对数据采样后取色填充,比如,现在数据源变化了,改为从一个图中取值,可以不再逐个像素填充,我们就可以分块来填充,兼顾质量和速度。

补充点代码片段:

#include "testimage.h"
#include 
#include 
#include 
#include 

TestImage::TestImage(QWidget *parent, Qt::WFlags flags)
	: QMainWindow(parent, flags)
{
	ui.setupUi(this);
}

TestImage::~TestImage()
{

}
namespace
{
	class TmpClass
	{
	public:
		TmpClass(QImage* image)
			:m_image(image), m_len(image->bytesPerLine()){}
		QImage* m_image;
		int m_len;
		void operator()(uchar* data)
		{
			//uchar* data = m_image->scanLine(index);
			int cnt = m_len / 4;//m_image->bytesPerLine() / 4;
			for (int i = 0; i < cnt; ++i)
			{
				data[i * 4] = qrand() % 255;
				data[i * 4 + 1] = qrand() % 255;
				data[i * 4 + 2] = qrand() % 255;
				data[i * 4 + 3] = 0xff;
			}
		}
	};
}
void renderImage( int index  )
{

}


void TestImage::paintEvent( QPaintEvent *event )
{
	QPainter painter(this);
	painter.save();

	int w = this->width();
	int h = this->height();
	QImage  image(w, h, QImage::Format_ARGB32);
	QVector vec(h);
	int sz = image.bytesPerLine();
	for (int i = 0; i < vec.size(); i++)
	{
		uchar* data = image.scanLine(i);
		vec[i] = data;
	}
	QFuture results = QtConcurrent::map(vec, TmpClass(&image));
	results.waitForFinished();
	painter.drawImage(0, 0, image);
	painter.restore();
}


你可能感兴趣的:(Qt)