This commit is contained in:
2026-07-17 15:27:33 +08:00
parent 6bb68eb6b7
commit 207cbde4bc
14 changed files with 498 additions and 301 deletions
+3 -2
View File
@@ -12,7 +12,8 @@ Version: 0.0.1
""" """
from .logging.log import FrameLog from .logging.log import FrameLog
from .tools.tools import ToolsWindow # FromTools → ToolsWindow from .plugin.plugins import Plugins
from .plugin.plugin_registry import PluginRegistry
__all__ = ["FrameLog", "ToolsWindow"] __all__ = ["FrameLog", "ToolsWindow","PluginRegistry"]
+127
View File
@@ -0,0 +1,127 @@
import os
import sys
import time
import logging
import importlib
import threading
from pathlib import Path
from enum import Enum, auto
from PySide6.QtCore import QObject,Signal
from dataclasses import dataclass, field, fields
LOCAL_PLUGINS_PATH = Path("./plugins")
REMOTE_PLUGINS_PATH = Path('Y:/SE/xufeifei/plugins')
logger = logging.getLogger(__name__)
class Event(Enum):
Update = auto()
Install = auto()
Uninstall = auto()
class PluginRegistry(QObject):
"""插件注册中心。"""
plugins_loader_signal = Signal(dict)
update_plugins_card_signal = Signal(dict)
def __init__(self, parent = None) -> None:
super().__init__(parent)
self.plugins = dict()
self.start_discover_local(LOCAL_PLUGINS_PATH, self.plugins)
self.start_discover_remote(REMOTE_PLUGINS_PATH, self.plugins)
def start_discover_local(self,plugins_dir: Path, plugins:dict):
self.thread_local = threading.Thread(target= self.discover_local_event,args=(plugins_dir, plugins,))
self.thread_local.start()
def discover_local_event(self, plugins_dir: Path, plugins:dict):
if not os.path.exists(plugins_dir):
os.mkdir(plugins_dir)
return
sys.path.append(str(plugins_dir))
for tool in Path(plugins_dir).glob("*.pyd"):
tool_name = tool.stem
try:
module = importlib.import_module(tool_name)
obj = module.create_plugin()
name = module.read_plugin_name()
version = module.read_plugin_version()
if name in plugins.keys():
pass
else:
plugins[name] = {}
plugins[name]['obj'] = obj
plugins[name]['local version'] = version
except Exception as e:
logger.error(f"插件{tool_name}注册失败,{str(e)}")
sys.path.remove(str(LOCAL_PLUGINS_PATH))
self.plugins_loader_signal.emit(plugins)
def start_discover_remote(self,plugins_dir: Path, plugins:dict):
self.thread_remote = threading.Thread(target= self.discover_remote_event,args=(plugins_dir, plugins,))
self.thread_remote.start()
def discover_remote_event(self, plugins_dir: Path, plugins:dict):
if not os.path.exists(plugins_dir):
logger.error("服务器链接错误!")
return
#读取服务器工具信息
time.sleep(0.01)
sys.path.append(str(plugins_dir))
for tool in Path(plugins_dir).glob("*.pyd"):
tool_name = tool.stem
try:
module = importlib.import_module(tool_name)
name = module.read_plugin_name()
version = module.read_plugin_version()
description = module.read_plugin_description()
if name in plugins.keys():
pass
else:
print("discover_remote_event")
plugins[name] = {}
plugins[name]["tool_name"] = tool_name
plugins[name]["local version"] = None
plugins[name]["local description"] = None
plugins[name]["remote version"] = version
plugins[name]["remote description"] = description
plugins[name]['remote path'] = plugins_dir
except Exception as e:
logger.error(f"服务器{tool_name}无法加载:{str(e)}")
sys.path.remove(str(plugins_dir))
self.update_plugins_card_signal.emit(plugins)
def start_plugins_event(self, event:Event, name:str):
if event == Event.Install:
local_path = str(LOCAL_PLUGINS_PATH) + '\\' + f"{self.plugins[name]['tool_name']}.pyd"
remote_path = str(REMOTE_PLUGINS_PATH) + '\\' + f"{self.plugins[name]['tool_name']}.pyd"
self.sub_thread = threading.Thread(target= self.install_plugins_event,args=(local_path,remote_path,))
self.sub_thread.start()
pass
def install_plugins_event(self, local_path, remote_path):
try:
total_size = os.path.getsize(remote_path)
copied_size = 0
with open(remote_path, 'rb') as fsrc, open(local_path, 'wb') as fdst:
while True:
buf = fsrc.read(1024*1024)
if not buf:
break
fdst.write(buf)
copied_size += len(buf)
logger.info(f"安装进度: {copied_size/1024/1024:.2f} MB / {total_size/1024/1024:.2f} MB")
time.sleep(0.1)
logger.info(f"{local_path}安装成功!!!")
except Exception as e:
logger.error(f"{remote_path}安装失败{e.args}")
return
+150
View File
@@ -0,0 +1,150 @@
"""
工具箱模块
提供工具箱主窗口,包含各种实用工具的入口。
使用 PySide6 构建的窗口框架。
主要功能:
- 工具箱主窗口界面
- 窗口居中显示功能
- 工具分类和导航
Author: Model Team
Version: 0.0.1
"""
import os
import sys
import logging
import threading
import importlib
from qt_material import apply_stylesheet
from pathlib import Path
from .plugins_ui import Ui_FormPlugins
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QWidget, QListWidgetItem
from PySide6.QtCore import QSize,Signal
from .plugins_card import PluginsCard
from .plugin_registry import PluginRegistry
logger = logging.getLogger(__name__)
LOCAL_PLUGINS_PATH = Path("./plugins")
REMOTE_PLUGINS_PATH = Path('Y:/SE/xufeifei/plugins')
class Plugins(QWidget, Ui_FormPlugins):
"""工具箱主窗口类
继承自 QWidgetQt 窗口基类)和 Ui_FormToolsQt Designer 生成的 UI 界面)
负责显示工具箱的主界面,提供工具的分类和导航功能。
窗口特性:
- 默认尺寸: 400x293 像素
- 支持窗口居中显示
- 可作为独立窗口或嵌入其他窗口使用
Attributes:
parent: 父窗口对象,默认为 None(顶级窗口)
"""
update_tool_card = Signal(dict)
def __init__(self, plugin_registry:PluginRegistry, parent: QWidget = None) -> None:
"""初始化工具箱窗口
创建工具箱窗口实例,初始化 UI 界面。
Args:
parent: 父窗口对象,用于建立父子关系。
默认为 None,表示这是顶级窗口。
"""
super().__init__(parent)
self.setupUi(self)
self.plugin_registry = plugin_registry
self.initUI()
self.load_stylesheet()
self.plugin_registry.update_plugins_card_signal.connect(self.on_update_plugins_card)
def initUI(self) -> None:
"""
初始化用户界面
配置窗口标题、图标、大小和居中显示。
"""
self.setWindowTitle("工具箱")
self.setWindowIcon(QIcon('resources/tools.ico'))
# self.update_tool_card.connect(self.on_update_tool_card)
def load_stylesheet(self) -> None:
"""
加载 Qt 样式表和自定义样式文件
使用 qt_material 库加载暗色主题,并应用自定义 QSS 样式表
失败时记录错误日志,但不影响应用继续运行(降级策略)
异常处理:
- FileNotFoundError: 样式文件不存在
- RuntimeError: 主题加载失败
- 其他异常: 记录警告但不中断应用
"""
try:
apply_stylesheet(self, style=None,theme='dark_teal.xml', css_file='resources/my.qss')
except FileNotFoundError as e:
logger.warning(f"样式文件未找到,使用默认主题: {e}")
except RuntimeError as e:
logger.warning(f"主题加载失败,使用默认主题: {e}")
except Exception as e:
logger.warning(f"样式加载失败,使用默认主题: {e}")
# def start_load_tools(self):
# self.sub_thread = threading.Thread(target= self.load_tool_list,args=(self.tools,))
# self.sub_thread.start()
# def load_tool_list(self, tools:dict):
# if not os.path.exists(REMOTE_PLUGINS_PATH):
# logger.error("服务器链接错误!")
# return
# #读取服务器工具信息
# sys.path.append(str(REMOTE_PLUGINS_PATH))
# for tool in Path(REMOTE_PLUGINS_PATH).glob("*.pyd"):
# tool_name = tool.stem
# try:
# module = importlib.import_module(tool_name)
# name = module.read_tool_name()
# version = module.read_tool_version()
# description = module.read_tool_description()
# if name in tools.keys():
# pass
# else:
# tools[name] = {}
# tools[name]["name"] = tool_name
# tools[name]["local version"] = None
# tools[name]["local description"] = None
# tools[name]["remote version"] = version
# tools[name]["remote description"] = description
# tools[name]['remote path'] = REMOTE_PLUGINS_PATH
# except Exception as e:
# logger.error(f"服务器{tool_name}无法加载:{str(e)}")
# sys.path.remove(str(REMOTE_PLUGINS_PATH))
# self.update_tool_card.emit(tools)
def on_update_plugins_card(self, plugins:dict):
# print(plugins)
for name in plugins.keys():
item = QListWidgetItem(self.listWidget)
plugin_card = PluginsCard(name, plugins[name])
plugin_card.send_event_signal.connect(self.plugin_registry.start_plugins_event)
item.setSizeHint(QSize(plugin_card.sizeHint().width(), 200))
self.listWidget.addItem(item)
self.listWidget.setCurrentItem(item)
self.listWidget.setItemWidget(item, plugin_card)
pass
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>FormTools</class> <class>FormPlugins</class>
<widget class="QWidget" name="FormTools"> <widget class="QWidget" name="FormPlugins">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
+52
View File
@@ -0,0 +1,52 @@
import os
import time
import logging
import threading
from .plugin_registry import Event
from PySide6.QtWidgets import QFrame
from PySide6.QtCore import Signal
from .plugins_card_ui import Ui_FramePluginsCard
logger = logging.getLogger(__name__)
class PluginsCard(QFrame, Ui_FramePluginsCard):
"""工具卡片类
继承自 QFrameQt 帧基类)和 Ui_FrameToolCardQt Designer 生成的 UI 界面)
负责显示工具的卡片界面,包含工具的图标、名称和描述。
"""
send_event_signal = Signal(Event,str)
def __init__(self, name: str, info:dict, parent=None) -> None:
super().__init__(parent)
self.setupUi(self)
self.name = name
self.info = info
self.initUI()
def initUI(self):
self.textBrowser.setReadOnly(True)
self.textBrowser.setMarkdown(self.to_card())
if self.info["local version"] is None:
self.pushButtonUpdate.setEnabled(False)
self.pushButtonUninstall.setEnabled(False)
else:
self.pushButtonInstall.setEnabled(False)
if self.info['remote version'] <= self.info['local version']:
self.pushButtonUpdate.setEnabled(False)
self.pushButtonInstall.clicked.connect(self.on_intsall_event)
def to_card(self):
card = f"# {self.name}\n\n"
card += f"**最新:** V{self.info['remote version']}\n\n"
if self.info['local version'] is None:
card += f"**当前:** 未安装!\n\n"
else:
card += f"**当前:** V{self.info['local version']}\n\n"
card += f"**描述:** {self.info['remote description']}"
return card
def on_intsall_event(self):
self.send_event_signal.emit(Event.Install, self.name)
@@ -1,48 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>FrameToolCard</class> <class>FramePluginsCard</class>
<widget class="QFrame" name="FrameToolCard"> <widget class="QFrame" name="FramePluginsCard">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>491</width> <width>357</width>
<height>64</height> <height>120</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Frame</string> <string>Frame</string>
</property> </property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QTextBrowser" name="textBrowser"/>
</item>
<item row="0" column="1">
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="2" column="0">
<widget class="QLabel" name="labelName">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pushButtonInstall">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>安装</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="pushButtonUninstall"> <widget class="QPushButton" name="pushButtonUninstall">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@@ -55,7 +41,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="3"> <item row="3" column="0">
<widget class="QPushButton" name="pushButtonUpdate"> <widget class="QPushButton" name="pushButtonUpdate">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@@ -68,21 +54,34 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QPushButton" name="pushButtonInstall">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>安装</string>
</property>
</widget>
</item>
<item row="0" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</item> </item>
<item row="1" column="0">
<widget class="QLabel" name="labelInfo">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>
+84
View File
@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'plugins_card.ui'
##
## Created by: Qt User Interface Compiler version 6.11.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QPushButton,
QSizePolicy, QSpacerItem, QTextBrowser, QWidget)
class Ui_FramePluginsCard(object):
def setupUi(self, FramePluginsCard):
if not FramePluginsCard.objectName():
FramePluginsCard.setObjectName(u"FramePluginsCard")
FramePluginsCard.resize(357, 120)
sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(FramePluginsCard.sizePolicy().hasHeightForWidth())
FramePluginsCard.setSizePolicy(sizePolicy)
FramePluginsCard.setAutoFillBackground(True)
self.gridLayout_2 = QGridLayout(FramePluginsCard)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.textBrowser = QTextBrowser(FramePluginsCard)
self.textBrowser.setObjectName(u"textBrowser")
self.gridLayout_2.addWidget(self.textBrowser, 0, 0, 1, 1)
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.pushButtonUninstall = QPushButton(FramePluginsCard)
self.pushButtonUninstall.setObjectName(u"pushButtonUninstall")
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.pushButtonUninstall.sizePolicy().hasHeightForWidth())
self.pushButtonUninstall.setSizePolicy(sizePolicy1)
self.gridLayout.addWidget(self.pushButtonUninstall, 2, 0, 1, 1)
self.pushButtonUpdate = QPushButton(FramePluginsCard)
self.pushButtonUpdate.setObjectName(u"pushButtonUpdate")
sizePolicy1.setHeightForWidth(self.pushButtonUpdate.sizePolicy().hasHeightForWidth())
self.pushButtonUpdate.setSizePolicy(sizePolicy1)
self.gridLayout.addWidget(self.pushButtonUpdate, 3, 0, 1, 1)
self.pushButtonInstall = QPushButton(FramePluginsCard)
self.pushButtonInstall.setObjectName(u"pushButtonInstall")
sizePolicy1.setHeightForWidth(self.pushButtonInstall.sizePolicy().hasHeightForWidth())
self.pushButtonInstall.setSizePolicy(sizePolicy1)
self.gridLayout.addWidget(self.pushButtonInstall, 1, 0, 1, 1)
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
self.gridLayout.addItem(self.verticalSpacer, 0, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 1, 1, 1)
self.retranslateUi(FramePluginsCard)
QMetaObject.connectSlotsByName(FramePluginsCard)
# setupUi
def retranslateUi(self, FramePluginsCard):
FramePluginsCard.setWindowTitle(QCoreApplication.translate("FramePluginsCard", u"Frame", None))
self.pushButtonUninstall.setText(QCoreApplication.translate("FramePluginsCard", u"\u5378\u8f7d", None))
self.pushButtonUpdate.setText(QCoreApplication.translate("FramePluginsCard", u"\u66f4\u65b0", None))
self.pushButtonInstall.setText(QCoreApplication.translate("FramePluginsCard", u"\u5b89\u88c5", None))
# retranslateUi
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################ ################################################################################
## Form generated from reading UI file 'tools.ui' ## Form generated from reading UI file 'plugins.ui'
## ##
## Created by: Qt User Interface Compiler version 6.11.1 ## Created by: Qt User Interface Compiler version 6.11.1
## ##
@@ -18,30 +18,30 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
from PySide6.QtWidgets import (QApplication, QGridLayout, QListWidget, QListWidgetItem, from PySide6.QtWidgets import (QApplication, QGridLayout, QListWidget, QListWidgetItem,
QSizePolicy, QWidget) QSizePolicy, QWidget)
class Ui_FormTools(object): class Ui_FormPlugins(object):
def setupUi(self, FormTools): def setupUi(self, FormPlugins):
if not FormTools.objectName(): if not FormPlugins.objectName():
FormTools.setObjectName(u"FormTools") FormPlugins.setObjectName(u"FormPlugins")
FormTools.resize(810, 423) FormPlugins.resize(810, 423)
sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(FormTools.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(FormPlugins.sizePolicy().hasHeightForWidth())
FormTools.setSizePolicy(sizePolicy) FormPlugins.setSizePolicy(sizePolicy)
self.gridLayout = QGridLayout(FormTools) self.gridLayout = QGridLayout(FormPlugins)
self.gridLayout.setObjectName(u"gridLayout") self.gridLayout.setObjectName(u"gridLayout")
self.listWidget = QListWidget(FormTools) self.listWidget = QListWidget(FormPlugins)
self.listWidget.setObjectName(u"listWidget") self.listWidget.setObjectName(u"listWidget")
self.gridLayout.addWidget(self.listWidget, 0, 0, 1, 1) self.gridLayout.addWidget(self.listWidget, 0, 0, 1, 1)
self.retranslateUi(FormTools) self.retranslateUi(FormPlugins)
QMetaObject.connectSlotsByName(FormTools) QMetaObject.connectSlotsByName(FormPlugins)
# setupUi # setupUi
def retranslateUi(self, FormTools): def retranslateUi(self, FormPlugins):
FormTools.setWindowTitle(QCoreApplication.translate("FormTools", u"Form", None)) FormPlugins.setWindowTitle(QCoreApplication.translate("FormPlugins", u"Form", None))
# retranslateUi # retranslateUi
-15
View File
@@ -1,15 +0,0 @@
from PySide6.QtWidgets import QFrame
from .tool_card_ui import Ui_FrameToolCard
class ToolCard(QFrame, Ui_FrameToolCard):
"""工具卡片类
继承自 QFrameQt 帧基类)和 Ui_FrameToolCardQt Designer 生成的 UI 界面)
负责显示工具的卡片界面,包含工具的图标、名称和描述。
"""
def __init__(self, parent = None) -> None:
super().__init__(parent)
self.setupUi(self)
-91
View File
@@ -1,91 +0,0 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'tool_card.ui'
##
## Created by: Qt User Interface Compiler version 6.11.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QFrame, QGridLayout, QLabel,
QPushButton, QSizePolicy, QWidget)
class Ui_FrameToolCard(object):
def setupUi(self, FrameToolCard):
if not FrameToolCard.objectName():
FrameToolCard.setObjectName(u"FrameToolCard")
FrameToolCard.resize(491, 64)
self.gridLayout_2 = QGridLayout(FrameToolCard)
self.gridLayout_2.setObjectName(u"gridLayout_2")
self.gridLayout = QGridLayout()
self.gridLayout.setObjectName(u"gridLayout")
self.labelName = QLabel(FrameToolCard)
self.labelName.setObjectName(u"labelName")
sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.labelName.sizePolicy().hasHeightForWidth())
self.labelName.setSizePolicy(sizePolicy)
self.gridLayout.addWidget(self.labelName, 0, 0, 1, 1)
self.pushButtonInstall = QPushButton(FrameToolCard)
self.pushButtonInstall.setObjectName(u"pushButtonInstall")
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.pushButtonInstall.sizePolicy().hasHeightForWidth())
self.pushButtonInstall.setSizePolicy(sizePolicy1)
self.gridLayout.addWidget(self.pushButtonInstall, 0, 1, 1, 1)
self.pushButtonUninstall = QPushButton(FrameToolCard)
self.pushButtonUninstall.setObjectName(u"pushButtonUninstall")
sizePolicy1.setHeightForWidth(self.pushButtonUninstall.sizePolicy().hasHeightForWidth())
self.pushButtonUninstall.setSizePolicy(sizePolicy1)
self.gridLayout.addWidget(self.pushButtonUninstall, 0, 2, 1, 1)
self.pushButtonUpdate = QPushButton(FrameToolCard)
self.pushButtonUpdate.setObjectName(u"pushButtonUpdate")
sizePolicy1.setHeightForWidth(self.pushButtonUpdate.sizePolicy().hasHeightForWidth())
self.pushButtonUpdate.setSizePolicy(sizePolicy1)
self.gridLayout.addWidget(self.pushButtonUpdate, 0, 3, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
self.labelInfo = QLabel(FrameToolCard)
self.labelInfo.setObjectName(u"labelInfo")
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Expanding)
sizePolicy2.setHorizontalStretch(0)
sizePolicy2.setVerticalStretch(0)
sizePolicy2.setHeightForWidth(self.labelInfo.sizePolicy().hasHeightForWidth())
self.labelInfo.setSizePolicy(sizePolicy2)
self.gridLayout_2.addWidget(self.labelInfo, 1, 0, 1, 1)
self.retranslateUi(FrameToolCard)
QMetaObject.connectSlotsByName(FrameToolCard)
# setupUi
def retranslateUi(self, FrameToolCard):
FrameToolCard.setWindowTitle(QCoreApplication.translate("FrameToolCard", u"Frame", None))
self.labelName.setText(QCoreApplication.translate("FrameToolCard", u"Name", None))
self.pushButtonInstall.setText(QCoreApplication.translate("FrameToolCard", u"\u5b89\u88c5", None))
self.pushButtonUninstall.setText(QCoreApplication.translate("FrameToolCard", u"\u5378\u8f7d", None))
self.pushButtonUpdate.setText(QCoreApplication.translate("FrameToolCard", u"\u66f4\u65b0", None))
self.labelInfo.setText(QCoreApplication.translate("FrameToolCard", u"TextLabel", None))
# retranslateUi
-127
View File
@@ -1,127 +0,0 @@
"""
工具箱模块
提供工具箱主窗口,包含各种实用工具的入口。
使用 PySide6 构建的窗口框架。
主要功能:
- 工具箱主窗口界面
- 窗口居中显示功能
- 工具分类和导航
Author: Model Team
Version: 0.0.1
"""
import os
import sys
import logging
import importlib.util
from qt_material import apply_stylesheet
from pathlib import Path
from .tools_ui import Ui_FormTools
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QWidget, QListWidgetItem
logger = logging.getLogger(__name__)
PLUGINS_PATH = Path('Y:/SE/xufeifei/plugins')
class ToolsWindow(QWidget, Ui_FormTools):
"""工具箱主窗口类
继承自 QWidgetQt 窗口基类)和 Ui_FormToolsQt Designer 生成的 UI 界面)
负责显示工具箱的主界面,提供工具的分类和导航功能。
窗口特性:
- 默认尺寸: 400x293 像素
- 支持窗口居中显示
- 可作为独立窗口或嵌入其他窗口使用
Attributes:
parent: 父窗口对象,默认为 None(顶级窗口)
"""
def __init__(self, tools:dict, parent: QWidget = None) -> None:
"""初始化工具箱窗口
创建工具箱窗口实例,初始化 UI 界面。
Args:
parent: 父窗口对象,用于建立父子关系。
默认为 None,表示这是顶级窗口。
"""
super().__init__(parent)
self.setupUi(self)
self.tools = tools
self.initUI()
self.init_tool_list()
self.load_stylesheet()
def initUI(self) -> None:
"""
初始化用户界面
配置窗口标题、图标、大小和居中显示。
"""
self.setWindowTitle("工具箱")
self.setWindowIcon(QIcon('resources/tools.ico'))
def load_stylesheet(self) -> None:
"""
加载 Qt 样式表和自定义样式文件
使用 qt_material 库加载暗色主题,并应用自定义 QSS 样式表
失败时记录错误日志,但不影响应用继续运行(降级策略)
异常处理:
- FileNotFoundError: 样式文件不存在
- RuntimeError: 主题加载失败
- 其他异常: 记录警告但不中断应用
"""
try:
apply_stylesheet(self, style=None,theme='dark_teal.xml', css_file='resources/my.qss')
except FileNotFoundError as e:
logger.warning(f"样式文件未找到,使用默认主题: {e}")
except RuntimeError as e:
logger.warning(f"主题加载失败,使用默认主题: {e}")
except Exception as e:
logger.warning(f"样式加载失败,使用默认主题: {e}")
def init_tool_list(self):
if not os.path.exists(PLUGINS_PATH):
logger.error("服务器链接错误!")
return
sys.path.append(str(PLUGINS_PATH))
for tool in Path(PLUGINS_PATH).glob("*.pyd"):
tool_name = tool.stem
try:
module = importlib.import_module(tool_name)
name = module.read_tool_name()
version = module.read_tool_version()
description = module.read_tool_description()
if name in self.tools.keys():
pass
else:
self.tools[name] = {}
self.tools[name]["version"] = version
self.tools[name]["description"] = description
except Exception as e:
logger.error(f"{tool_name}无法加载:{str(e)}")
# if
sys.path.remove(str(PLUGINS_PATH))
def on_update_tool_card(self):
# for ke
# item = QListWidgetItem()
pass
+13 -5
View File
@@ -10,10 +10,12 @@ Model Team Tools - 主程序入口
- 配置菜单栏和状态栏 - 配置菜单栏和状态栏
- 提供统一的日志记录接口 - 提供统一的日志记录接口
""" """
import os
import sys import sys
import logging import logging
import core import core
import traceback import traceback
import importlib
from pathlib import Path from pathlib import Path
@@ -33,6 +35,7 @@ MICRO_VER: int = 1 # 修订版本号
APP_NAME: str = "Model Team Tools" APP_NAME: str = "Model Team Tools"
APP_VERSION: str = f"{MAJOR_VER}.{MINOR_VER}.{MICRO_VER}" APP_VERSION: str = f"{MAJOR_VER}.{MINOR_VER}.{MICRO_VER}"
LOCAL_PLUGINS_PATH = Path("./plugins")
class MainWindow(QMainWindow, Ui_MainWindow): class MainWindow(QMainWindow, Ui_MainWindow):
""" """
@@ -45,9 +48,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self) -> None: def __init__(self) -> None:
super().__init__() super().__init__()
self.setupUi(self) self.setupUi(self)
self.initUI()
self.tools = dict() self.plugin_registry = core.PluginRegistry()
self.plugins = core.Plugins(self.plugin_registry)
self.plugin_registry.plugins_loader_signal.connect(self.on_plugins_loader)
self.initUI()
def initUI(self) -> None: def initUI(self) -> None:
""" """
@@ -108,13 +114,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
- 打开失败时记录 ERROR 级别日志 - 打开失败时记录 ERROR 级别日志
""" """
try: try:
self.tool_window = core.ToolsWindow(self.tools) self.plugins.show()
self.tool_window.show()
# logger.info("工具箱窗口已打开")
except Exception as e: except Exception as e:
logger.error(f"无法打开工具箱窗口: {e}") logger.error(f"无法打开工具箱窗口: {e}")
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
def on_plugins_loader(self, plugins:dict):
for name in plugins.keys():
self.stackedWidget.addWidget(plugins[name]['obj'])
if __name__ == '__main__': if __name__ == '__main__':
app = QApplication(sys.argv) app = QApplication(sys.argv)
+8
View File
@@ -0,0 +1,8 @@
{
"DataPath": "",
"FilePath": "",
"AddTimeEn": true,
"GeratePath": true,
"CurrProject": "",
"ItemConfigs": {}
}
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 512 512"><path fill="#1de9b6" d="M495.855 367.604c-28.98-73.177-53.037-148.231-80.725-221.893c-12.23-31.362-24.198-62.986-40.868-92.33c-6.62-10.535-12.956-22.119-23.814-28.86c-2.739-1.74-5.828-2.479-8.88-2.42c-5.084.096-10.14 2.37-14.025 5.65c-14.571 11.543-23.209 28.334-32.896 43.793c-17.114 28.698-35.156 58.748-63.773 77.396c-13.44 9.485-31.039 10.514-43.995 20.686c-17.72 13.36-29.767 32.31-44.298 48.737c-3.31 3.956-8.436 5.53-12.916 7.67C86.315 243.71 42.945 261.35 0 279.916c36.367 28.132 75.115 53.157 112.208 80.321c10.172-2.018 20.383-6.196 30.877-4.339c16.63 5.207 26.377 21.15 34.006 35.721c15.5 31.765 26.7 65.307 39.253 98.283c20.988-1.493 39.878-12.31 56.104-25.025c31.24-25.307 55.034-58.001 81.23-88.192c12.552-13.199 25.347-28.92 44.197-32.593c19.05-4.601 39.454 2.22 53.581 15.338c19.818 17.719 37.376 38.203 60.544 51.765c-3.108-15.338-10.575-29.101-16.145-43.592M171.844 316.04c-18.284 10.817-37.699 19.717-56.71 29.162c-29.828-19.98-58.889-41.15-88.192-61.856c39.515-17.315 79.635-33.4 119.675-49.545c18.97 14.813 38.547 28.88 57.517 43.693c-8.92 14.248-19.657 27.487-32.29 38.546m40.665-49.646c-18.85-14.167-37.94-27.951-56.508-42.482c11.907-16.226 24.945-31.906 40.565-44.701c10.333-6.62 22.966-8.456 33.703-14.43c25.469-12.714 42.845-36.044 59.434-58.324c-21.271 55.216-43.975 110.654-77.194 159.937"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB