Qt在绘制point的时候,一般都直接调用addPoint()函数,但是在point数量达到一定程度的时候,会发生很严重的卡顿现象,比如,绘制10w个point,绘制100w个point(point的无序的)
以10w个point为测试,
QTime time;
time.start();
for(int i=0;i<100000;i++){
QGraphicsLineItem* item = new QGraphicsLineItem(50+i*0.5,50+i*0.5,100+i*0.5,50+i*0.5);
mScene->addItem(item);
// QGraphicsLineItem* item = mScene->addLine(50+i*0.5,50+i*0.5,100+i*0.5,50+i*0.5);
}
qDebug()<<"time elapsed: "<<time.elapsed();
上面的代码运行后,显示耗时达到15s,这是直接使用Qt本身的addPoint()方法,之所以需要如此长的时间,主要是因为,每一个点在绘制的时候,都会new一个painter去绘制,绘制结束后再去吧painter释放掉,导致的。
下面是自己封装的point控件中的paint()和boundingRect()函数的重写
QRectF PointItem::boundingRect() const
{
if(pointNumber == single){
return QRectF(m_x,m_y,0,0);
}else if(pointNumber == multiple){
//测试rect
QList<qreal> lstX,lstY;
lstX = m_lstX;lstY = m_lstY;
qSort(lstX.begin(), lstX.end());
qSort(lstY.begin(), lstY.end());
return QRectF(lstX[0],lstY[0],lstX[lstX.count()-1],lstY[lstY.count()-1]);
}
}
void PointItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(widget)
Q_UNUSED(option)
int cnt = this->scene()->views().count();
for (int i =0;i<cnt;i++)
{
QGraphicsView *view = this->scene()->views().at(i);
QMatrix matrix = view->matrix();
qreal scale = matrix.m11();
qreal width = penWidth/scale;
painter->setPen(QPen(QBrush(penColor),width));
if(pointNumber == single){
painter->drawPoint(m_x,m_y);
}else if(pointNumber == multiple){
for(int j=0;j<m_lstX.count();j++){
painter->drawPoint(m_lstX[j],m_lstY[j]);
}
}
}
}
当需要绘制多个点的时候,直接在paint()函数中使用同一个painter进行绘制,经过测试这种方法绘制耗时大概在150ms左右。这里要说明的一点是,在boundingRect()函数中,我对点的坐标进行排序,当我不排序的时候,整个绘制耗时大概在20ms左右,必须要对点进行排序,因为点是无序的,我们需要对控件的有效绘制区域进行设置,排序所占用的时间,是不可以避免的。但是就算如此,也比官方的绘制优化了100倍左右的时间,(为了更好地效率,可以在绘制之前,对点的坐标进行先排序,但是这一部分的资源占用还是存在,只是被移到其他部分去了)
测试结果截图放在下面。
如有问题,勿喷。只是工作上遇到的问题,进行优化后的总结和分享。
上述方法还有一个优化的地方,就是,qSort()函数,其实我只需要获得最大值最小值即可,不需要进行排序。测试后,确实可以节省很多时间