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