Initial commit
This commit is contained in:
parent
3a26c132fb
commit
f6c8fac77f
3
.idea/.gitignore
vendored
Normal file
3
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
8
.idea/PyQt_Lesson.iml
Normal file
8
.idea/PyQt_Lesson.iml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
7
.idea/misc.xml
Normal file
7
.idea/misc.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.13 (project (3)) (2)" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (project (3)) (2)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/PyQt_Lesson.iml" filepath="$PROJECT_DIR$/.idea/PyQt_Lesson.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
362
lesson1/动态layout.py
Normal file
362
lesson1/动态layout.py
Normal file
@ -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")
|
||||||
|
|
385
lesson1/无边框拖动窗口.py
Normal file
385
lesson1/无边框拖动窗口.py
Normal file
@ -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_())
|
119
lesson1/流式布局.py
Normal file
119
lesson1/流式布局.py
Normal file
@ -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_())
|
12
lesson1/类添加方法.py
Normal file
12
lesson1/类添加方法.py
Normal file
@ -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()
|
Loading…
Reference in New Issue
Block a user