(终)PyQt6 / PySide 6 + Pywin32 自定义标题栏窗口 + 完全还原 Windows 原生窗口边框特效

13 篇文章 1 订阅
13 篇文章 1 订阅

参考文章:

如何在 pyqt 中自定义无边框窗口 - 之一Yo - 博客园 (cnblogs.com)icon-default.png?t=N7T8https://www.cnblogs.com/zhiyiYo/p/14659981.html

如何在pyqt中给无边框窗口添加DWM环绕阴影 - 之一Yo - 博客园 (cnblogs.com)icon-default.png?t=N7T8https://www.cnblogs.com/zhiyiYo/p/14644155.html

简述:

1. 窗口系统事件依赖的几个枚举类和 C 结构体类:

class MINMAXINFO(Structure):
    _fields_ = [
        ("ptReserved", POINT),
        ("ptMaxSize", POINT),
        ("ptMaxPosition", POINT),
        ("ptMinTrackSize", POINT),
        ("ptMaxTrackSize", POINT),
    ]
class PWINDOWPOS(Structure):
    _fields_ = [
        ('hWnd',            HWND),
        ('hwndInsertAfter', HWND),
        ('x',               c_int),
        ('y',               c_int),
        ('cx',              c_int),
        ('cy',              c_int),
        ('flags', UINT)
    ]
class NCCALCSIZE_PARAMS(Structure):
    _fields_ = [
        ('rgrc', RECT*3),
        ('lppos', POINTER(PWINDOWPOS))
    ]

class DWMNCRENDERINGPOLICY(Enum):
    DWMNCRP_USEWINDOWSTYLE = 0
    DWMNCRP_DISABLED = 1
    DWMNCRP_ENABLED = 2
    DWMNCRP_LAS = 3


class DWMWINDOWATTRIBUTE(Enum):
    DWMWA_NCRENDERING_ENABLED = 1
    DWMWA_NCRENDERING_POLICY = 2
    DWMWA_TRANSITIONS_FORCEDISABLED = 3
    DWMWA_ALLOW_NCPAINT = 4
    DWMWA_CAPTION_BUTTON_BOUNDS = 5
    DWMWA_NONCLIENT_RTL_LAYOUT = 6
    DWMWA_FORCE_ICONIC_REPRESENTATION = 7
    DWMWA_FLIP3D_POLICY = 8
    DWMWA_EXTENDED_FRAME_BOUNDS = 9
    DWMWA_HAS_ICONIC_BITMAP = 10
    DWMWA_DISALLOW_PEEK = 11
    DWMWA_EXCLUDED_FROM_PEEK = 12
    DWMWA_CLOAK = 13
    DWMWA_CLOAKED = 14
    DWMWA_FREEZE_REPRESENTATION = 25
    DWMWA_LAST = 16


class MARGINS(Structure):
    _fields_ = [
        ("cxLeftWidth", c_int),
        ("cxRightWidth", c_int),
        ("cyTopHeight", c_int),
        ("cyBottomHeight", c_int),
    ]

2. 给窗口添加阴影的方法(参考开头提到的文章方法添加):

注:使用此方法给窗口添加 DWM 阴影实际上就是新建了一个空白的带阴影的窗口,再将自己创建的窗口绘制到该窗口上(覆盖原有标题栏),所以修改后的窗口拖动和改变大小时占用的 CPU 和内存资源大概是未添加阴影时的 2~3 倍甚至更多,当系统刚启动时或外部应用占用的 CPU 和内存资源过多时,拖动和缩放窗口会出现明显的卡顿。
    def __init__(self, *args, **kwargs):
        "--snip--"
        self.user32 = WinDLL("user32")
        self.dwmapi = WinDLL("dwmapi")
        self.SetWindowCompositionAttribute = self.user32.SetWindowCompositionAttribute
        self.DwmExtendFrameIntoClientArea = self.dwmapi.DwmExtendFrameIntoClientArea
        self.DwmSetWindowAttribute = self.dwmapi.DwmSetWindowAttribute
        "--snip--"
    def addShadowEffect(self, hWnd):
        hWnd = int(hWnd)
        self.DwmSetWindowAttribute(
            hWnd,
            DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value,
            byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_ENABLED.value)),
            4,
        )
        margins = MARGINS(-1, -1, -1, -1)
        self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))

