You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
12 KiB
Python
286 lines
12 KiB
Python
from PyQt5 import QtCore, QtWidgets
|
|
from PyQt5.QtCore import QSize, Qt
|
|
from PyQt5.QtGui import QIcon
|
|
from PyQt5.QtWidgets import QSplitter, QPushButton
|
|
import qtawesome as qta
|
|
from .ProjectTable import ProjectTableView
|
|
from model.ProjectModel.ProjectManage import ProjectManage
|
|
|
|
|
|
class ProjectWidgets(QtWidgets.QWidget):
|
|
def __init__(self):
|
|
super(ProjectWidgets, self).__init__()
|
|
self.setAttribute(Qt.WA_StyledBackground, True)
|
|
self.setupUi()
|
|
|
|
def setupButtonIcon(self, button, icon_name, color):
|
|
"""设置按钮图标,支持不同状态的颜色变化"""
|
|
# 正常状态图标
|
|
normal_icon = qta.icon(icon_name, color=color)
|
|
|
|
# 悬停状态图标(稍微亮一些)
|
|
hover_color = self.lightenColor(color, 0.2)
|
|
hover_icon = qta.icon(icon_name, color=hover_color)
|
|
|
|
# 按下状态图标(稍微暗一些)
|
|
pressed_color = self.darkenColor(color, 0.2)
|
|
pressed_icon = qta.icon(icon_name, color=pressed_color)
|
|
|
|
# 设置图标
|
|
button.setIcon(normal_icon)
|
|
|
|
# 存储不同状态的图标,用于状态切换
|
|
button._normal_icon = normal_icon
|
|
button._hover_icon = hover_icon
|
|
button._pressed_icon = pressed_icon
|
|
|
|
# 连接事件
|
|
button.enterEvent = lambda event: self.onButtonEnter(button, event)
|
|
button.leaveEvent = lambda event: self.onButtonLeave(button, event)
|
|
button.mousePressEvent = lambda event: self.onButtonPress(button, event)
|
|
button.mouseReleaseEvent = lambda event: self.onButtonRelease(button, event)
|
|
|
|
def lightenColor(self, color, factor):
|
|
"""使颜色变亮"""
|
|
if color.startswith('#'):
|
|
# 十六进制颜色
|
|
r = int(color[1:3], 16)
|
|
g = int(color[3:5], 16)
|
|
b = int(color[5:7], 16)
|
|
|
|
r = min(255, int(r + (255 - r) * factor))
|
|
g = min(255, int(g + (255 - g) * factor))
|
|
b = min(255, int(b + (255 - b) * factor))
|
|
|
|
return f"#{r:02x}{g:02x}{b:02x}"
|
|
return color
|
|
|
|
def darkenColor(self, color, factor):
|
|
"""使颜色变暗"""
|
|
if color.startswith('#'):
|
|
# 十六进制颜色
|
|
r = int(color[1:3], 16)
|
|
g = int(color[3:5], 16)
|
|
b = int(color[5:7], 16)
|
|
|
|
r = max(0, int(r * (1 - factor)))
|
|
g = max(0, int(g * (1 - factor)))
|
|
b = max(0, int(b * (1 - factor)))
|
|
|
|
return f"#{r:02x}{g:02x}{b:02x}"
|
|
return color
|
|
|
|
def onButtonEnter(self, button, event):
|
|
"""按钮鼠标进入事件"""
|
|
if hasattr(button, '_hover_icon'):
|
|
button.setIcon(button._hover_icon)
|
|
# 调用原始的enterEvent
|
|
QPushButton.enterEvent(button, event)
|
|
|
|
def onButtonLeave(self, button, event):
|
|
"""按钮鼠标离开事件"""
|
|
if hasattr(button, '_normal_icon'):
|
|
button.setIcon(button._normal_icon)
|
|
# 调用原始的leaveEvent
|
|
QPushButton.leaveEvent(button, event)
|
|
|
|
def onButtonPress(self, button, event):
|
|
"""按钮鼠标按下事件"""
|
|
if hasattr(button, '_pressed_icon'):
|
|
button.setIcon(button._pressed_icon)
|
|
# 调用原始的mousePressEvent
|
|
QPushButton.mousePressEvent(button, event)
|
|
|
|
def onButtonRelease(self, button, event):
|
|
"""按钮鼠标释放事件"""
|
|
# 检查鼠标是否还在按钮上
|
|
if button.rect().contains(event.pos()):
|
|
if hasattr(button, '_hover_icon'):
|
|
button.setIcon(button._hover_icon)
|
|
else:
|
|
if hasattr(button, '_normal_icon'):
|
|
button.setIcon(button._normal_icon)
|
|
# 调用原始的mouseReleaseEvent
|
|
QPushButton.mouseReleaseEvent(button, event)
|
|
|
|
def setupUi(self):
|
|
# 新建工程按钮
|
|
self.createBtn = QPushButton('新建工程')
|
|
self.createBtn.setObjectName('createBtn')
|
|
self.createBtn.setIconSize(QSize(18, 18))
|
|
self.createBtn.clicked.connect(self.createProject)
|
|
self.setupButtonIcon(self.createBtn, 'fa5s.plus', '#2277EF')
|
|
|
|
# 导入工程按钮
|
|
self.importBtn = QPushButton('导入工程')
|
|
self.importBtn.setObjectName('importBtn')
|
|
self.importBtn.setIconSize(QSize(18, 18))
|
|
self.importBtn.clicked.connect(self.importProject)
|
|
self.setupButtonIcon(self.importBtn, 'fa5s.file-import', '#059669')
|
|
|
|
# 导出工程按钮
|
|
self.exportBtn = QPushButton('导出工程')
|
|
self.exportBtn.setObjectName('exportBtn')
|
|
self.exportBtn.setIconSize(QSize(18, 18))
|
|
self.exportBtn.clicked.connect(self.exportPorject)
|
|
self.setupButtonIcon(self.exportBtn, 'fa5s.file-export', '#7C3AED')
|
|
|
|
self.projectView = ProjectTableView()
|
|
self.projectView.setObjectName('projectView')
|
|
|
|
self.gridLayout = QtWidgets.QGridLayout(self)
|
|
self.gridLayout.addWidget(self.createBtn, 0, 0, 1, 1)
|
|
self.gridLayout.addWidget(QSplitter(), 0, 1, 1, 20)
|
|
self.gridLayout.addWidget(self.importBtn, 0, 21, 1, 1)
|
|
self.gridLayout.addWidget(self.exportBtn, 0, 22, 1, 1)
|
|
self.gridLayout.addWidget(self.projectView, 1, 0, 10, 23)
|
|
|
|
self.gridLayout.setSpacing(10)
|
|
self.gridLayout.setContentsMargins(20, 30, 20, 20)
|
|
|
|
self.proxy = QtCore.QSortFilterProxyModel(self)
|
|
self.proxy.setSourceModel(self.projectView.model)
|
|
|
|
self.projectView.setModel(self.proxy)
|
|
self.projectView.proxy = self.proxy
|
|
self.projectView.model.initTable()
|
|
|
|
self.horizontalHeader = self.projectView.horizontalHeader()
|
|
self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
|
|
|
|
@QtCore.pyqtSlot(int)
|
|
def on_view_horizontalHeader_sectionClicked(self, logicalIndex):
|
|
self.logicalIndex = logicalIndex
|
|
self.on_comboBox_currentIndexChanged(self.logicalIndex)
|
|
menuName = '_' + str(logicalIndex) + 'Menu'
|
|
if not hasattr(self, menuName):
|
|
setattr(self, menuName, QtWidgets.QMenu(self))
|
|
self.menuValues = getattr(self, menuName)
|
|
menuEdit = QtWidgets.QLineEdit()
|
|
inputAction = QtWidgets.QWidgetAction(self.menuValues)
|
|
inputAction.setDefaultWidget(menuEdit)
|
|
self.menuValues.addAction(inputAction)
|
|
menuEdit.textChanged.connect(self.on_lineEdit_textChanged)
|
|
|
|
self.menuValues = getattr(self, menuName)
|
|
self.romoveAction(self.menuValues)
|
|
|
|
self.signalMapper = QtCore.QSignalMapper(self)
|
|
self.menuValues.mouseReleaseEvent = self._menu_mouseReleaseEvent
|
|
|
|
actionAll = QtWidgets.QAction("All", self)
|
|
actionAll.triggered.connect(self.on_actionAll_triggered)
|
|
actionAll.setProperty('canHide', True)
|
|
actionAll.setCheckable(True)
|
|
self.menuValues.addAction(actionAll)
|
|
self.menuValues.addSeparator()
|
|
|
|
valuesUnique = [self.proxy.data(self.proxy.index(row, self.logicalIndex))
|
|
for row in range(self.proxy.rowCount())
|
|
]
|
|
for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))):
|
|
action = QtWidgets.QAction(str(actionName), self)
|
|
self.signalMapper.setMapping(action, actionNumber)
|
|
action.triggered.connect(self.signalMapper.map)
|
|
action.setCheckable(True)
|
|
self.menuValues.addAction(action)
|
|
|
|
self.signalMapper.mapped.connect(self.on_signalMapper_mapped)
|
|
|
|
headerPos =self.projectView.mapToGlobal(self.horizontalHeader.pos())
|
|
|
|
posY = headerPos.y() + self.horizontalHeader.height()
|
|
posX = headerPos.x() + self.horizontalHeader.sectionPosition(self.logicalIndex)
|
|
getattr(self, menuName).exec_(QtCore.QPoint(posX, posY))
|
|
|
|
@QtCore.pyqtSlot()
|
|
def on_actionAll_triggered(self):
|
|
# 显示全部
|
|
filterColumn = self.logicalIndex
|
|
filterString = QtCore.QRegExp( "",
|
|
QtCore.Qt.CaseInsensitive,
|
|
QtCore.QRegExp.RegExp
|
|
)
|
|
|
|
self.proxy.setFilterRegExp(filterString)
|
|
self.proxy.setFilterKeyColumn(filterColumn)
|
|
|
|
@QtCore.pyqtSlot(int)
|
|
def on_signalMapper_mapped(self, i):
|
|
stringActions = '|'.join([x.text() for x in getattr(self, '_' + str(self.logicalIndex) + 'Menu').actions() if x.isChecked()])
|
|
filterColumn = self.logicalIndex
|
|
filterString = QtCore.QRegExp( stringActions,
|
|
QtCore.Qt.CaseSensitive,
|
|
)
|
|
self.proxy.setFilterRegExp(filterString)
|
|
self.proxy.setFilterKeyColumn(filterColumn)
|
|
|
|
@QtCore.pyqtSlot(str)
|
|
def on_lineEdit_textChanged(self, text):
|
|
# 搜索框文字变化函数
|
|
search = QtCore.QRegExp( text,
|
|
QtCore.Qt.CaseInsensitive,
|
|
QtCore.QRegExp.RegExp
|
|
)
|
|
|
|
self.proxy.setFilterRegExp(search)
|
|
|
|
|
|
@QtCore.pyqtSlot(int)
|
|
def on_comboBox_currentIndexChanged(self, index):
|
|
self.proxy.setFilterKeyColumn(index)
|
|
|
|
def _menu_mouseReleaseEvent(self, event):
|
|
action = self.menuValues.actionAt(event.pos())
|
|
if not action:
|
|
# 没有找到action就交给QMenu自己处理
|
|
return QtWidgets.QMenu.mouseReleaseEvent(self.menuValues, event)
|
|
if action.property('canHide'): # 如果有该属性则给菜单自己处理
|
|
return QtWidgets.QMenu.mouseReleaseEvent(self.menuValues, event)
|
|
# 找到了QAction则只触发Action
|
|
action.activate(action.Trigger)
|
|
|
|
def romoveAction(self, menu):
|
|
# 删除输入框之外的按钮1
|
|
for action in menu.actions():
|
|
if type(action) != QtWidgets.QWidgetAction:
|
|
menu.removeAction(action)
|
|
|
|
def _checkAction(self):
|
|
# 三个action都响应该函数
|
|
self.labelInfo.setText('\n'.join(['{}\t选中:{}'.format(
|
|
action.text(), action.isChecked()) for action in self.menuValues.actions()]))
|
|
|
|
def createProject(self):
|
|
self.projectView.model.append_data(['', '', '', '', '', ''])
|
|
|
|
def exportPorject(self):
|
|
checks = [i for i,x in enumerate(self.projectView.model.checkList) if x == 'Checked']
|
|
if not checks:
|
|
QtWidgets.QMessageBox.warning(self, "Warning", "请勾选想要导出的工程")
|
|
return
|
|
# 弹出一个导出zip文件的文件选择框
|
|
zipName, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Export Project", "", "Project Files (*.project)")
|
|
if not zipName:
|
|
return
|
|
|
|
projects = [self.projectView.model.datas[i][1] for i in checks]
|
|
ProjectManage.exportProject(zipName, projects)
|
|
|
|
def importProject(self):
|
|
# 弹出一个导入zip文件的文件选择框
|
|
zipName, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Import Project", "", "Project Files (*.project)")
|
|
if not zipName:
|
|
return
|
|
repeatProject = ProjectManage.importProject(zipName)
|
|
|
|
if isinstance(repeatProject, set):
|
|
# repeatProject是集合
|
|
QtWidgets.QMessageBox.warning(self, "Warning", "{}工程名称重复".format(str(repeatProject)[1:-1]))
|
|
return
|
|
else:
|
|
# repeatProject不是集合
|
|
for name in repeatProject:
|
|
proMes = ProjectManage.getByName(name)
|
|
proMes.append('')
|
|
self.projectView.model.append_data(proMes) |