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類。

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