PyQt5 / PyQt

PyQt Examples(PyQt各种测试和例子) PyQt4 PyQt5

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[问题] FramelessWindow Bug 无边框窗体Bug

ConyKitty opened this issue · comments

Environment : / 环境

  • OS: [e.g. Win 11]
  • Python [e.g. 3.6.2 X32]
  • PyQt5 [e.g. 5.15.2]

在用PyQt实现无边框带阴影的窗体时,用到了两种方式,分别都遇到了Bug,请帮忙看下:

方案1 Bug

采用Qt实现阴影, 具体代码如库中NewFramelessWindow.py, 此方案有个Bug:点击标题栏,整个窗体会失去对鼠标的响应,例如按钮悬停等状态不会更新。然后如果拖动一下窗体,或者单击一下标题栏之外的区域,界面对鼠标的相应又会恢复正常。

方案2 Bug

采用实现实现nativeEvent方式,采用Window系统实现阴影,拦截WM_NCCALCSIZE事件隐藏标题栏。参考链接QT自绘标题和边框NativeEvent python demo
此方案的bug是多屏的副屏中,无论鼠标在哪,总是在resize箭头光标的状态,不能点击任何控件和拖动,在主屏上就没有问题。前面参考1中已经提到这个问题,但是我对C++编程和Windows这些API不太懂,能否麻烦给个下列副屏问题的python的实现方式?

当程序在辅屏上时,它的screen是辅屏,如果当前screen不等于QGuiApplication::primaryScreen(主屏),则不设置MINMAXINFO结构,但是由于它已经处理了WM_GETMINMAXINFO消息,导致这个消息不会被系统默认的窗口处理函数处理(DefWindowProc),所以才会显示不完整,解决办法是优先响应WM_GETMINMAXINFO消息,让后交给系统默认的窗口处理函数进行处理。

另外方案2中的全屏时显示不全问题,我没有用看懂文中C++代码中实现最大化时添加margin的方式,但是我仿照方案1中,用qt的changeEvent实现最大化添加了margin,也能解决问题。只是这个margin的值是试出来的,让窗体刚好全屏,具体应该设置多少从哪里看不清楚。

case WM_GETMINMAXINFO:
    {
        if (::IsZoomed(msg->hwnd)) {
            // 最大化时会超出屏幕,所以填充边框间距
            RECT frame = { 0, 0, 0, 0 };
            AdjustWindowRectEx(&frame, WS_OVERLAPPEDWINDOW, FALSE, 0);
            frame.left = abs(frame.left);
            frame.top = abs(frame.bottom);
             this->setContentsMargins(frame.left, frame.top, frame.right, frame.bottom);
        }
        else {
            this->setContentsMargins(2, 2, 2, 2);
        }

        *result = ::DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
        return true;
    }
    def changeEvent(self, event):
        """窗口状态改变
        :param event:
        """
        # 窗口状态改变时修改标题栏控制按钮
        if event.type() == 105:  # WindowStateChange
            if self.isMaximized():
                self.gridLayout_3.setContentsMargins(10, 10, 10, 10)  # 这个margin设多少?全屏显示不全,超出屏幕的尺寸具体是多少?
            else:
                self.gridLayout_3.setContentsMargins(0, 0, 0, 0)

补充添加Gif说明下。
方案1bug:
FramelessWindow bug
方案2bug:
重新实现nativeEvent 副屏bug

commented

初步调试了下 bug 1.
1、按下鼠标后立即放开,发现窗口并没有收到鼠标释放事件
2、按下鼠标后过一段时间放开,窗口可以收到鼠标释放事件,此时右侧按钮悬停正常
3、按下鼠标立即放开,并触发一个临时的定时器。应该可以模拟鼠标右键在标题栏处按下释放,应该可以解决问题。还待研究

commented

bug2 已修复原demo中的鼠标坐标获取。
另外可以参考这个比较完整的实现:https://github.com/zhiyiYo/PyQt-Frameless-Window

bug2 已修复原demo中的鼠标坐标获取。 另外可以参考这个比较完整的实现:https://github.com/zhiyiYo/PyQt-Frameless-Window

这里我尝试运行Example下的Demo,全都没有运行成功,Window实例化时报错:zhiyiYo/PyQt-Frameless-Window#39