wangwenx190 / framelesshelper

Project moved to: https://github.com/stdware/qwindowkit Cross-platform window customization framework for Qt Widgets and Qt Quick. Supports Windows, Linux and macOS.
MIT License
845 stars 203 forks source link

切换到FullScreen的时候原生窗体会一闪而过 #145

Open kylix opened 2 years ago

kylix commented 2 years ago

为了能切换到FullScreen,在examples下的Quick的MainWindow.qml加了以下代码:

    Action {
        shortcut : "F11"
        onTriggered : {
            if (window.visibility !== Window.FullScreen) {
                window.showFullScreen()
            } else {
                window.showNormal()
            }
        }
    }

或者使用FramelessWindow的toggleFullScreen

    Action {
        shortcut : "F11"
        onTriggered :  window.toggleFullScreen()
    }

然后在切换的时候能很看到原生窗体一闪而过,非常短的瞬间,但还是肉眼可见(按F11),操作系统是Win11。

wangwenx190 commented 2 years ago

是的,这是进入全屏和退出全屏时QPA会调整窗口样式导致的,这个应该不好在FramelessHelper层面解决,而且能不能解决也是未知数,毕竟我觉得也不是bug

kylix commented 2 years ago

谢谢,也许我试下用windows api实现一个showFullScreen能绕过这个问题

wangwenx190 commented 2 years ago

能解决的话也告诉我一下,我看看能不能整合到framelesshelper中

kylix commented 2 years ago

好的

be-water-myFriend commented 2 years ago

我觉得这个现象很影响用户体验,毕竟全屏播放在视频播放器类应用是刚需, 但全屏切换闪烁原生窗口这个体验很差,类比其它qq影音或者vlc、potplayer则没有这种现象。

wangwenx190 commented 2 years ago

我觉得这个现象很影响用户体验,毕竟全屏播放在视频播放器类应用是刚需, 但全屏切换闪烁原生窗口这个体验很差,类比其它qq影音或者vlc、potplayer则没有这种现象。

@ZhouYing-bit 我可以试着解决,不过大概率不能使用Qt自身的接口来切换全屏状态了

wangwenx190 commented 2 years ago

我研究了一下Windows Terminal的代码,发现其切换全屏的代码的逻辑与行为,与Qt并无明显差异,而且Windows Terminal的代码中,也用注释明确表示,切换全屏状态时,会有Vista风格的窗口一闪而过。而且经过我的实验,很多程序在切换全屏时,都存在这个问题,包括一些有名的多媒体播放器(例如MPC系列),看来不是Qt自身的问题,更不是FramelessHelper导致的。不过确实有些程序是没有这个问题的。想要解决这个问题,还需要进一步研究。

be-water-myFriend commented 2 years ago

https://github.com/qtdevs/FramelessHelper 我测试过这个项目, 它在showFullScreen 和 showNormal 之间切换没有原生窗口闪烁问题。

wangwenx190 commented 2 years ago

https://github.com/qtdevs/FramelessHelper 我测试过这个项目, 它在showFullScreen 和 showNormal 之间切换没有原生窗口闪烁问题。

好的,我去研究下

wangwenx190 commented 2 years ago

研究了一段时间,暂时没发现是什么导致的,还需要进一步研究。

wangwenx190 commented 2 years ago

大概知道怎么回事了,但不好解决。问题根源出在我们隐藏标题栏的方式,要彻底解决这个问题,就只能用Qt::FramelessWindowHint那个方案,缺点比较多,我还是不倾向于使用它。

be-water-myFriend commented 2 years ago

Qt::FramelessWindowHint方案在windows上主要是有什么缺点

wangwenx190 commented 2 years ago

只要开启Qt::FramelessWindowHint,Qt就会把窗口变为分层窗口(Layered Window),这在很多情况下都会显著降低图形绘制性能。而且有Qt::FramelessWindowHint这个flag时Qt绘制窗口用的是分层窗口专用的UpdateLayeredWindowIndirect,没有那个flag时,Qt绘制窗口用的是BitBlt,所以这两种情况Qt绘制窗口的方式也完全不一样。Qt的这两个行为(分层/不分层 + 绘制方式不同)是完全无法从外部进行干预的,我们没有办法阻止Qt去这么做。

而且Qt::FramelessWindowHint会导致窗口在去掉标题栏后,丢失窗口的原生阴影以及窗口动画(最大化/最小化时那个动画),不过幸运的是这两个东西都可以通过一定的技巧重新启用。

不过分层窗口有个额外的好处,就是可以在窗口中绘制透明区域,从而制作异形窗口或半透明窗口。

具体为什么启用Qt::FramelessWindowHint之后,切换全屏时就没有那个Vista风格的窗口了,其根本原因我还未知,但我能确认就是这个导致的。

所以你看有些软件切换全屏时有同样的问题,有些则没有,也是由于它们所隐藏标题栏的方式不同所导致的。

be-water-myFriend commented 2 years ago

明白了,感谢大佬细致的讲解。

wangwenx190 commented 1 year ago

这个问题难办,而且很多自定义边框的软件也都存在这个问题,估计短时间内没法解决。

其根源是我们是通过扩大客户区遮住了原本的标题栏,在切换全屏与窗口状态时,有一瞬间标题栏没有及时被客户区遮住,从而看到了原生窗口,也就是原本的标题栏。

而使用Qt::FramelessWindowHint这个flag会导致窗口样式被Qt修改,最终得到一个特殊的没有边框的窗口,Windows不会为此类窗口绘制标题栏,所以不存在上述问题。但由于这个做法缺点更多,所以我没有选用这个方案。