Skip to content

COMPONENTS

Zuko edited this page Jan 29, 2026 · 1 revision

Component Architecture Guide

Overview

Tất cả UI components trong App nên tuân theo pattern nhất quán với:

  • File .ui cho giao diện (Qt Designer)
  • File Widget.py cho logic UI và Controller
  • File Handler.py cho xử lý events (Observer pattern)

Benefits

1. Separation of Concerns

  • UI logic (Widget) tách biệt với business logic (Handler)
  • Dễ maintain và test từng layer riêng biệt

2. Consistent Pattern

  • Tất cả components tuân theo cùng một pattern
  • Developer dễ hiểu và implement

3. Observer Pattern

  • Loose coupling giữa UI và logic
  • Dễ extend và modify behavior

4. Qt Designer Integration

  • UI được thiết kế bằng visual tool
  • Tự động compile và sync

5. Reusability

  • Components có thể tái sử dụng ở nhiều nơi
  • Parameterizable và configurable

Quick Start

1. Tạo Component Mới

# Tạo thư mục component
mkdir windows/components/MyComponent

# Tạo các files cần thiết:
# - MyComponent.ui (Qt Designer)
# - MyComponent.py (compiled UI)
# - MyComponentWidget.py (Widget + Controller)
# - MyComponentHandler.py (Event Handler)
# - __init__.py (Module exports)

2. Thiết Kế UI (.ui file)

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <author>Zuko</author>
 <class>MyComponent</class>
 <widget class="QWidget" name="MyComponent">
  <!-- UI elements here -->
 </widget>
</ui>

3. Compile UI to Python

# Manual compile (nếu có pyside6-uic)
pyside6-uic MyComponent.ui -o MyComponent.py

# Hoặc dùng script
python scripts/compile_ui.py

4. Implement Widget

from core import BaseController
from .MyComponent import Ui_MyComponent

# QUAN TRỌNG: thứ tự kế thừa BaseController luôn đứng sau Ui, đứng trước Window hoặc Widget của QT
class MyComponentWidget(Ui_MyComponent, BaseController, QWidget):
    # Observer pattern mapping
    slot_map = {
        'buttonClicked': ['myButton', 'clicked'],
    }
    
    # External signals
    dataChanged = Signal(dict)
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        # Setup logic here

5. Implement Handler

from core.Observer import Subscriber

class MyComponentHandler(Subscriber):
    def __init__(self, widget, events):
        super().__init__(events)
        self.widget = widget
    
    def onButtonClicked(self, data=None):
        # Handle event here
        pass

6. Sử Dụng Component

from windows.components.MyComponent import MyComponentWidget

class ParentController(BaseController):
    slot_map = {
        'data_changed': ['my_comp', 'dataChanged'],
    }
    def setup_components(self):
        # Tạo widget
        self.my_comp = MyComponentWidget(parent=self)
        self.layout.addWidget(self.my_comp)

Best Practices

1. UI Design

  • Sử dụng meaningful object names
  • Set tooltips và status tips
  • Configure sane defaults
  • ComponentName.ui - UI definition
  • ComponentName.py - Generated UI code (DON'T EDIT)
  • ComponentNameWidget.py - Widget implementation
  • ComponentNameHandler.py - Event handler
  • __init__.py - Module exports

2. Widget Implementation

  • Kế thừa: Ui_ComponentName, BaseController, QWidget. Đúng thứ tự
  • Định nghĩa slot_map đầy đủ

3. Handler Implementation

  • Kế thừa từ Subscriber
  • Prefix methods với on
  • Handle exceptions properly
  • Log important events
  • Keep methods focused

Testing Components

Unit Testing

def test_component_widget():
    widget = MyComponentWidget()
    assert widget.some_property == expected_value

def test_component_handler():
    widget = MyComponentWidget()
    handler = MyComponentHandler(widget, widget.events)
    handler.on_some_event()
    # Assert expected behavior

Integration Testing

def test_component_integration():
    parent = ParentController()
    parent.setup_components()
    # Test component interaction

Clone this wiki locally