mvvm-framework 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mvvm_framework-0.1.0/PKG-INFO +220 -0
- mvvm_framework-0.1.0/README.md +210 -0
- mvvm_framework-0.1.0/pyproject.toml +16 -0
- mvvm_framework-0.1.0/src/mvvm_framework/__init__.py +21 -0
- mvvm_framework-0.1.0/src/mvvm_framework/core/__init__.py +18 -0
- mvvm_framework-0.1.0/src/mvvm_framework/core/binding.py +362 -0
- mvvm_framework-0.1.0/src/mvvm_framework/core/command.py +311 -0
- mvvm_framework-0.1.0/src/mvvm_framework/core/model.py +212 -0
- mvvm_framework-0.1.0/src/mvvm_framework/core/observable.py +358 -0
- mvvm_framework-0.1.0/src/mvvm_framework/core/viewmodel.py +217 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: mvvm-framework
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A general-purpose MVVM framework based on PySide6 property system
|
|
5
|
+
Author: henxun
|
|
6
|
+
Author-email: henxun <1371490145@qq.com>
|
|
7
|
+
Requires-Dist: pyside6>=6.0.0
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# MVVM Framework for PySide6
|
|
12
|
+
|
|
13
|
+
一个基于 PySide6 属性系统实现的通用 QtWidgets MVVM 框架。
|
|
14
|
+
|
|
15
|
+
## 项目结构
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
mvvm_framework/
|
|
19
|
+
├── __init__.py # 包入口,导出核心组件
|
|
20
|
+
├── core/ # 核心模块
|
|
21
|
+
│ ├── __init__.py
|
|
22
|
+
│ ├── observable.py # 可观察对象和列表
|
|
23
|
+
│ ├── model.py # 模型基类
|
|
24
|
+
│ ├── viewmodel.py # 视图模型基类
|
|
25
|
+
│ ├── command.py # 命令模式实现
|
|
26
|
+
│ └── binding.py # 数据绑定工具
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 核心组件
|
|
30
|
+
|
|
31
|
+
### 1. ObservableObject(可观察对象)
|
|
32
|
+
|
|
33
|
+
所有 MVVM 组件的基类,提供属性变更通知机制。
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from mvvm_framework import ObservableObject
|
|
37
|
+
|
|
38
|
+
class MyObject(ObservableObject):
|
|
39
|
+
def __init__(self):
|
|
40
|
+
super().__init__()
|
|
41
|
+
self._value = 0
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def value(self) -> int:
|
|
45
|
+
return self._value
|
|
46
|
+
|
|
47
|
+
@value.setter
|
|
48
|
+
def value(self, val: int):
|
|
49
|
+
if self._value != val:
|
|
50
|
+
self._value = val
|
|
51
|
+
self.notify_property_changed("value")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Model(模型)
|
|
55
|
+
|
|
56
|
+
数据模型层,包含业务逻辑和数据验证。
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from mvvm_framework import Model
|
|
60
|
+
|
|
61
|
+
class Person(Model):
|
|
62
|
+
def __init__(self, name: str = "", age: int = 0):
|
|
63
|
+
super().__init__()
|
|
64
|
+
self._name = name
|
|
65
|
+
self._age = age
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def name(self) -> str:
|
|
69
|
+
return self._name
|
|
70
|
+
|
|
71
|
+
@name.setter
|
|
72
|
+
def name(self, value: str):
|
|
73
|
+
if self._name != value:
|
|
74
|
+
self._name = value
|
|
75
|
+
self.notify_property_changed("name")
|
|
76
|
+
|
|
77
|
+
def validate_name(self, value: str) -> str | None:
|
|
78
|
+
if not value.strip():
|
|
79
|
+
return "Name cannot be empty"
|
|
80
|
+
return None
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 3. ViewModel(视图模型)
|
|
84
|
+
|
|
85
|
+
连接 Model 和 View 的桥梁,暴露数据和命令给视图。
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from mvvm_framework import ViewModel, Command
|
|
89
|
+
|
|
90
|
+
class PersonViewModel(ViewModel[Person]):
|
|
91
|
+
def __init__(self, model: Person):
|
|
92
|
+
super().__init__(model)
|
|
93
|
+
self._save_command = Command(self.save, self.can_save)
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def name(self) -> str:
|
|
97
|
+
return self.model.name
|
|
98
|
+
|
|
99
|
+
@name.setter
|
|
100
|
+
def name(self, value: str):
|
|
101
|
+
if self.model.name != value:
|
|
102
|
+
self.model.name = value
|
|
103
|
+
self.notify_property_changed("name")
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def save_command(self) -> Command:
|
|
107
|
+
return self._save_command
|
|
108
|
+
|
|
109
|
+
def can_save(self) -> bool:
|
|
110
|
+
return self.model.name != ""
|
|
111
|
+
|
|
112
|
+
def save(self):
|
|
113
|
+
print(f"Saving {self.model.name}")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 4. Command(命令)
|
|
117
|
+
|
|
118
|
+
实现命令模式,用于处理用户操作。
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from mvvm_framework import Command
|
|
122
|
+
|
|
123
|
+
# 基本命令
|
|
124
|
+
save_cmd = Command(
|
|
125
|
+
execute=lambda: print("Saved!"),
|
|
126
|
+
can_execute=lambda: True
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# 带参数的命令
|
|
130
|
+
from mvvm_framework.core.command import ParameterizedCommand
|
|
131
|
+
delete_cmd = ParameterizedCommand(
|
|
132
|
+
execute=lambda item: print(f"Deleting {item}"),
|
|
133
|
+
can_execute=lambda item: item is not None
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 5. ObservableList(可观察列表)
|
|
138
|
+
|
|
139
|
+
支持变更通知的列表类型。
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from mvvm_framework import ObservableList
|
|
143
|
+
|
|
144
|
+
numbers = ObservableList([1, 2, 3])
|
|
145
|
+
numbers.itemAdded.connect(lambda idx, val: print(f"Added {val} at {idx}"))
|
|
146
|
+
numbers.append(4) # 触发 itemAdded 信号
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 6. Binding(数据绑定)
|
|
150
|
+
|
|
151
|
+
简化 View 和 ViewModel 之间的绑定。
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from mvvm_framework import Binding
|
|
155
|
+
|
|
156
|
+
# 双向文本绑定
|
|
157
|
+
Binding.bind_text(viewmodel, "name", line_edit)
|
|
158
|
+
|
|
159
|
+
# 单向标签绑定
|
|
160
|
+
Binding.bind_label(viewmodel, "display_name", label)
|
|
161
|
+
|
|
162
|
+
# 命令绑定
|
|
163
|
+
Binding.bind_command(viewmodel, "save_command", button)
|
|
164
|
+
|
|
165
|
+
# 值绑定(SpinBox/Slider)
|
|
166
|
+
Binding.bind_value(viewmodel, "age", spinbox)
|
|
167
|
+
|
|
168
|
+
# 选中状态绑定
|
|
169
|
+
Binding.bind_checked(viewmodel, "is_active", checkbox)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## 完整示例
|
|
173
|
+
|
|
174
|
+
运行示例应用:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
python -m mvvm_framework.examples.person_view
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
或者在代码中使用:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
import sys
|
|
184
|
+
from PySide6.QtWidgets import QApplication
|
|
185
|
+
from mvvm_framework.examples import Person, PersonViewModel, PersonView
|
|
186
|
+
|
|
187
|
+
app = QApplication(sys.argv)
|
|
188
|
+
|
|
189
|
+
# 创建 Model
|
|
190
|
+
person = Person(name="John", age=30, email="john@example.com")
|
|
191
|
+
|
|
192
|
+
# 创建 ViewModel
|
|
193
|
+
viewmodel = PersonViewModel(person)
|
|
194
|
+
|
|
195
|
+
# 创建 View
|
|
196
|
+
view = PersonView(viewmodel)
|
|
197
|
+
view.show()
|
|
198
|
+
|
|
199
|
+
sys.exit(app.exec())
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 特性
|
|
203
|
+
|
|
204
|
+
- **属性变更通知**: 自动通知 UI 更新
|
|
205
|
+
- **双向数据绑定**: View 和 ViewModel 自动同步
|
|
206
|
+
- **命令模式**: 统一的动作处理方式
|
|
207
|
+
- **数据验证**: 内置验证系统
|
|
208
|
+
- **计算属性缓存**: 优化性能
|
|
209
|
+
- **集合变更通知**: ObservableList 支持
|
|
210
|
+
- **类型提示**: 完整的类型注解支持
|
|
211
|
+
|
|
212
|
+
## 安装依赖
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
pip install PySide6
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## 许可证
|
|
219
|
+
|
|
220
|
+
MIT License
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# MVVM Framework for PySide6
|
|
2
|
+
|
|
3
|
+
一个基于 PySide6 属性系统实现的通用 QtWidgets MVVM 框架。
|
|
4
|
+
|
|
5
|
+
## 项目结构
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
mvvm_framework/
|
|
9
|
+
├── __init__.py # 包入口,导出核心组件
|
|
10
|
+
├── core/ # 核心模块
|
|
11
|
+
│ ├── __init__.py
|
|
12
|
+
│ ├── observable.py # 可观察对象和列表
|
|
13
|
+
│ ├── model.py # 模型基类
|
|
14
|
+
│ ├── viewmodel.py # 视图模型基类
|
|
15
|
+
│ ├── command.py # 命令模式实现
|
|
16
|
+
│ └── binding.py # 数据绑定工具
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 核心组件
|
|
20
|
+
|
|
21
|
+
### 1. ObservableObject(可观察对象)
|
|
22
|
+
|
|
23
|
+
所有 MVVM 组件的基类,提供属性变更通知机制。
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from mvvm_framework import ObservableObject
|
|
27
|
+
|
|
28
|
+
class MyObject(ObservableObject):
|
|
29
|
+
def __init__(self):
|
|
30
|
+
super().__init__()
|
|
31
|
+
self._value = 0
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def value(self) -> int:
|
|
35
|
+
return self._value
|
|
36
|
+
|
|
37
|
+
@value.setter
|
|
38
|
+
def value(self, val: int):
|
|
39
|
+
if self._value != val:
|
|
40
|
+
self._value = val
|
|
41
|
+
self.notify_property_changed("value")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Model(模型)
|
|
45
|
+
|
|
46
|
+
数据模型层,包含业务逻辑和数据验证。
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from mvvm_framework import Model
|
|
50
|
+
|
|
51
|
+
class Person(Model):
|
|
52
|
+
def __init__(self, name: str = "", age: int = 0):
|
|
53
|
+
super().__init__()
|
|
54
|
+
self._name = name
|
|
55
|
+
self._age = age
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def name(self) -> str:
|
|
59
|
+
return self._name
|
|
60
|
+
|
|
61
|
+
@name.setter
|
|
62
|
+
def name(self, value: str):
|
|
63
|
+
if self._name != value:
|
|
64
|
+
self._name = value
|
|
65
|
+
self.notify_property_changed("name")
|
|
66
|
+
|
|
67
|
+
def validate_name(self, value: str) -> str | None:
|
|
68
|
+
if not value.strip():
|
|
69
|
+
return "Name cannot be empty"
|
|
70
|
+
return None
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 3. ViewModel(视图模型)
|
|
74
|
+
|
|
75
|
+
连接 Model 和 View 的桥梁,暴露数据和命令给视图。
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
from mvvm_framework import ViewModel, Command
|
|
79
|
+
|
|
80
|
+
class PersonViewModel(ViewModel[Person]):
|
|
81
|
+
def __init__(self, model: Person):
|
|
82
|
+
super().__init__(model)
|
|
83
|
+
self._save_command = Command(self.save, self.can_save)
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def name(self) -> str:
|
|
87
|
+
return self.model.name
|
|
88
|
+
|
|
89
|
+
@name.setter
|
|
90
|
+
def name(self, value: str):
|
|
91
|
+
if self.model.name != value:
|
|
92
|
+
self.model.name = value
|
|
93
|
+
self.notify_property_changed("name")
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def save_command(self) -> Command:
|
|
97
|
+
return self._save_command
|
|
98
|
+
|
|
99
|
+
def can_save(self) -> bool:
|
|
100
|
+
return self.model.name != ""
|
|
101
|
+
|
|
102
|
+
def save(self):
|
|
103
|
+
print(f"Saving {self.model.name}")
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 4. Command(命令)
|
|
107
|
+
|
|
108
|
+
实现命令模式,用于处理用户操作。
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from mvvm_framework import Command
|
|
112
|
+
|
|
113
|
+
# 基本命令
|
|
114
|
+
save_cmd = Command(
|
|
115
|
+
execute=lambda: print("Saved!"),
|
|
116
|
+
can_execute=lambda: True
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# 带参数的命令
|
|
120
|
+
from mvvm_framework.core.command import ParameterizedCommand
|
|
121
|
+
delete_cmd = ParameterizedCommand(
|
|
122
|
+
execute=lambda item: print(f"Deleting {item}"),
|
|
123
|
+
can_execute=lambda item: item is not None
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 5. ObservableList(可观察列表)
|
|
128
|
+
|
|
129
|
+
支持变更通知的列表类型。
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from mvvm_framework import ObservableList
|
|
133
|
+
|
|
134
|
+
numbers = ObservableList([1, 2, 3])
|
|
135
|
+
numbers.itemAdded.connect(lambda idx, val: print(f"Added {val} at {idx}"))
|
|
136
|
+
numbers.append(4) # 触发 itemAdded 信号
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 6. Binding(数据绑定)
|
|
140
|
+
|
|
141
|
+
简化 View 和 ViewModel 之间的绑定。
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from mvvm_framework import Binding
|
|
145
|
+
|
|
146
|
+
# 双向文本绑定
|
|
147
|
+
Binding.bind_text(viewmodel, "name", line_edit)
|
|
148
|
+
|
|
149
|
+
# 单向标签绑定
|
|
150
|
+
Binding.bind_label(viewmodel, "display_name", label)
|
|
151
|
+
|
|
152
|
+
# 命令绑定
|
|
153
|
+
Binding.bind_command(viewmodel, "save_command", button)
|
|
154
|
+
|
|
155
|
+
# 值绑定(SpinBox/Slider)
|
|
156
|
+
Binding.bind_value(viewmodel, "age", spinbox)
|
|
157
|
+
|
|
158
|
+
# 选中状态绑定
|
|
159
|
+
Binding.bind_checked(viewmodel, "is_active", checkbox)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## 完整示例
|
|
163
|
+
|
|
164
|
+
运行示例应用:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
python -m mvvm_framework.examples.person_view
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
或者在代码中使用:
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
import sys
|
|
174
|
+
from PySide6.QtWidgets import QApplication
|
|
175
|
+
from mvvm_framework.examples import Person, PersonViewModel, PersonView
|
|
176
|
+
|
|
177
|
+
app = QApplication(sys.argv)
|
|
178
|
+
|
|
179
|
+
# 创建 Model
|
|
180
|
+
person = Person(name="John", age=30, email="john@example.com")
|
|
181
|
+
|
|
182
|
+
# 创建 ViewModel
|
|
183
|
+
viewmodel = PersonViewModel(person)
|
|
184
|
+
|
|
185
|
+
# 创建 View
|
|
186
|
+
view = PersonView(viewmodel)
|
|
187
|
+
view.show()
|
|
188
|
+
|
|
189
|
+
sys.exit(app.exec())
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## 特性
|
|
193
|
+
|
|
194
|
+
- **属性变更通知**: 自动通知 UI 更新
|
|
195
|
+
- **双向数据绑定**: View 和 ViewModel 自动同步
|
|
196
|
+
- **命令模式**: 统一的动作处理方式
|
|
197
|
+
- **数据验证**: 内置验证系统
|
|
198
|
+
- **计算属性缓存**: 优化性能
|
|
199
|
+
- **集合变更通知**: ObservableList 支持
|
|
200
|
+
- **类型提示**: 完整的类型注解支持
|
|
201
|
+
|
|
202
|
+
## 安装依赖
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
pip install PySide6
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 许可证
|
|
209
|
+
|
|
210
|
+
MIT License
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "mvvm-framework"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A general-purpose MVVM framework based on PySide6 property system"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "henxun", email = "1371490145@qq.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"pyside6>=6.0.0",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[build-system]
|
|
15
|
+
requires = ["uv_build>=0.11.12,<0.12.0"]
|
|
16
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MVVM Framework for PySide6
|
|
3
|
+
A general-purpose MVVM framework based on PySide6 property system
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .core.observable import ObservableObject, ObservableList
|
|
7
|
+
from .core.model import Model
|
|
8
|
+
from .core.viewmodel import ViewModel
|
|
9
|
+
from .core.command import Command
|
|
10
|
+
from .core.binding import Binding
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'ObservableObject',
|
|
14
|
+
'ObservableList',
|
|
15
|
+
'Model',
|
|
16
|
+
'ViewModel',
|
|
17
|
+
'Command',
|
|
18
|
+
'Binding',
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
__version__ = '1.0.0'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Core module for MVVM framework
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .observable import ObservableObject, ObservableList
|
|
6
|
+
from .model import Model
|
|
7
|
+
from .viewmodel import ViewModel
|
|
8
|
+
from .command import Command
|
|
9
|
+
from .binding import Binding
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
'ObservableObject',
|
|
13
|
+
'ObservableList',
|
|
14
|
+
'Model',
|
|
15
|
+
'ViewModel',
|
|
16
|
+
'Command',
|
|
17
|
+
'Binding',
|
|
18
|
+
]
|