阳子926 2024-08-19 19:44 采纳率: 33.3%
浏览 10

pyqt5, pywin32冲突问题

想用 PyQt5 做一个自定义标题栏和带系统边框的窗口,但在自定义标题栏时出现了问题:
  • 当鼠标拖动改变窗口大小,且鼠标在某个窗口元素上时,系统自带的窗口上部白边框就会强制显示,使用下面的代码也没用:
            if msg.message == win32con.WM_NCCALCSIZE:
                # 拦截不显示顶部的系统自带的边框
                return True, 0
  • 有什么方法可以解决此问题呢?
原代码:

import ctypes.wintypes
from ctypes.wintypes import POINT

import win32api
import win32con
import win32gui


from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QLabel
from PyQt5.QtWinExtras import QtWin


class MINMAXINFO(ctypes.Structure):
    _fields_ = [
        ("ptReserved", POINT),
        ("ptMaxSize", POINT),
        ("ptMaxPosition", POINT),
        ("ptMinTrackSize", POINT),
        ("ptMaxTrackSize", POINT),
    ]


class Window(QWidget):
    BorderWidth = 5

    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        # 主屏幕的可用大小(去掉任务栏)
        self._rect = QApplication.instance().desktop().availableGeometry(self)
        self.title_height = 30
        self.resize(800, 600)
        self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint |
                            Qt.WindowSystemMenuHint |
                            Qt.WindowMinimizeButtonHint |
                            Qt.WindowMaximizeButtonHint |
                            Qt.WindowCloseButtonHint)

        # 增加薄边框
        style = win32gui.GetWindowLong(int(self.winId()), win32con.GWL_STYLE)
        win32gui.SetWindowLong(int(self.winId()), win32con.GWL_STYLE,
                               style | win32con.WS_THICKFRAME)

        if QtWin.isCompositionEnabled():
            # 加上 Aero 边框阴影
            QtWin.extendFrameIntoClientArea(self, -1, -1, -1, -1)
        else:
            QtWin.resetExtendedFrame(self)

    def setWindowTitle(self, title: str):
        super().setWindowTitle(title)
        self.titleBar = QLabel(title, self)
        self.titleBar.setGeometry(self.title_height, 0, self.size().width(), self.title_height)

    def resizeEvent(self, a0):
        super().resizeEvent(a0)
        self.titleBar.setGeometry(self.title_height, 0, self.size().width(), self.title_height)
        
    def nativeEvent(self, eventType, message):
        retval, result = super(Window, self).nativeEvent(eventType, message)
        if eventType == "windows_generic_MSG":
            msg = ctypes.wintypes.MSG.from_address(message.__int__())
            # 获取鼠标移动经过时的坐标
            pos = QCursor.pos()
            x = pos.x() - self.frameGeometry().x()
            y = pos.y() - self.frameGeometry().y()
            # 判断鼠标位置是否有其它控件
            if self.childAt(x, y) != None:
                return retval, result
            if msg.message == win32con.WM_NCCALCSIZE:
                # 拦截不显示顶部的系统自带的边框
                return True, 0
            if msg.message == win32con.WM_GETMINMAXINFO:
                # 当窗口位置改变或者大小改变时会触发该消息
                info = ctypes.cast(msg.lParam,
                                   ctypes.POINTER(MINMAXINFO)).contents
                # 修改最大化的窗口大小为主屏幕的可用大小
                info.ptMaxSize.x = self._rect.width()
                info.ptMaxSize.y = self._rect.height()
                # 修改放置点的x,y坐标为0,0
                info.ptMaxPosition.x, info.ptMaxPosition.y = 0, 0
            if msg.message == win32con.WM_NCHITTEST:
                w, h = self.width(), self.height()
                lx = x < self.BorderWidth
                rx = x > w - self.BorderWidth
                ty = y < self.BorderWidth
                by = y > h - self.BorderWidth
                # 左上角
                if (lx and ty):
                    return True, win32con.HTTOPLEFT
                # 右下角
                if (rx and by):
                    return True, win32con.HTBOTTOMRIGHT
                # 右上角
                if (rx and ty):
                    return True, win32con.HTTOPRIGHT
                # 左下角
                if (lx and by):
                    return True, win32con.HTBOTTOMLEFT
                # 上
                if ty:
                    return True, win32con.HTTOP
                # 下
                if by:
                    return True, win32con.HTBOTTOM
                # 左
                if lx:
                    return True, win32con.HTLEFT
                # 右
                if rx:
                    return True, win32con.HTRIGHT
                # 标题
                if self.pos().y() <= QCursor.pos().y() <= self.pos().y() + self.title_height:
                    return True, win32con.HTCAPTION
        return retval, result


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    w = Window()
    w.setWindowTitle("123")
    w.show()
    sys.exit(app.exec_())

  • 写回答

1条回答 默认 最新

  • 一直免费一直爽 2024-08-19 19:45
    关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    从你的代码来看,你已经正确地使用了win32guiPyQt5库。但是,如果你遇到了冲突问题,可能是因为两个库之间的某些功能相互干扰。在这种情况下,你可以尝试以下方法来解决问题:

    1. 确保你安装了正确版本的pywin32库。你可以使用以下命令来安装或更新pywin32库:
    pip install --upgrade pywin32
    
    1. 在你的代码中,尝试将win32gui相关的操作放在nativeEvent方法之外,以避免与PyQt5的事件处理机制发生冲突。例如,你可以在Window类的__init__方法中添加以下代码:
    import win32gui
    import win32con
    
    # ...
    
    class Window(QWidget):
        # ...
    
        def __init__(self, *args, **kwargs):
            # ...
    
            # 增加薄边框
            style = win32gui.GetWindowLong(int(self.winId()), win32con.GWL_STYLE)
            win32gui.SetWindowLong(int(self.winId()), win32con.GWL_STYLE,
                                   style | win32con.WS_THICKFRAME)
    
            # ...
    
    1. 如果问题仍然存在,你可以尝试使用其他库来实现类似的功能,例如ctypes库。这样,你可以更直接地与Windows API进行交互,而不依赖于pywin32库。但请注意,这可能需要更多的工作和对Windows API的深入了解。
    评论

报告相同问题?

问题事件

  • 创建了问题 8月19日

悬赏问题

  • ¥66 换电脑后应用程序报错
  • ¥50 array数据同步问题
  • ¥15 pic16F877a单片机的外部触发中断程序仿真失效
  • ¥15 Matlab插值拟合差分微分规划图论
  • ¥15 keil5 target not created
  • ¥15 C/C++数据与算法请教
  • ¥15 怎么找志同道合的伙伴
  • ¥20 如何让程序ab.eXe自已删除干净硬盘里的本文件自己的ab.eXe文件
  • ¥50 爬虫预算充足,跪巨佬
  • ¥15 滑块验证码拖动问题悬赏