关于QT - QML - 窗口内控件出现闪烁的问题!

QT - QML - 窗口内控件出现闪烁的问题 ?


出问题的代码

该代码采用了 Control 1 模块的按钮

import QtQuick 2.14
import QtQuick.Controls 1.4
import QtQuick.Window 2.14

Window {  //使用Window会出现闪烁的问题,改成ApplicationWindow就没问题了。
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    
    ExclusiveGroup {
        id: naviGroup
    }
    Column {
        Button {
            id: page1
            checkable: true
            exclusiveGroup: naviGroup

            onCheckedChanged: {
                if(checked) {
                    console.log("1")
                }
            }
        }
        Button {
            id: page2
            checkable: true
            exclusiveGroup: naviGroup
        }
        Button {
            id: page3
            checkable: true
            exclusiveGroup: naviGroup
        }
        Button {
            id: page4
            checkable: true
            exclusiveGroup: naviGroup
        }
    }
}

问题

当我把根节点Window改成ApplicationWindow之后,闪烁的问题就不会出现了,我再次将ApplicationWindow改回Window之后,闪烁的问题就又出现了,所以为什么会出现闪烁的问题呢,为什么更换了窗口类型就不会出现闪烁呢?

闪烁问题预览

img

【以下回答由 GPT 生成】

这个问题可能是由于窗口的双缓冲机制导致的。在Qt中,Window和ApplicationWindow是不同的窗口类型,它们有不同的渲染方式和双缓冲机制。在你的代码中,当你将根节点的Window改成ApplicationWindow时,闪烁的问题消失了,这是因为ApplicationWindow使用了双缓冲机制来渲染窗口,可以避免闪烁的情况发生。

双缓冲是一种常用的解决闪烁问题的方法。它通过在后台缓冲区进行绘制,然后将绘制结果一次性刷新到前台窗口上,避免了直接在前台窗口绘制的过程中出现闪烁的问题。在你的代码中,当你使用ApplicationWindow时,Qt会自动处理双缓冲,所以你不再看到控件闪烁的现象。

但是,当你将ApplicationWindow改回Window时,窗口不再使用双缓冲机制,默认情况下会直接在前台窗口进行绘制。这可能会导致闪烁的问题重新出现。为了解决这个问题,你可以尝试手动启用双缓冲机制。下面是一种可能的解决方案:

import QtQuick 2.14
import QtQuick.Controls 1.4
import QtQuick.Window 2.14

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    flags: Qt.FramelessWindowHint | Qt.Window

    Item {
        width: parent.width
        height: parent.height

        DoubleBuffered {
            id: buffer
            width: parent.width
            height: parent.height

            Column {
                Button {
                    id: page1
                    checkable: true

                    onCheckedChanged: {
                        if (checked) {
                            console.log("1")
                        }
                    }
                }

                Button {
                    id: page2
                    checkable: true
                }

                Button {
                    id: page3
                    checkable: true
                }

                Button {
                    id: page4
                    checkable: true
                }
            }

            onPaint: {
                // 在缓冲区绘制所有的子项
                var painter = new QPainter()
                painter.begin(buffer)
                // 绘制背景色或背景图像
                painter.fillRect(buffer.rect, Qt.transparent)
                // 绘制子项
                buffer.children.forEach(function(child) {
                    painter.render(child)
                })
                painter.end()

                // 将缓冲区的绘制结果渲染到前台窗口
                painter.begin(viewport)
                painter.drawImage(viewport.rect, buffer.image, buffer.rect)
                painter.end()
            }
        }
    }
}

上述代码中使用了一个自定义的DoubleBuffered组件来手动启用双缓冲机制。该组件实际上是一个辅助项,它本身没有可见性,但它包含了一个和窗口一样大小的缓冲区(buffer),并且在onPaint事件中将所有的子项绘制到缓冲区中,最后再将缓冲区的绘制结果渲染到前台窗口中。

通过将你的控件放入DoubleBuffered组件中,并在onPaint事件中绘制到缓冲区中,可以避免直接在前台窗口中进行绘制,从而解决闪烁的问题。

希望这个解决方案对你有帮助。如果你还有其他问题,请随时向我提问。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^