From f6c8fac77fccda47d1e42e6e7f0f9418cdad2980 Mon Sep 17 00:00:00 2001
From: Jcen <172036972@qq.com>
Date: Fri, 4 Oct 2024 12:37:45 +0800
Subject: [PATCH] Initial commit
---
.idea/.gitignore | 3 +
.idea/PyQt_Lesson.iml | 8 +
.../inspectionProfiles/profiles_settings.xml | 6 +
.idea/misc.xml | 7 +
.idea/modules.xml | 8 +
.idea/vcs.xml | 6 +
lesson1/动态layout.py | 362 ++++++++++++++++
lesson1/无边框拖动窗口.py | 385 ++++++++++++++++++
lesson1/流式布局.py | 119 ++++++
lesson1/类添加方法.py | 12 +
10 files changed, 916 insertions(+)
create mode 100644 .idea/.gitignore
create mode 100644 .idea/PyQt_Lesson.iml
create mode 100644 .idea/inspectionProfiles/profiles_settings.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/modules.xml
create mode 100644 .idea/vcs.xml
create mode 100644 lesson1/动态layout.py
create mode 100644 lesson1/无边框拖动窗口.py
create mode 100644 lesson1/流式布局.py
create mode 100644 lesson1/类添加方法.py
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/PyQt_Lesson.iml b/.idea/PyQt_Lesson.iml
new file mode 100644
index 0000000..d0876a7
--- /dev/null
+++ b/.idea/PyQt_Lesson.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..4b53f34
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..7a08674
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lesson1/动态layout.py b/lesson1/动态layout.py
new file mode 100644
index 0000000..ae5b1ef
--- /dev/null
+++ b/lesson1/动态layout.py
@@ -0,0 +1,362 @@
+# -*- coding: utf-8 -*-
+import os
+import sys
+from PyQt5.QtCore import pyqtSlot, Qt
+# from PyQt5.QtGui import Q
+from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow, QListWidget, QTextEdit, QPushButton, QApplication, \
+ QWidget, QToolBar, QAction, QVBoxLayout, QMenu, QLineEdit, QLabel
+from PyQt5.QtCore import Qt, QSettings
+from PyQt5.QtCore import QByteArray
+
+
+class MainWindow(QMainWindow):
+ def __init__(self, parent=None):
+ super(MainWindow, self).__init__(parent)
+
+ self.dock_widgets = {} # 存储QDockWidget的字典
+ self.object = []
+ self.initUI()
+
+ def initUI(self):
+ self.setWindowTitle("DockWidget Example")
+ self.setGeometry(100, 100, 800, 600)
+ self.setDockNestingEnabled(True)
+ # 加载布局
+ self.loadLayout()
+
+ def add(self, text):
+ # 创建三个QDockWidget
+ dock1 = QDockWidget(text, self)
+ # 设置QDockWidget的特性
+ dock1.setFeatures(
+ QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable)
+ # 创建QTextEdit作为QDockWidget的内容
+ text_edit = QWidget()
+ text_edit1 = QLabel()
+ text_edit1.setText('sdfdsfdsafdsfdsa')
+ text_edit11 = QVBoxLayout()
+ text_edit11.addWidget(text_edit1)
+ text_edit.setLayout(text_edit11)
+ # 将QTextEdit添加到QDockWidget中
+ dock1.setWidget(text_edit1)
+
+ # 将QDockWidget添加到主窗口中
+ self.addDockWidget(Qt.LeftDockWidgetArea, dock1)
+
+ if self.object:
+ # 设置QDockWidget的叠加摆放
+ self.tabifyDockWidget(self.object[-1], dock1)
+ else:
+ self.object.append(dock1)
+ print(self.object)
+ self.dock_widgets[text] = dock1
+
+ def save_layout(self):
+ try:
+ p = 'layout1.ini'
+ with open(p, 'wb') as f:
+ s = self.saveState()
+ f.write(s)
+ # 创建QSettings对象,用于保存布局设置
+ settings = QSettings("layout.ini", QSettings.IniFormat)
+
+ # 保存当前的布局设置
+ settings.setValue("mainWindow/geometry", self.saveGeometry())
+ settings.setValue("mainWindow/state", self.saveState())
+
+ # 保存QDockWidget的信息
+ settings.beginGroup("dockWidgets")
+ for name, dock in self.dock_widgets.items():
+ settings.setValue(name + "/geometry", dock.saveGeometry())
+ settings.endGroup()
+ except Exception as e:
+ print("保存布局时出错:", e)
+
+ def createDockWidget(self, name):
+ # 创建一个QDockWidget
+ dock = QDockWidget(name, self)
+ dock.setObjectName(name)
+ # 设置QDockWidget的特性
+ dock.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable)
+
+ # 创建QTextEdit作为QDockWidget的内容
+ text_edit = QTextEdit()
+ dock.setWidget(text_edit)
+
+
+ # 将QDockWidget添加到字典中
+ self.dock_widgets[name] = dock
+
+ def loadLayout(self):
+ # 创建QSettings对象,用于加载布局设置
+ settings = QSettings("layout.ini", QSettings.IniFormat)
+
+ # 加载之前保存的布局设置
+ self.restoreGeometry(settings.value("mainWindow/geometry", self.saveGeometry()))
+ self.restoreState(settings.value("mainWindow/state", self.saveState()))
+
+ # 加载QDockWidget的信息
+ settings.beginGroup("dockWidgets")
+ dock_names = settings.childGroups()
+ for s, name in enumerate(dock_names):
+ self.createDockWidget(name)
+ dock = self.dock_widgets[name]
+ dock.restoreGeometry(settings.value(name + "/geometry", dock.saveGeometry()))
+ self.addDockWidget(Qt.LeftDockWidgetArea, dock) # 将QDockWidget添加到主窗口中
+ self.restoreState(self.saveState())
+ settings.endGroup()
+ p = 'layout1.ini'
+ if os.path.exists(p):
+ with open(p, 'rb') as f:
+ s = f.read()
+ self.restoreState(s)
+
+
+class widget(QWidget):
+
+ def __init__(self):
+ super(widget, self).__init__()
+
+ self.L = QHBoxLayout()
+ self.setLayout(self.L)
+
+ self.A = MainWindow()
+ self.P = QPushButton('add')
+ self.Ps = QPushButton('save')
+ self.Lo = QPushButton('lo')
+ self.name = QLineEdit()
+ self.L.addWidget(self.name)
+ self.L.addWidget(self.A)
+ self.L.addWidget(self.P)
+ self.L.addWidget(self.Ps)
+ self.L.addWidget(self.Lo)
+
+ self.P.clicked.connect(self.add)
+ self.Ps.clicked.connect(self.adds)
+ self.Lo.clicked.connect(self.addss)
+
+ def add(self):
+ self.A.add(self.name.text())
+
+ def adds(self):
+ self.A.save_layout()
+
+ def addss(self):
+ self.A.sss()
+
+
+if __name__ == "__main__":
+ import sys
+ import qtmodern.styles
+ app = QApplication(sys.argv)
+ qtmodern.styles.dark(app)
+ mainWindow = widget()
+
+ mainWindow.show()
+ sys.exit(app.exec_())
+
+
+
+from .import_qt import *
+import os
+from .MyDockWidget import MyDockWidget
+from .util.form_class_registration import FormCalss
+from util.func import quantity_recursion
+import re
+
+
+class InitUI(QMainWindow):
+ def __init__(self, parent=None):
+ super(InitUI, self).__init__(parent)
+
+ self.dock_widgets = {} # 存储QDockWidget的字典
+ self.initUI()
+ # self.setStyleSheet_func()
+
+ # 创建一个动作,用于保存布局设置
+ save_layout_action = QAction("Save Layout", self)
+ save_layout_action.triggered.connect(self.save_layout)
+
+ # 创建一个动作,用于加载布局设置
+ load_layout_action = QAction("Load Layout", self)
+ load_layout_action.triggered.connect(self.load_layout)
+
+ # 创建一个动作,用于加载布局设置
+ create_action = QAction("create", self)
+ create_action.triggered.connect(self.create_action_func)
+
+ # 将动作添加到菜单栏
+ file_menu = self.menuBar().addMenu("File")
+ file_menu.addAction(save_layout_action)
+ file_menu.addAction(load_layout_action)
+ file_menu.addAction(create_action)
+
+ # 将动作添加到菜单栏
+ self.tool_menu = self.menuBar().addMenu("tool")
+ self.init_tool()
+
+ def init_tool(self):
+ import functools
+ for i in FormCalss.FormDict:
+ create_action = QAction(i, self)
+ self.tool_menu.addAction(create_action)
+ create_action.triggered.connect(functools.partial(self.create_action_func, i))
+
+ def create_action_func(self, name):
+ widget = {'type': name, 'text': ''}
+ try:
+ FormCalss.form_class_dict[widget['type']]
+ except:
+ FormCalss.form_class_dict[widget['type']] = []
+ if FormCalss.form_class_dict[widget['type']] != []:
+ widgetList = FormCalss.form_class_dict[widget['type']]
+ widgetNameList = [i.objectName() for i in widgetList]
+ widget['text'] = quantity_recursion(1, widgetNameList)
+ else:
+ widget = {'type': name, 'text': '%s1' % name}
+ widgets = FormCalss.FormDict[widget['type']]()
+ widgets.setObjectName(widget['text'])
+ self.addTest(widgets, text=widget['text'])
+ FormCalss.add_form_class(widgets, widget['type'])
+ print(FormCalss.form_class_dict)
+
+ def addTest(self, widget, text):
+ # 创建三个QDockWidget
+ result = re.sub(r'\d+', '', text)
+ dock1 = MyDockWidget(text, self, type=result)
+ # 将QTextEdit添加到QDockWidget中
+ dock1.setWidget(widget)
+ # 将QDockWidget添加到主窗口中
+
+ self.addDockWidget(Qt.LeftDockWidgetArea, dock1)
+
+ self.dock_widgets[text] = dock1
+
+ def setStyleSheet_func(self):
+ StyleSheet = """
+ background-color: rgb(50, 50, 50);
+
+ """
+ self.setStyleSheet(StyleSheet)
+
+ def initUI(self):
+ self.setWindowTitle("DockWidget Example")
+ self.setGeometry(100, 100, 800, 600)
+ self.setDockNestingEnabled(True)
+ # 加载布局
+ self.load_layout()
+
+ # def add(self, text):
+ # # 创建三个QDockWidget
+ # dock1 = QDockWidget(text, self)
+ # # 设置QDockWidget的特性
+ # dock1.setFeatures(
+ # QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetClosable)
+ # # 创建QTextEdit作为QDockWidget的内容
+ # text_edit = QWidget()
+ # text_edit1 = QLabel()
+ # text_edit1.setText('sdfdsfdsafdsfdsa')
+ # text_edit11 = QVBoxLayout()
+ # text_edit11.addWidget(text_edit1)
+ # text_edit.setLayout(text_edit11)
+ # # 将QTextEdit添加到QDockWidget中
+ # dock1.setWidget(text_edit1)
+ #
+ # # 将QDockWidget添加到主窗口中
+ # self.addDockWidget(Qt.LeftDockWidgetArea, dock1)
+ #
+ # if self.object:
+ # # 设置QDockWidget的叠加摆放
+ # self.tabifyDockWidget(self.object[-1], dock1)
+ # else:
+ # self.object.append(dock1)
+ # self.dock_widgets[text] = dock1
+
+ def save_layout(self):
+ try:
+ try:
+ os.remove('layout1.ini')
+ except:
+ try:
+ os.remove('layout.ini')
+ except Exception as e:
+ print(e, 'save')
+ pass
+ p = 'layout1.ini'
+ with open(p, 'wb') as f:
+ s = self.saveState()
+ f.write(s)
+ # 创建QSettings对象,用于保存布局设置
+ settings = QSettings("layout.ini", QSettings.IniFormat)
+
+ # 保存当前的布局设置
+ settings.setValue("mainWindow/geometry", self.saveGeometry())
+ settings.setValue("mainWindow/state", self.saveState())
+
+ # 保存QDockWidget的信息
+ settings.beginGroup("dockWidgets")
+ for name, dock in self.dock_widgets.items():
+ settings.setValue(name + "/geometry", dock.saveGeometry())
+ settings.endGroup()
+ except Exception as e:
+ print("保存布局时出错:", e)
+ self.w = QWidget()
+ self.w.setWindowFlags(Qt.WindowStaysOnTopHint)
+ reply = QMessageBox.question(self.w, '信息', '保存预设成功', QMessageBox.Cancel)
+ if reply == QMessageBox.Cancel:
+ return
+
+ def createDockWidget(self, name):
+ result = re.sub(r'\d+', '', name)
+ widget_object = FormCalss.FormDict[result]()
+ widget_object.setObjectName(name)
+ # 创建一个QDockWidget
+ dock = MyDockWidget(name, self, type=result)
+ # 创建QTextEdit作为QDockWidget的内容
+ dock.setWidget(widget_object)
+
+ widget = {'type': result, 'text': ''}
+ try:
+ FormCalss.form_class_dict[widget['type']]
+ except:
+ FormCalss.form_class_dict[widget['type']] = []
+ if FormCalss.form_class_dict[widget['type']] != []:
+ widgetList = FormCalss.form_class_dict[widget['type']]
+ widgetNameList = [i.objectName() for i in widgetList]
+ widget['text'] = quantity_recursion(1, widgetNameList)
+
+ else:
+ widget = {'type': result, 'text': '%s1' % result}
+ FormCalss.add_form_class(widget_object, widget['type'])
+ print(FormCalss.form_class_dict)
+ # 将QDockWidget添加到字典中
+ self.dock_widgets[name] = dock
+
+ def load_layout(self):
+ # 创建QSettings对象,用于加载布局设置
+ settings = QSettings("layout.ini", QSettings.IniFormat)
+
+ # 加载之前保存的布局设置
+ self.restoreGeometry(settings.value("mainWindow/geometry", self.saveGeometry()))
+ self.restoreState(settings.value("mainWindow/state", self.saveState()))
+
+ # 加载QDockWidget的信息
+ settings.beginGroup("dockWidgets")
+ dock_names = settings.childGroups()
+ for s, name in enumerate(dock_names):
+ self.createDockWidget(name)
+ dock = self.dock_widgets[name]
+ dock.restoreGeometry(settings.value(name + "/geometry", dock.saveGeometry()))
+ self.addDockWidget(Qt.LeftDockWidgetArea, dock) # 将QDockWidget添加到主窗口中
+ self.restoreState(self.saveState())
+ settings.endGroup()
+ p = 'layout1.ini'
+ if os.path.exists(p):
+ with open(p, 'rb') as f:
+ s = f.read()
+ self.restoreState(s)
+ for i in self.findChildren(QDockWidget):
+ if i.isHidden():
+ settings = QSettings("layout.ini", QSettings.IniFormat)
+ settings.remove("dockWidgets/" + i.objectName() + "/geometry")
+
diff --git a/lesson1/无边框拖动窗口.py b/lesson1/无边框拖动窗口.py
new file mode 100644
index 0000000..0a8021a
--- /dev/null
+++ b/lesson1/无边框拖动窗口.py
@@ -0,0 +1,385 @@
+#!/usr/bin/env python
+# -*- coding:utf-8 -*-
+# Author: jyroy
+import sys
+
+from PyQt5.QtCore import QSize
+from PyQt5.QtWidgets import QApplication
+from PyQt5.QtCore import Qt, pyqtSignal, QPoint
+from PyQt5.QtGui import QFont, QEnterEvent, QPainter, QColor, QPen
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel,QSpacerItem, QSizePolicy, QPushButton
+from PyQt5.QtGui import QIcon
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QTextEdit
+# from LeftTabWidget import LeftTabWidget
+# 样式
+StyleSheet = """
+/*标题栏*/
+TitleBar {
+ background-color: red;
+}
+/*最小化最大化关闭按钮通用默认背景*/
+#buttonMinimum,#buttonMaximum,#buttonClose {
+ border: none;
+ background-color: red;
+}
+/*悬停*/
+#buttonMinimum:hover,#buttonMaximum:hover {
+ background-color: red;
+ color: white;
+}
+#buttonClose:hover {
+ color: white;
+}
+/*鼠标按下不放*/
+#buttonMinimum:pressed,#buttonMaximum:pressed {
+ background-color: Firebrick;
+}
+#buttonClose:pressed {
+ color: white;
+ background-color: Firebrick;
+}
+"""
+
+class TitleBar(QWidget):
+
+ # 窗口最小化信号
+ windowMinimumed = pyqtSignal()
+ # 窗口最大化信号
+ windowMaximumed = pyqtSignal()
+ # 窗口还原信号
+ windowNormaled = pyqtSignal()
+ # 窗口关闭信号
+ windowClosed = pyqtSignal()
+ # 窗口移动
+ windowMoved = pyqtSignal(QPoint)
+
+ def __init__(self, *args, **kwargs):
+ super(TitleBar, self).__init__(*args, **kwargs)
+ # 支持qss设置背景
+ self.setAttribute(Qt.WA_StyledBackground, True)
+ self.mPos = None
+ self.iconSize = 20 # 图标的默认大小
+ # 设置默认背景颜色,否则由于受到父窗口的影响导致透明
+ self.setAutoFillBackground(True)
+ palette = self.palette()
+ palette.setColor(palette.Window, QColor(240, 240, 240))
+ self.setPalette(palette)
+ # 布局
+ layout = QHBoxLayout(self, spacing=0)
+ layout.setContentsMargins(0, 0, 0, 0)
+ # 窗口图标
+ self.iconLabel = QLabel(self)
+ # self.iconLabel.setScaledContents(True)
+ layout.addWidget(self.iconLabel)
+ # 窗口标题
+ self.titleLabel = QLabel(self)
+ self.titleLabel.setMargin(2)
+ layout.addWidget(self.titleLabel)
+ # 中间伸缩条
+ layout.addSpacerItem(QSpacerItem(
+ 40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
+ # 利用Webdings字体来显示图标
+ font = self.font() or QFont()
+ font.setFamily('Webdings')
+ # 最小化按钮
+ self.buttonMinimum = QPushButton(
+ '0', self, clicked=self.windowMinimumed.emit, font=font, objectName='buttonMinimum')
+ layout.addWidget(self.buttonMinimum)
+ # 最大化/还原按钮
+ self.buttonMaximum = QPushButton(
+ '1', self, clicked=self.showMaximized, font=font, objectName='buttonMaximum')
+ layout.addWidget(self.buttonMaximum)
+ # 关闭按钮
+ self.buttonClose = QPushButton(
+ 'r', self, clicked=self.windowClosed.emit, font=font, objectName='buttonClose')
+ layout.addWidget(self.buttonClose)
+ # 初始高度
+ self.setHeight()
+
+ def showMaximized(self):
+ if self.buttonMaximum.text() == '1':
+ # 最大化
+ self.buttonMaximum.setText('2')
+ self.windowMaximumed.emit()
+ else: # 还原
+ self.buttonMaximum.setText('1')
+ self.windowNormaled.emit()
+
+ def setHeight(self, height=38):
+ """设置标题栏高度"""
+ self.setMinimumHeight(height)
+ self.setMaximumHeight(height)
+ # 设置右边按钮的大小
+ self.buttonMinimum.setMinimumSize(height, height)
+ self.buttonMinimum.setMaximumSize(height, height)
+ self.buttonMaximum.setMinimumSize(height, height)
+ self.buttonMaximum.setMaximumSize(height, height)
+ self.buttonClose.setMinimumSize(height, height)
+ self.buttonClose.setMaximumSize(height, height)
+
+ def setTitle(self, title):
+ """设置标题"""
+ self.titleLabel.setText(title)
+
+ def setIcon(self, icon):
+ """设置图标"""
+ self.iconLabel.setPixmap(icon.pixmap(self.iconSize, self.iconSize))
+
+ def setIconSize(self, size):
+ """设置图标大小"""
+ self.iconSize = size
+
+ def enterEvent(self, event):
+ self.setCursor(Qt.ArrowCursor)
+ super(TitleBar, self).enterEvent(event)
+
+ def mouseDoubleClickEvent(self, event):
+ super(TitleBar, self).mouseDoubleClickEvent(event)
+ self.showMaximized()
+
+ def mousePressEvent(self, event):
+ """鼠标点击事件"""
+ if event.button() == Qt.LeftButton:
+ self.mPos = event.pos()
+ event.accept()
+
+ def mouseReleaseEvent(self, event):
+ '''鼠标弹起事件'''
+ self.mPos = None
+ event.accept()
+
+ def mouseMoveEvent(self, event):
+ if event.buttons() == Qt.LeftButton and self.mPos:
+ self.windowMoved.emit(self.mapToGlobal(event.pos() - self.mPos))
+ event.accept()
+
+# 枚举左上右下以及四个定点
+Left, Top, Right, Bottom, LeftTop, RightTop, LeftBottom, RightBottom = range(8)
+
+class FramelessWindow(QWidget):
+
+ # 四周边距
+ Margins = 5
+
+ def __init__(self, *args, **kwargs):
+ super(FramelessWindow, self).__init__(*args, **kwargs)
+
+ self._pressed = False
+ self.Direction = None
+ # 背景透明
+ self.setAttribute(Qt.WA_TranslucentBackground, True)
+ # 无边框
+ self.setWindowFlags(Qt.FramelessWindowHint) # 隐藏边框
+ # 鼠标跟踪
+ self.setMouseTracking(True)
+ # 布局
+ layout = QVBoxLayout(self, spacing=0)
+ # 预留边界用于实现无边框窗口调整大小
+ layout.setContentsMargins(
+ self.Margins, self.Margins, self.Margins, self.Margins)
+ # 标题栏
+ self.titleBar = TitleBar(self)
+ layout.addWidget(self.titleBar)
+ # 信号槽
+ self.titleBar.windowMinimumed.connect(self.showMinimized)
+ self.titleBar.windowMaximumed.connect(self.showMaximized)
+ self.titleBar.windowNormaled.connect(self.showNormal)
+ self.titleBar.windowClosed.connect(self.close)
+ self.titleBar.windowMoved.connect(self.move)
+ self.windowTitleChanged.connect(self.titleBar.setTitle)
+ self.windowIconChanged.connect(self.titleBar.setIcon)
+
+ def setTitleBarHeight(self, height=38):
+ """设置标题栏高度"""
+ self.titleBar.setHeight(height)
+
+ def setIconSize(self, size):
+ """设置图标的大小"""
+ self.titleBar.setIconSize(size)
+
+ def setWidget(self, widget):
+ """设置自己的控件"""
+ if hasattr(self, '_widget'):
+ return
+ self._widget = widget
+ # 设置默认背景颜色,否则由于受到父窗口的影响导致透明
+ self._widget.setAutoFillBackground(True)
+ palette = self._widget.palette()
+ palette.setColor(palette.Window, QColor(240, 240, 240))
+ self._widget.setPalette(palette)
+ self._widget.installEventFilter(self)
+ self.layout().addWidget(self._widget)
+
+ def move(self, pos):
+ if self.windowState() == Qt.WindowMaximized or self.windowState() == Qt.WindowFullScreen:
+ # 最大化或者全屏则不允许移动
+ return
+ super(FramelessWindow, self).move(pos)
+
+ def showMaximized(self):
+ """最大化,要去除上下左右边界,如果不去除则边框地方会有空隙"""
+ super(FramelessWindow, self).showMaximized()
+ self.layout().setContentsMargins(0, 0, 0, 0)
+
+ def showNormal(self):
+ """还原,要保留上下左右边界,否则没有边框无法调整"""
+ super(FramelessWindow, self).showNormal()
+ self.layout().setContentsMargins(
+ self.Margins, self.Margins, self.Margins, self.Margins)
+
+ def eventFilter(self, obj, event):
+ """事件过滤器,用于解决鼠标进入其它控件后还原为标准鼠标样式"""
+ if isinstance(event, QEnterEvent):
+ self.setCursor(Qt.ArrowCursor)
+ return super(FramelessWindow, self).eventFilter(obj, event)
+
+ def paintEvent(self, event):
+ """由于是全透明背景窗口,重绘事件中绘制透明度为1的难以发现的边框,用于调整窗口大小"""
+ super(FramelessWindow, self).paintEvent(event)
+ painter = QPainter(self)
+ painter.setPen(QPen(QColor(255, 255, 255, 1), 2 * self.Margins))
+ painter.drawRect(self.rect())
+
+ def mousePressEvent(self, event):
+ """鼠标点击事件"""
+ super(FramelessWindow, self).mousePressEvent(event)
+ if event.button() == Qt.LeftButton:
+ self._mpos = event.pos()
+ self._pressed = True
+
+ def mouseReleaseEvent(self, event):
+ '''鼠标弹起事件'''
+ super(FramelessWindow, self).mouseReleaseEvent(event)
+ self._pressed = False
+ self.Direction = None
+
+ def mouseMoveEvent(self, event):
+ """鼠标移动事件"""
+ super(FramelessWindow, self).mouseMoveEvent(event)
+ pos = event.pos()
+ xPos, yPos = pos.x(), pos.y()
+ wm, hm = self.width() - self.Margins, self.height() - self.Margins
+ if self.isMaximized() or self.isFullScreen():
+ self.Direction = None
+ self.setCursor(Qt.ArrowCursor)
+ return
+ if event.buttons() == Qt.LeftButton and self._pressed:
+ self._resizeWidget(pos)
+ return
+ if xPos <= self.Margins and yPos <= self.Margins:
+ # 左上角
+ self.Direction = LeftTop
+ self.setCursor(Qt.SizeFDiagCursor)
+ elif wm <= xPos <= self.width() and hm <= yPos <= self.height():
+ # 右下角
+ self.Direction = RightBottom
+ self.setCursor(Qt.SizeFDiagCursor)
+ elif wm <= xPos and yPos <= self.Margins:
+ # 右上角
+ self.Direction = RightTop
+ self.setCursor(Qt.SizeBDiagCursor)
+ elif xPos <= self.Margins and hm <= yPos:
+ # 左下角
+ self.Direction = LeftBottom
+ self.setCursor(Qt.SizeBDiagCursor)
+ elif 0 <= xPos <= self.Margins and self.Margins <= yPos <= hm:
+ # 左边
+ self.Direction = Left
+ self.setCursor(Qt.SizeHorCursor)
+ elif wm <= xPos <= self.width() and self.Margins <= yPos <= hm:
+ # 右边
+ self.Direction = Right
+ self.setCursor(Qt.SizeHorCursor)
+ elif self.Margins <= xPos <= wm and 0 <= yPos <= self.Margins:
+ # 上面
+ self.Direction = Top
+ self.setCursor(Qt.SizeVerCursor)
+ elif self.Margins <= xPos <= wm and hm <= yPos <= self.height():
+ # 下面
+ self.Direction = Bottom
+ self.setCursor(Qt.SizeVerCursor)
+
+ def _resizeWidget(self, pos):
+ """调整窗口大小"""
+ if self.Direction == None:
+ return
+ mpos = pos - self._mpos
+ xPos, yPos = mpos.x(), mpos.y()
+ geometry = self.geometry()
+ x, y, w, h = geometry.x(), geometry.y(), geometry.width(), geometry.height()
+ if self.Direction == LeftTop: # 左上角
+ if w - xPos > self.minimumWidth():
+ x += xPos
+ w -= xPos
+ if h - yPos > self.minimumHeight():
+ y += yPos
+ h -= yPos
+ elif self.Direction == RightBottom: # 右下角
+ if w + xPos > self.minimumWidth():
+ w += xPos
+ self._mpos = pos
+ if h + yPos > self.minimumHeight():
+ h += yPos
+ self._mpos = pos
+ elif self.Direction == RightTop: # 右上角
+ if h - yPos > self.minimumHeight():
+ y += yPos
+ h -= yPos
+ if w + xPos > self.minimumWidth():
+ w += xPos
+ self._mpos.setX(pos.x())
+ elif self.Direction == LeftBottom: # 左下角
+ if w - xPos > self.minimumWidth():
+ x += xPos
+ w -= xPos
+ if h + yPos > self.minimumHeight():
+ h += yPos
+ self._mpos.setY(pos.y())
+ elif self.Direction == Left: # 左边
+ if w - xPos > self.minimumWidth():
+ x += xPos
+ w -= xPos
+ else:
+ return
+ elif self.Direction == Right: # 右边
+ if w + xPos > self.minimumWidth():
+ w += xPos
+ self._mpos = pos
+ else:
+ return
+ elif self.Direction == Top: # 上面
+ if h - yPos > self.minimumHeight():
+ y += yPos
+ h -= yPos
+ else:
+ return
+ elif self.Direction == Bottom: # 下面
+ if h + yPos > self.minimumHeight():
+ h += yPos
+ self._mpos = pos
+ else:
+ return
+ self.setGeometry(x, y, w, h)
+
+class MainWindow(QWidget):
+
+ def __init__(self, *args, **kwargs):
+ super(MainWindow, self).__init__(*args, **kwargs)
+ layout = QVBoxLayout(self, spacing=0)
+ layout.setContentsMargins(0, 0, 0, 0)
+
+ # self.left_tag = LeftTabWidget()
+ # layout.addWidget(self.left_tag)
+
+
+if __name__ == '__main__':
+
+ app = QApplication(sys.argv)
+ app.setStyleSheet(StyleSheet)
+ mainWnd = FramelessWindow()
+ mainWnd.setWindowTitle('测试标题栏')
+ mainWnd.setWindowIcon(QIcon('Qt.ico'))
+ mainWnd.resize(QSize(1250,780))
+ mainWnd.setWidget(MainWindow(mainWnd)) # 把自己的窗口添加进来
+ mainWnd.show()
+ sys.exit(app.exec_())
diff --git a/lesson1/流式布局.py b/lesson1/流式布局.py
new file mode 100644
index 0000000..e334476
--- /dev/null
+++ b/lesson1/流式布局.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+from PyQt5.QtCore import QPoint, QRect, QSize, Qt
+from PyQt5.QtWidgets import (QApplication, QLayout, QPushButton, QSizePolicy, QWidget)
+
+
+class Window(QWidget):
+ def __init__(self):
+ super(Window, self).__init__()
+
+ flowLayout = FlowLayout()
+ flowLayout.addWidget(QPushButton("Short"))
+ flowLayout.addWidget(QPushButton("Longer"))
+ flowLayout.addWidget(QPushButton("Different text"))
+ flowLayout.addWidget(QPushButton("More text"))
+ flowLayout.addWidget(QPushButton("Even longer button text"))
+ self.setLayout(flowLayout)
+
+ self.setWindowTitle("Flow Layout")
+
+
+class FlowLayout(QLayout):
+ def __init__(self, parent=None, margin=0, spacing=-1):
+ super(FlowLayout, self).__init__(parent)
+
+ if parent is not None:
+ self.setContentsMargins(margin, margin, margin, margin)
+
+ self.setSpacing(spacing)
+
+ self.itemList = []
+
+ def __del__(self):
+ item = self.takeAt(0)
+ while item:
+ item = self.takeAt(0)
+
+ def addItem(self, item):
+ self.itemList.append(item)
+
+ def count(self):
+ return len(self.itemList)
+
+ def itemAt(self, index):
+ if index >= 0 and index < len(self.itemList):
+ return self.itemList[index]
+
+ return None
+
+ def takeAt(self, index):
+ if index >= 0 and index < len(self.itemList):
+ return self.itemList.pop(index)
+
+ return None
+
+ def expandingDirections(self):
+ return Qt.Orientations(Qt.Orientation(0))
+
+ def hasHeightForWidth(self):
+ return True
+
+ def heightForWidth(self, width):
+ height = self.doLayout(QRect(0, 0, width, 0), True)
+ return height
+
+ def setGeometry(self, rect):
+ super(FlowLayout, self).setGeometry(rect)
+ self.doLayout(rect, False)
+
+ def sizeHint(self):
+ return self.minimumSize()
+
+ def minimumSize(self):
+ size = QSize()
+
+ for item in self.itemList:
+ size = size.expandedTo(item.minimumSize())
+
+ margin, _, _, _ = self.getContentsMargins()
+
+ size += QSize(2 * margin, 2 * margin)
+ return size
+
+ def doLayout(self, rect, testOnly):
+ x = rect.x()
+ y = rect.y()
+ lineHeight = 0
+
+ for item in self.itemList:
+ wid = item.widget()
+ spaceX = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton,
+ QSizePolicy.PushButton, Qt.Horizontal)
+ spaceY = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton,
+ QSizePolicy.PushButton, Qt.Vertical)
+ nextX = x + item.sizeHint().width() + spaceX
+ if nextX - spaceX > rect.right() and lineHeight > 0:
+ x = rect.x()
+ y = y + lineHeight + spaceY
+ nextX = x + item.sizeHint().width() + spaceX
+ lineHeight = 0
+
+ if not testOnly:
+ item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
+
+ x = nextX
+ lineHeight = max(lineHeight, item.sizeHint().height())
+
+ return y + lineHeight - rect.y()
+
+
+if __name__ == '__main__':
+
+ import sys
+
+ app = QApplication(sys.argv)
+ mainWin = Window()
+ mainWin.show()
+ sys.exit(app.exec_())
diff --git a/lesson1/类添加方法.py b/lesson1/类添加方法.py
new file mode 100644
index 0000000..37929d2
--- /dev/null
+++ b/lesson1/类添加方法.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+code = '''def my_function(self):
+ print("Hello, World!")
+ '''
+exec(code, globals())
+class_obj = globals()['my_function']
+# print(class_obj())
+# 创建临时实例方法
+self.temp_method = types.MethodType(class_obj, self)
+#
+# # 调用临时实例方法
+self.temp_method()
\ No newline at end of file