4

我正在将应用程序从 MFC 迁移到 Qt。

MFC 应用程序将使用 GDI 调用来构建窗口(基本上是一个图表)。它将绘制到内存位图后台缓冲区,然后将 BitBlt 绘制到屏幕上。然而,Qt 已经做了双缓冲。

当用户在图表中单击并拖动时,我希望窗口的该部分被反转。

我想找到最好的方法来做到这一点。有没有办法做一些像从小部件的后台缓冲区而不是屏幕抓取的东西?...也许是 BitBlt(..., DST_INVERT) 等价物?

我在 QPainter 中看到了 setCompositionMode(),但文档说这只适用于在 QImage 上操作的画家。(否则,我可以使用精美的合成模式将实心矩形图像合成到我的小部件上,以获得类似反转效果的效果)

我可以做与 MFC 相同的事情,绘制到 QImage 后台缓冲区......但我读到硬件加速可能无法以这种方式工作。重新实现 Qt 中已经提供给您的双缓冲似乎是一种浪费。我也不太确定关闭小部件的双缓冲可能会产生什么副作用(以避免三重缓冲)。

有一次,我有一个令人费解的 QPixmap::grabWidget() 调用,并带有防止递归的标志来保护它,但这会将所有内容渲染两次,并且显然比仅绘制到 QImage 更糟糕。(并且在文档中特别警告过)

我是否应该放弃并将所有内容绘制到 QImage 上,就像我在 MFC 中所做的那样?

编辑:

好的,QPixmap 画家的运行速度与现在的直接运行速度大致相同。因此,使用 QPixmap 后台缓冲区似乎是最好的方法。

解决方案对我来说并不明显,但如果我查看更多示例(例如 Ariya 的 Monster 演示),我可能会按照预期的方式对其进行编码,并且效果会很好。

这就是区别。我看到了使用这个的帮助系统演示:

    QPainter painter(this)

在paintEvent() 的开始。因此,我似乎很自然地认为,将缓冲区加倍到 QPixmap 然后在屏幕上绘制,您需要这样做:

    QPainter painter(&pixmap);
    QPainter painterWidget(this);
    ...  draw using 'painter' ...
    painterWidget.drawPixmap(QPoint(0,0), pixmap);

实际上,您显然应该这样做:

    QPainter painter;
    painter.begin(&pixmap);
    ... draw using 'painter' ...
    painter.end();
    painter.begin(this);
    painter.drawPixmap(QPoint(0,0), pixmap);
    painter.end();

我可以看到我的方式同时有两个活跃的画家。我不完全确定为什么它更快,但直觉上我更喜欢后者。它是一个单一的 QPainter 对象,一次只做一件事。也许有人可以解释为什么第一种方法不好?(就 Qt 渲染引擎中的错误假设而言)

4

3 回答 3

4

假设你真的不想从你的屏幕外缓冲区像素值(而是只是在它上面再次绘制一些东西并再次blit到屏幕上),你应该使用QPixmap作为缓冲区,而不是QImage。使用后者会禁用所有绘画加速,因为 Qt 使用其软件光栅引擎回退,因此使用 QPixmap。如果您使用 OpenGL 图形系统,您仍然可以从中受益。

有关如何执行此操作的示例,请查看我运行 Monster 演示的最后代码,它需要有一个屏幕外像素图,以通过使用源超过合成模式重复绘制来产生运动模糊效果。

要禁用 Qt 的后备存储(这通常不是一个好主意),请将Qt::WA_PaintOnScreen用于您的顶级小部件。

有点不相关,但您可能想看看QRubberBand小部件。

于 2009-05-22T11:37:16.337 回答
4

在图形区域顶部绘图,您应该能够使用合成模式进行反转。使用差异合成模式绘制白色。以下示例是显示像素图的 QLabel 的子类:

void Widget::paintEvent(QPaintEvent *pe)
{
    // make sure we paint background
    QLabel::paintEvent(pe);

    // paint the overlay
    if (!selectionRect.isNull()) {
        QPainter p(this);
        p.setCompositionMode(QPainter::CompositionMode_Difference);
        p.fillRect(selectionRect,QColor("#FFFFFF"));
    }
}

替代文字 http://chaos.troll.no/~hhartz/yesManInverted.png

于 2009-05-22T13:02:54.200 回答
0

我所知道的最简单、最直接的答案是像以前一样对 QImage 进行操作,并使用 QImage 作为屏幕上小部件的源。

另一种选择可能是在您的图表上添加一个透明小部件,它只绘制图表的倒置部分。但是,我认为这根本不会优化绘图。它可能会导致绘制底层图形,然后是倒置部分的叠加。

于 2009-05-21T17:39:18.457 回答