Qt:为什么QGraphicsView设置Antialiasing/SmoothPixmapTransform没生效?

QGraphicsView::setRenderHint有两个常用的选项:QPainter::AntialiasingQPainter::SmoothPixmapTransform,前者是用来打开反走样功能,后者用来在对图片进行缩放时启用线性插值算法而不是最邻近算法。然而这两个选项都有一些坑,想达到预期的效果的话得做一些额外的功课。

QPainter::Antialiasing和QOpenGLWidget

如果viewport被设置成了QOpenGLWidget控件的话,想要启用QPainter::Antialiasing,那QOpenGLWidget必须开启多重采样,否则反走样效果完全不生效。毕竟OpenGL默认的反走样手段就是多重采样(是否也是唯一的手段呢?),没开多重采样就没反走样很正常。不过这种情况下Qt连个警告提示都不会给,这就有点坑了。不过这个坑在Qt文档Graphics View Framework里有提到,那就怪自己没好好读文档吧。
如果viewport被设置成QWidget控件的话就没这个问题了,用CPU反走样有内存就可以了。

QPainter::SmoothPixmapTransform和QGraphicsPixmapItem

(这个比上面那个要坑。)如果没有特别的需求,往场景里面添加图片用QGraphicsScene::addPixmap就可以,这个方法会创建一个QGraphicsPixmapItem,然后添加到场景里面。

当我们放大场景时,已添加的图片也会跟着放大,这就涉及到一个问题:使用哪种插值算法进行放大?默认情况下使用的是最邻近算法,放大后会有马赛克效果。如果我们希望线性插值算法来使图像平滑一些,该怎么做呢?QGraphicsView的文档里面提到了QPainter::SmoothPixmapTransform,能够改变默认的插值算法。然而实际情况是,如果使用QGraphicsScene::addPixmap这种方式插入图片的话,这个选项是无效的!因为QGraphicsPixmapItem有另外一个属性transformationModeQGraphicsPixmapItem放大时的插值算法由这个属性决定,完全不受QPainter::SmoothPixmapTransform的影响。QGraphicsPixmapItem::paint是这么实现的:

void QGraphicsPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                                QWidget *widget)
{
    Q_D(QGraphicsPixmapItem);
    Q_UNUSED(widget);

    painter->setRenderHint(QPainter::SmoothPixmapTransform,
                           (d->transformationMode == Qt::SmoothTransformation));

    painter->drawPixmap(d->offset, d->pixmap);

    if (option->state & QStyle::State_Selected)
        qt_graphicsItem_highlightSelected(this, painter, option);
}

不管传入的painterrenderHint是什么,都会被覆盖掉。那这样的话QPainter::SmoothPixmapTransform就形同虚设了,除非自己实现一个管理图片的QGraphicsItem类。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章