3.设置计时器监听最大化事件和活动状态事件(如果你喜欢别的样式可直接修改QSS):

    def __init__(self, *args, **kwargs):
        "--snip--"
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.__maxOrNormal2)
        self.timer.start(30)
        "--snip--"
    def __maxOrNormal2(self):
        if self.isMaximized():
            self.maxbutton.setIcon(QIcon("normal.png"))
            self.maxbutton.setToolTip("向下还原")
        else:
            self.maxbutton.setIcon(QIcon("max.png"))
            self.maxbutton.setToolTip("最大化")
        if self.isActiveWindow():
            self.titlebackground.setStyleSheet("QLabel {"
                                               "background-color:rgba(0,0,0,1);"
                                               "}")
            self.titleBar.setStyleSheet("QLabel {"
                                        'font: normal normal 15px "微软雅黑";'
                                        "background-color:rgba(0,0,0,0);"
                                        "color:rgb(255,255,255)"
                                        "}")
        else:
            self.titlebackground.setStyleSheet("QLabel {"
                                               "background-color:rgba(50,50,50,1);"
                                               "}")
            self.titleBar.setStyleSheet("QLabel {"
                                        'font: normal normal 15px "微软雅黑";'
                                        "background-color:rgba(0,0,0,0);"
                                        "color:rgba(255,255,255,0.9)"
                                        "}")

4.NativeEvent 自定义系统事件(如果你想按 Alt+F4 保持窗口不关闭,请将返回值中的 False 改成 True):

    def nativeEvent(self, eventType, message):
        "--snip--"
        elif msg.message == win32con.WM_SYSKEYDOWN:
            if msg.wParam == win32con.VK_F4:
                QApplication.sendEvent(self, QCloseEvent())
                return False, 0
        "--snip--"

准备工作:

准备工作与之前一致:

(终)基于 PySide6 的自定义边框窗口类(添加标题右键菜单,双击窗口图标关闭事件)_pyside6 窗口关闭事件-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/2402_84665876/article/details/141123995?spm=1001.2014.3001.5501

完整代码:

NativeWindow.pyw

import win32api
import win32con
import win32gui
from ctypes import (Structure, POINTER, c_int, cast, windll, byref, WinDLL)
from ctypes.wintypes import (POINT, HWND, UINT, RECT, MSG)
from PySide6.QtCore import (Qt, QSize, QTimer, QPoint)
from PySide6.QtGui import (QCursor, QCloseEvent, QIcon, QGuiApplication, QAction)
from PySide6.QtWidgets import (QApplication, QPushButton, QLabel, QMainWindow, QMenu)
from sys import exit as sys_exit
from enum import Enum
from sys import argv
class MINMAXINFO(Structure):
    _fields_ = [
        ("ptReserved", POINT),
        ("ptMaxSize", POINT),
        ("ptMaxPosition", POINT),
        ("ptMinTrackSize", POINT),
        ("ptMaxTrackSize", POINT),
    ]
class PWINDOWPOS(Structure):
    _fields_ = [
        ('hWnd',            HWND),
        ('hwndInsertAfter', HWND),
        ('x',               c_int),
        ('y',               c_int),
        ('cx',              c_int),
        ('cy',              c_int),
        ('flags', UINT)
    ]
class NCCALCSIZE_PARAMS(Structure):
    _fields_ = [
        ('rgrc', RECT*3),
        ('lppos', POINTER(PWINDOWPOS))
    ]

class DWMNCRENDERINGPOLICY(Enum):
    DWMNCRP_USEWINDOWSTYLE = 0
    DWMNCRP_DISABLED = 1
    DWMNCRP_ENABLED = 2
    DWMNCRP_LAS = 3


