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