代码之家  ›  专栏  ›  技术社区  ›  darron

qt和双缓冲-有没有任何巧妙的技巧来捕捉像素或操作后缓冲?

  •  3
  • darron  · 技术社区  · 15 年前

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

    MFC应用程序将使用GDI调用来构造窗口(基本上是一个图形图)。它将绘制一个内存位图后缓冲区,然后将其位置到屏幕上。然而,qt已经进行了双重缓冲。

    当用户点击并拖动图表时,我希望窗口的那个部分被反转。

    我想找到最好的方法。有没有一种方法可以像grabwindow()那样从小部件的后缓冲区而不是屏幕上进行抓取?…也许是一个bitblt(…,dst_invert)等价物?

    我在qpainer中看到了setcompositionmode(),但是文档说它只适用于在qimage上操作的油漆工。(否则,我可以用一种奇特的合成模式将一个实心矩形图像合成到小部件上,以获得类似反转效果的效果)

    我可以和MFC做同样的事情,在一个qimage的缓冲区中绘制…但我读到硬件加速可能不会这样工作。重新实现qt中已经提供给您的双缓冲似乎是浪费。我也不太确定关闭小部件的双重缓冲可能会有什么副作用(以避免三重缓冲)。

    有一次,我有一个复杂的qpixmap::grabwidget()调用,它带有防止标志保护它的递归,但它呈现了所有内容两次,明显比仅仅绘制一个qImage更糟糕。(文件中特别警告)

    我应该放弃一切画给一个齐玛吉做它基本上就像我在MFC?

    编辑:

    好吧,现在一个qpixmap绘制程序以与direct相同的速度运行。因此,使用qpixmap返回缓冲区似乎是最好的方法。

    这个解决方案对我来说并不明显,但是如果我看更多的例子(比如Ariya的怪物演示),我可能会按照预期的方式对它进行编码,并且会很好地工作。

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

        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();
    

    我可以看到我的方式有两个活跃的画家在同一时间。我不完全确定 为什么? 速度更快,但直觉上我更喜欢后者。它是一个单独的qpainer对象,一次只做一件事。也许有人能解释为什么第一种方法不好?(根据qt呈现引擎中的中断假设)

    3 回复  |  直到 15 年前
        1
  •  4
  •   Ariya Hidayat    15 年前

    假设您不想从屏幕外的缓冲区中对值进行像素化处理(但更确切地说,只需在缓冲区上重新绘制一些内容,然后再次将其显示到屏幕上),那么您应该使用qpixmap作为缓冲区,而不是qimage。使用后者将禁用所有绘制加速,因为qt使用其软件光栅引擎返回,因此使用qpixmap。如果您使用OpenGL图形系统,您仍然可以从中受益。

    有关如何执行此操作的示例,请检查 my last code on running the Monster demo ,它需要有一个屏幕外的像素映射,因为运动模糊的效果,通过重复的绘画源,而不是合成模式。

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

    有点不相关,但你可能想看看 QRubberBand 小装置。

        2
  •  4
  •   Henrik Hartz    15 年前

    在图形区域的顶部绘制时,您应该能够使用合成模式来反转。使用差异合成模式绘制白色。以下示例是显示pixmap的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"));
        }
    }
    

    alt text http://chaos.troll.no/~hhartz/yesManInverted.png

        3
  •  0
  •   Caleb Huitt - cjhuitt    15 年前

    我知道的最简单、最直截了当的答案是像你以前那样做,对一个qimage,并使用qimage作为屏幕上小部件的源。

    另一种选择可能是在图形上添加一个透明的小部件,它只绘制图形的反转部分。不过,我认为这根本无法优化绘图。它很可能会导致绘制底层的图形,然后是反向部分的叠加。