class DWMWINDOWATTRIBUTE(Enum):
    DWMWA_NCRENDERING_ENABLED = 1
    DWMWA_NCRENDERING_POLICY = 2
    DWMWA_TRANSITIONS_FORCEDISABLED = 3
    DWMWA_ALLOW_NCPAINT = 4
    DWMWA_CAPTION_BUTTON_BOUNDS = 5
    DWMWA_NONCLIENT_RTL_LAYOUT = 6
    DWMWA_FORCE_ICONIC_REPRESENTATION = 7
    DWMWA_FLIP3D_POLICY = 8
    DWMWA_EXTENDED_FRAME_BOUNDS = 9
    DWMWA_HAS_ICONIC_BITMAP = 10
    DWMWA_DISALLOW_PEEK = 11
    DWMWA_EXCLUDED_FROM_PEEK = 12
    DWMWA_CLOAK = 13
    DWMWA_CLOAKED = 14
    DWMWA_FREEZE_REPRESENTATION = 25
    DWMWA_LAST = 16


class MARGINS(Structure):
    _fields_ = [
        ("cxLeftWidth", c_int),
        ("cxRightWidth", c_int),
        ("cyTopHeight", c_int),
        ("cyBottomHeight", c_int),
    ]


class NativeWindow(QMainWindow):
    BORDER_WIDTH = 5

    def __init__(self, *args, **kwargs):
        windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")
        super(NativeWindow, self).__init__(*args, **kwargs)
        self._rect = QGuiApplication.primaryScreen().availableGeometry()
        self.title_height = 30
        self.user32 = WinDLL("user32")
        self.dwmapi = WinDLL("dwmapi")
        self.SetWindowCompositionAttribute = self.user32.SetWindowCompositionAttribute
        self.DwmExtendFrameIntoClientArea = self.dwmapi.DwmExtendFrameIntoClientArea
        self.DwmSetWindowAttribute = self.dwmapi.DwmSetWindowAttribute
        self.setWindowFlags(Qt.WindowType.Window |
                            Qt.WindowType.FramelessWindowHint |
                            Qt.WindowType.WindowMinimizeButtonHint |
                            Qt.WindowType.WindowMaximizeButtonHint |
                            Qt.WindowType.WindowCloseButtonHint |
                            Qt.WindowType.WindowSystemMenuHint)
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.__maxOrNormal2)
        self.timer.start(30)
        self.setStyleSheet("NativeWindow{background:rgb(255,255,255);}")
        self.__setWindowsBorder()
        self.__setWindowStatusMenu()
        self.addShadowEffect(self.winId())

    def addShadowEffect(self, hWnd):
        hWnd = int(hWnd)
        self.DwmSetWindowAttribute(
            hWnd,
            DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value,
            byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_ENABLED.value)),
            4,
        )
        margins = MARGINS(-1, -1, -1, -1)
        self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))

    def __setWindowsBorder(self):
        style = win32gui.GetWindowLong(int(self.winId()), win32con.GWL_STYLE)
        win32gui.SetWindowLong(int(self.winId()), win32con.GWL_STYLE,
                               style
                               | win32con.WS_THICKFRAME
                               | win32con.WS_MINIMIZEBOX
                               | win32con.WS_MAXIMIZEBOX
                               | win32con.WS_CAPTION
                               | win32con.CS_DBLCLKS)
       
    def setWindowTitle(self, title: str):
        super().setWindowTitle(title)
        self.titlebackground = QLabel(self)
        self.titleBar = QLabel(f" {title}", self)
        self.titlebackground.setGeometry(0,0,self.size().width(), self.title_height)
        self.titleBar.setGeometry(self.title_height, 0, self.size().width(), self.title_height)
        self.__raiseEvent()
        self.setMinimumHeight(self.title_height)
        self.__setthreebutton()

    def setWindowIcon(self, icon):
        super().setWindowIcon(icon)
        self.iconimage = QPushButton(self)
        self.iconimage.setIcon(icon)
        self.iconimage.setIconSize(QSize(self.title_height - 10, self.title_height - 10))
        self.iconimage.setFixedSize(self.title_height, self.title_height)
        self.iconimage.setStyleSheet("QPushButton {"
                                     "border:none;"
                                     "background-color:rgba(0,0,0,0);}")
        self.iconimage.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.iconimage.customContextMenuRequested.connect(self.__showWindowStatusMenuFromIcon)
        self.iconimage.move(0,0)
        self.__raiseEvent()

    def __setWindowStatusMenu(self):
        self.WindowStatusMenu = QMenu(self)
        self.WindowStatusMenu_qss = ("QMenu {"
                                     "background-color:rgb(40, 40, 40);"
                                     "color:rgb(255, 255, 255);"
                                     "border: 1px solid rgb(127, 127, 127);"
                                     "}"
                                     "QMenu:item:selected {"
                                     "background-color:rgb(80, 80, 80);"
                                     "}"
                                     "QMenu:separator{"
                                     "height:1px;"
                                     "background-color:rgba(123,123,123,1);"
                                     "margin-left:22px;"
                                     "margin-right:1px;"
                                     "}"
                                     "QMenu:item:disabled {"
                                     "color:rgb(100,100,100);"
                                     "background-color:rgb(40, 40, 40);"
                                     "}")
        self.WindowStatusMenu.setStyleSheet(self.WindowStatusMenu_qss)
        self.NormalAction = QAction("还原(&R)", self)
        self.NormalAction.setEnabled(False)
        self.NormalAction.triggered.connect(self.showNormal)
        self.NormalAction.setIcon(QIcon("normalborder.png"))
        self.WindowStatusMenu.addAction(self.NormalAction)
        self.MoveAction = QAction("移动(&M)", self)
        self.WindowStatusMenu.addAction(self.MoveAction)
        self.SizeAction = QAction("大小(&S)", self)
        self.WindowStatusMenu.addAction(self.SizeAction)
        self.MinAction = QAction("最小化(&N)", self)
        self.MinAction.setIcon(QIcon("minborder.png"))
        self.MinAction.triggered.connect(self.showMinimized)
        self.WindowStatusMenu.addAction(self.MinAction)
        self.MaxAction = QAction("最大化(&X)", self)
        self.MaxAction.triggered.connect(self.showMaximized)
        self.MaxAction.setIcon(QIcon("maxborder.png"))
        self.WindowStatusMenu.addAction(self.MaxAction)
        self.WindowStatusMenu.addSeparator()
        self.CloseAction = QAction("关闭(&C)", self)
        self.CloseAction.setShortcut("Alt+F4")
        self.CloseAction.setIcon(QIcon("closeborder.png"))
        self.CloseAction.triggered.connect(self.close)
        self.WindowStatusMenu.addAction(self.CloseAction)

    def __setWindowStatusMenuOnMax(self):
        self.WindowStatusMenu = QMenu(self)
        self.WindowStatusMenu.setStyleSheet(self.WindowStatusMenu_qss)
        self.NormalAction = QAction("还原(&R)", self)
        self.NormalAction.triggered.connect(self.showNormal)
        self.NormalAction.setIcon(QIcon("normalborder.png"))
        self.WindowStatusMenu.addAction(self.NormalAction)
        self.MoveAction = QAction("移动(&M)", self)
        self.MoveAction.setEnabled(False)
        self.WindowStatusMenu.addAction(self.MoveAction)
        self.SizeAction = QAction("大小(&S)", self)
        self.SizeAction.setEnabled(False)
        self.WindowStatusMenu.addAction(self.SizeAction)
        self.MinAction = QAction("最小化(&N)", self)
        self.MinAction.setIcon(QIcon("minborder.png"))
        self.MinAction.triggered.connect(self.showMinimized)
        self.WindowStatusMenu.addAction(self.MinAction)
        self.MaxAction = QAction("最大化(&X)", self)
        self.MaxAction.setEnabled(False)
        self.MaxAction.triggered.connect(self.showMaximized)
        self.MaxAction.setIcon(QIcon("maxborder.png"))
        self.WindowStatusMenu.addAction(self.MaxAction)
        self.WindowStatusMenu.addSeparator()
        self.CloseAction = QAction("关闭(&C)", self)
        self.CloseAction.setShortcut("Alt+F4")
        self.CloseAction.setIcon(QIcon("closeborder.png"))
        self.CloseAction.triggered.connect(self.close)
        self.WindowStatusMenu.addAction(self.CloseAction)

    def __showWindowStatusMenuFromIcon(self):
        if not self.isMaximized():
            self.__setWindowStatusMenu()
            self.WindowStatusMenu.exec(QPoint(self.pos().x(),self.title_height + self.pos().y()))
        else:
            self.__setWindowStatusMenuOnMax()
            self.WindowStatusMenu.exec(QPoint(self.pos().x(), self.title_height + self.pos().y() + 8))

    def __setthreebutton(self):
        clqss = ("QPushButton {"
               "background-color:rgba(0,0,0,0);"
               "border:none;"
               "}"
               "QPushButton:hover {"
               "background-color:rgba(255,0,0,1);"
               "}"
               "QPushButton:pressed {"
               "background-color:rgba(255,100,100,1);"
               "}"
               )
        blqss = ("QPushButton {"
                 "background-color:rgba(0,0,0,0);"
                 "border:none;"
                 "}"
                 "QPushButton:hover {"
                 "background-color:rgba(100,100,100,1);"
                 "}"
                 "QPushButton:pressed {"
                 "background-color:rgba(100,100,100,1);"
                 "}"
                 )
        psize = QSize(self.title_height + 10, self.title_height)
        isize = QSize(self.title_height - 17, self.title_height - 17)
        self.exitbutton = QPushButton(self)
        self.exitbutton.setIcon(QIcon("close.png"))
        self.exitbutton.setIconSize(isize)
        self.exitbutton.resize(psize)
        self.exitbutton.setStyleSheet(clqss)
        self.exitbutton.setToolTip("关闭")
        self.exitbutton.clicked.connect(self.close)
        self.maxbutton = QPushButton(self)
        self.maxbutton.setIcon(QIcon("max.png"))
        self.maxbutton.setIconSize(isize)
        self.maxbutton.resize(psize)
        self.maxbutton.setStyleSheet(blqss)
        self.maxbutton.clicked.connect(self.__maxOrNormal)
        self.minbutton = QPushButton(self)
        self.minbutton.setIcon(QIcon("min.png"))
        self.minbutton.setToolTip("最小化")
        self.minbutton.setIconSize(isize)
        self.minbutton.resize(psize)
        self.minbutton.setStyleSheet(blqss)
        self.minbutton.clicked.connect(self.showMinimized)

    def showNormal(self):
        super().showNormal()
        QCursor.setPos(QCursor.pos().x(), QCursor.pos().y() - 1)

    def showMaximized(self):
        super().showMaximized()
        QCursor.setPos(QCursor.pos().x(), QCursor.pos().y() - 1)

    def __maxOrNormal(self):
        if self.isMaximized():
            self.showNormal()
        else:
            self.showMaximized()

    def __maxOrNormal2(self):
        if self.isMaximized():
            self.maxbutton.setIcon(QIcon("normal.png"))
            self.maxbutton.setToolTip("向下还原")
        else:
            self.maxbutton.setIcon(QIcon("max.png"))
            self.maxbutton.setToolTip("最大化")
        if self.isActiveWindow():
            self.titlebackground.setStyleSheet("QLabel {"
                                               "background-color:rgba(0,0,0,1);"
                                               "}")
            self.titleBar.setStyleSheet("QLabel {"
                                        'font: normal normal 15px "微软雅黑";'
                                        "background-color:rgba(0,0,0,0);"
                                        "color:rgb(255,255,255)"
                                        "}")
        else:
            self.titlebackground.setStyleSheet("QLabel {"
                                               "background-color:rgba(50,50,50,1);"
                                               "}")
            self.titleBar.setStyleSheet("QLabel {"
                                        'font: normal normal 15px "微软雅黑";'
                                        "background-color:rgba(0,0,0,0);"
                                        "color:rgba(255,255,255,0.9)"
                                        "}")

    def __raiseEvent(self):
        try:
            self.titlebackground.raise_()
            self.titleBar.raise_()
            self.exitbutton.raise_()
            self.maxbutton.raise_()
            self.minbutton.raise_()
        except:
            pass
        try:
            self.iconimage.raise_()
        except:
            pass

    def resizeEvent(self, a0):
        self.__resizeEvent__()

    def __resizeEvent__(self):
        try:
            self.titlebackground.setGeometry(0, 0, self.size().width(), self.title_height)
            self.titleBar.setGeometry(self.title_height, 0, self.size().width(), self.title_height)
            self.exitbutton.move(self.size().width() - self.exitbutton.size().width(), 0)
            self.maxbutton.move(self.exitbutton.pos().x() - self.maxbutton.size().width(), 0)
            self.minbutton.move(self.maxbutton.pos().x() - self.minbutton.size().width(), 0)
        except:
            pass

    def __isWindowMaximized(self, hWnd) -> bool:
        windowPlacement = win32gui.GetWindowPlacement(hWnd)
        if not windowPlacement:
            return False
        return windowPlacement[1] == win32con.SW_MAXIMIZE

    def nativeEvent(self, eventType, message):
        msg = MSG.from_address(message.__int__())
        pos = QCursor.pos()
        x = pos.x() - self.frameGeometry().x()
        y = pos.y() - self.frameGeometry().y()
        if msg.message == win32con.WM_NCHITTEST:
            xPos = win32api.LOWORD(msg.lParam) - self.frameGeometry().x()
            yPos = win32api.HIWORD(msg.lParam) - self.frameGeometry().y()
            w, h = self.width(), self.height()
            lx = xPos < self.BORDER_WIDTH
            rx = xPos + 9 > w - self.BORDER_WIDTH + 7
            ty = yPos < self.BORDER_WIDTH
            by = yPos > h - self.BORDER_WIDTH
            if lx and ty and not self.isMaximized():
                return True, win32con.HTTOPLEFT
            elif rx and by and not self.isMaximized():
                return True, win32con.HTBOTTOMRIGHT
            elif rx and ty and not self.isMaximized():
                return True, win32con.HTTOPRIGHT
            elif lx and by and not self.isMaximized():
                return True, win32con.HTBOTTOMLEFT
            elif ty and not self.isMaximized():
                return True, win32con.HTTOP
            elif by and not self.isMaximized():
                return True, win32con.HTBOTTOM
            elif lx and not self.isMaximized():
                return True, win32con.HTLEFT
            elif rx and not self.isMaximized():
                return True, win32con.HTRIGHT
            elif self.pos().y() <= QCursor.pos().y() <= self.pos().y() + self.title_height and self.childAt(x,y) == self.titleBar:
                return True, win32con.HTCAPTION
        elif msg.message == win32con.WM_NCCALCSIZE:
            if self.__isWindowMaximized(msg.hWnd):
                self.__monitorNCCALCSIZE(msg)
            return True, 0
        elif msg.message == win32con.WM_GETMINMAXINFO:
            if self.__isWindowMaximized(msg.hWnd):
                window_rect = win32gui.GetWindowRect(msg.hWnd)
                if not window_rect:
                    return False, 0
                monitor = win32api.MonitorFromRect(window_rect)
                if not monitor:
                    return False, 0
                work_area = (self._rect.x(), self._rect.y(), self._rect.width() + 5, self._rect.height())
                info = cast(msg.lParam, POINTER(MINMAXINFO)).contents
                info.ptMaxSize.x = work_area[2]
                info.ptMaxSize.y = work_area[3]
                info.ptMaxTrackSize.x = info.ptMaxSize.x
                info.ptMaxTrackSize.y = info.ptMaxSize.y
                info.ptMaxPosition.x = 0
                info.ptMaxPosition.y = 0
                return True, 1
        elif msg.message == win32con.WM_SYSKEYDOWN:
            if msg.wParam == win32con.VK_F4:
                QApplication.sendEvent(self, QCloseEvent())
                return False, 0
        return QMainWindow.nativeEvent(self, eventType, message)

    def __monitorNCCALCSIZE(self, msg: MSG):
        monitor = win32api.MonitorFromWindow(msg.hWnd)
        if monitor is None and not self.monitor_info:
            return
        elif monitor is not None:
            self.monitor_info = win32api.GetMonitorInfo(monitor)
        params = cast(msg.lParam, POINTER(NCCALCSIZE_PARAMS)).contents
        params.rgrc[0].left = self.monitor_info['Work'][0]
        params.rgrc[0].top = self.monitor_info['Work'][1]
        params.rgrc[0].right = self.monitor_info['Work'][2]
        params.rgrc[0].bottom = self.monitor_info['Work'][3]


