一个基于配置驱动的模块化Qt组件创建框架。通过简单的配置文件,即可创建复杂的Qt界面,无需编写大量重复的UI代码。
pip install modular-qtwidgets
一个基于配置驱动的模块化Qt组件创建框架。通过简单的配置文件,即可创建复杂的Qt界面,无需编写大量重复的UI代码。
pip install modular-qtwidgets
配置文件使用YAML格式,主要包含以下部分:
widget_system:
# 全局配置
config:
default_group_enabled: true # 默认组是否启用
default_widget_enabled: true # 默认组件是否启用
# 组件创建策略配置
strategies:
- name: "QWidgetStrategy" # 策略名称
description: "策略描述" # 策略描述
enabled: true # 是否启用
path: "path/to/strategy.py" # 策略类文件路径
class: StrategyClassName # 策略类名
# 组件组配置
groups:
group_name: # 组名称
enabled: true # 是否启用
description: "组描述" # 组描述
widgets: # 组内组件列表
widget_name: # 组件名称
enabled: true # 是否启用
path: "path/to/widget.py" # 组件类文件路径
class: WidgetClassName # 组件类名
priority: 0 # 显示优先级(数字越小优先级越高)
description: "组件描述" # 组件描述
strategy: "策略名称" # 使用的创建策略
params: # 组件初始化参数
param1: value1
param2: value2
使用 WidgetCreationService
来加载和创建组件:
from modular_qtwidgets import WidgetCreationService
# 初始化服务
service = WidgetCreationService("config.yaml")
# 为特定位置创建组件
def on_widget_created(widget, widget_name, widget_config):
"""组件创建回调函数
Args:
widget: 创建的组件实例
widget_name: 配置中的组件名称
widget_config: 组件的配置信息
"""
# 处理新创建的组件
pass
# 创建指定位置的所有组件
widgets = service.create_widgets_for_location("group_name", on_widget_created)
创建自定义组件策略:
from modular_qtwidgets import WidgetCreationStrategy
from PySide6.QtWidgets import QWidget
class CustomWidgetStrategy(WidgetCreationStrategy):
def can_handle(self, widget_class: Type) -> bool:
"""检查是否可以处理该组件类"""
return issubclass(widget_class, QWidget)
def create_widget(self, widget_class: Type, params: Dict[str, Any] = None) -> QWidget:
"""创建组件实例"""
if params is None:
params = {}
return widget_class(**params)
# 注册策略
service.register_strategy("CustomStrategy", CustomWidgetStrategy())
如果你有一个主窗口,想要在其中的垂直布局中加载配置的组件,可以这样做:
from PySide6.QtWidgets import QWidget, QVBoxLayout, QScrollArea
from modular_qtwidgets import WidgetCreationService
class MainWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setup_ui()
self.load_widgets()
def setup_ui(self):
# 创建主布局
self.main_layout = QVBoxLayout(self)
self.setLayout(self.main_layout)
# 创建滚动区域(可选,用于内容超出窗口时)
self.scroll_area = QScrollArea(self)
self.scroll_area.setWidgetResizable(True)
self.main_layout.addWidget(self.scroll_area)
# 创建容器组件
self.container = QWidget()
self.scroll_area.setWidget(self.container)
self.container_layout = QVBoxLayout(self.container)
# 在底部添加弹性空间(可选,使组件靠上对齐)
self.container_layout.addStretch()
def load_widgets(self):
try:
# 创建组件服务
service = WidgetCreationService("config.yaml")
# 定义组件创建回调
def on_widget_created(widget, widget_name, widget_config):
# 将新组件插入到弹性空间之前
self.container_layout.insertWidget(
self.container_layout.count() - 1, # 插入到最后一个项目(弹性空间)之前
widget
)
# 创建指定位置的所有组件
widgets = service.create_widgets_for_location(
"your_group_name", # 配置文件中定义的组名
on_widget_created
)
if not widgets:
# 处理没有组件的情况
pass
except Exception as e:
# 处理错误情况
pass
这个实现提供了以下功能:
- 滚动支持:当组件总高度超过窗口高度时,可以滚动查看
- 自动布局:组件会自动垂直排列
- 靠上对齐:通过底部的弹性空间,组件会靠上对齐
- 动态加载:组件是根据配置动态创建的
配置文件示例:
widget_system:
config:
default_group_enabled: true
default_widget_enabled: true
strategies:
- name: "QWidgetStrategy"
enabled: true
path: "path/to/strategies.py"
class: QtWidgetStrategy
groups:
your_group_name:
enabled: true
description: "Your group description"
widgets:
widget1:
enabled: true
path: "path/to/widget1.py"
class: Widget1Class
priority: 0
strategy: "QWidgetStrategy"
params:
param1: value1
widget2:
enabled: true
path: "path/to/widget2.py"
class: Widget2Class
priority: 1
strategy: "QWidgetStrategy"
params:
param2: value2
注意事项:
- 组件会按照
priority
值从小到大的顺序创建和添加 - 每个组件的具体参数在
params
中定义 - 确保配置文件中的路径是正确的
- 可以通过
enabled
字段控制组件是否加载
如果你是从 GitHub 克隆此仓库进行开发,请按照以下步骤操作:
-
克隆仓库:
git clone <repository_url> cd modular_qtwidgets
-
创建并激活虚拟环境(推荐):
# Windows python -m venv .venv .venv\Scripts\activate # Linux/macOS python -m venv .venv source .venv/bin/activate
-
安装开发依赖:
# 安装基本依赖 pip install -e . # 安装测试依赖 pip install -e ".[test]"
本项目使用 pytest 进行测试。测试套件包括单元测试和集成测试,涵盖了以下方面:
-
组件创建服务测试:
- 服务初始化
- 策略注册
- 组件创建
- 回调函数
- 错误处理
-
组件策略测试:
- QWidget 类型检查
- 参数处理
- 错误处理
-
集成测试:
- 主窗口集成
- 组件创建顺序
运行测试:
# 运行所有测试
pytest
# 运行特定测试文件
pytest tests/unit/test_widget_creation_service.py
# 运行带覆盖率报告的测试
pytest --cov=modular_qtwidgets
# 运行特定测试用例
pytest tests/unit/test_widget_creation_service.py::test_service_initialization
如果你要为项目添加新的测试,请遵循以下规则:
-
测试文件组织:
- 单元测试放在
tests/unit/
目录下 - 集成测试放在
tests/integration/
目录下 - 测试固件放在
tests/fixtures/
目录下
- 单元测试放在
-
命名约定:
- 测试文件名以
test_
开头 - 测试函数名以
test_
开头 - 测试类名以
Test
开头
- 测试文件名以
-
固件使用:
- 使用
conftest.py
定义共享固件 - 使用
@pytest.fixture
装饰器定义测试固件 - Qt 应用程序使用全局
qapp
固件
- 使用
示例:
import pytest
from PySide6.QtWidgets import QWidget
from modular_qtwidgets import WidgetCreationService
def test_widget_creation(widget_service, qapp):
"""测试组件创建"""
widgets = widget_service.create_widgets_for_location("test_group")
assert len(widgets) > 0
assert isinstance(widgets[0], QWidget)
#启动示例窗口
python example/simple_tools/main.py
主要的组件创建服务类。
service = WidgetCreationService(config_path: str)
-
create_widgets_for_location(location: str, on_widget_created: Callable = None) -> List[QWidget]
- 创建指定位置的所有组件
location
: 组件组名称on_widget_created
: 组件创建回调函数- 返回创建的组件列表
-
create_widget(module_path: str, class_name: str, params: Dict = None, strategy_name: str = None) -> QWidget
- 创建单个组件
module_path
: 组件类文件路径class_name
: 组件类名params
: 初始化参数strategy_name
: 使用的策略名称- 返回创建的组件实例
-
register_strategy(name: str, strategy: WidgetCreationStrategy)
- 注册新的组件创建策略
name
: 策略名称strategy
: 策略实例
组件创建策略的基类。
-
can_handle(widget_class: Type) -> bool
- 检查是否可以处理该组件类
- 返回是否可以处理
-
create_widget(widget_class: Type, params: Dict = None) -> QWidget
- 创建组件实例
- 返回创建的组件
-
配置文件组织
- 按功能模块分组组织组件
- 使用优先级控制组件显示顺序
- 合理使用组件参数配置
-
策略使用
- 为不同类型的组件创建专门的策略
- 策略类保持单一职责
- 适当复用已有策略
- Fork 本仓库
- 创建你的特性分支:
git checkout -b feature/my-new-feature
- 提交你的改动:
git commit -am 'Add some feature'
- 推送到分支:
git push origin feature/my-new-feature
- 提交 Pull Request
在提交 PR 之前,请确保:
- 所有测试都通过
- 新功能有适当的测试覆盖
- 文档已更新
- 代码符合项目的代码风格
MIT License