if __name__ == '__main__':
    app = QApplication(argv)
    w = NativeWindow()
    w.setWindowTitle("NativeWindow 示例")
    w.setWindowIcon(QIcon("icon.png"))
    w.setMinimumWidth(450)
    w.resize(800,450)
    w.show()
    sys_exit(app.exec())

课程亮点       本课程是PySide6零基础入门与项目实战视频教程,经过精心设计,分为十个章节,制作了141页ppt, 接近70个代码示例,主要讲解PySide6开发环境安装、基础控件与界面布局、项目实战,PySide6程序打包,安装包制作,安装卸载、更新,发布等知识。涵盖从基础概念到高级应用的全方位知识,旨在为你提供一条清晰、系统的学习之路。无论你是编程新手,还是希望深化对PySide6的了解,本课程都能满足你的需求。       教学环境:Win11 64bit、Python3.11、PyCharm、Anacoda。课程大纲第一章:基础篇 PySide6开发环境安装        从Anaconda环境配置开始,带你快速入门Win11/win10下PySide6、PyQt5开发环境的安装与配置,分别介绍PyCharm与VSCode如何配置PySide6,  以及Python AnaConda的基本用法,创建虚拟环境,安装python模块。第二章 控件与布局篇 PySide6常用控件与界面布局使用介绍        深入PySide6中的常用控件与界面布局技巧,通过丰富的实例,掌握PySide6的窗口、布局、控件等核心内容。主要介绍QLabel、QPushButton、QLineEdit、QCheckBox、QComboBox、QTextEdit、QTextBrowser、QListView与QListWidget、QStackedWidget、QTabWidget、QTableView等控件以及水平垂直布局,弹簧控件,栅格布局,表单布局。第三章 信号槽与事件机制       解锁PySide6的信号槽机制和事件处理技能,让你的应用更加灵活。详细介绍Qt自定义信号槽,跨窗口传递信号;Qt鼠标事件,键盘事件,组合事件,事件过滤。第四章 QMainWindow应用篇       详细介绍QMainWindow的使用,包括菜单栏、工具栏、状态栏和停靠窗口等。第五章 样式表qss与自定义控件        教你如何使用样式表美化应用界面,并创建独特的自定义控件。掌握这些技能后,学员将能够设计出既美观又功能丰富的用户界面。第六章 图表与曲线        引入pyqtgraph,展示如何在PySide6应用中绘制图表和动态曲线。第七章 数据库编程        带你进入数据库编程世界,使用sqlite3与PySide6结合,进行数据存储和管理。第八章 项目实战:高仿有道词典        通过一个高仿有道词典的项目,将所学知识融会贯通,实战演练。课程中将会接入翻译接口,开发一个属于自己的翻译软件。第九章 打包与部署       教你如何将PySide6项目打包成exe,并使用Inno Setup制作安装包,介绍软件更新、卸载策略,让你的应用轻松上线。第十章 课程总结        回顾整个课程的学习内容,巩固知识点,为进一步的学习和应用打下坚实的基础。教学特色       实战案例:每个章节都配备实战案例,让学习者在实践中深化理解。       代码资料全覆盖:提供全套课程代码资料下载,便于学习者随时查阅和复习。       高效学习路径:课程内容结构清晰,由浅入深,适合不同层次的学习者。       本课程提供全部代码与在线答疑。谁应该学习这个课程       对图形界面开发感兴趣的编程新手。       希望提升个人技能,进入或者深耕在GUI开发领域的开发者。       需要快速掌握PySide6进行项目开发的软件工程师。结语        通过本课程的学习,你不仅能掌握PySide6的核心技能,还能通过实战项目提升解决实际问题的能力,最让你能独立完成专业的GUI应用开发。随着技术的深入,你将发现PySide6不仅仅是一个工具库,它开启的是一扇通往高效、美观应用开发的大门。        开始PySide6的学习之旅,让你的编程之路更加精彩!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值