Qt MVC架构下,如何实现控制器间的解耦调用?
在Qt的MVC架构下,要实现两个独立控制器的解耦交互,核心思路是避免控制器间直接引用或信号连接,而是通过中间层(模型、事件总线或Qt原生事件)传递状态或事件。以下是几种可行的方案:
方案1:基于模型层的状态同步(最贴合MVC设计)
MVC的核心是模型作为状态中枢,所有控制器围绕模型交互,完全符合解耦要求:
- 定义共享模型,包含控制矩形显示状态的属性及对应信号
- 窗口控制器修改模型状态,场景控制器监听模型状态变化并更新视图
// 共享模型类 class AppModel : public QObject { Q_OBJECT Q_PROPERTY(bool isRectangleVisible READ isRectangleVisible WRITE setIsRectangleVisible NOTIFY rectangleVisibilityChanged) public: bool isRectangleVisible() const { return m_visible; } void setIsRectangleVisible(bool visible) { if (m_visible != visible) { m_visible = visible; emit rectangleVisibilityChanged(visible); } } signals: void rectangleVisibilityChanged(bool visible); private: bool m_visible = true; }; // 窗口控制器(按钮所在) class WindowController : public QObject { Q_OBJECT public: WindowController(AppModel* model, QPushButton* button) : m_model(model) { connect(button, &QPushButton::clicked, this, [this](){ m_model->setIsRectangleVisible(false); // 点击按钮设置隐藏状态 }); } private: AppModel* m_model; }; // 场景控制器 class SceneController : public QObject { Q_OBJECT public: SceneController(AppModel* model, QGraphicsRectItem* rect) : m_model(model), m_rect(rect) { connect(m_model, &AppModel::rectangleVisibilityChanged, this, [this](bool visible){ m_rect->setVisible(visible); // 根据模型状态更新矩形显示 }); } private: AppModel* m_model; QGraphicsRectItem* m_rect; };
这种方式下,两个控制器仅依赖模型,彼此完全解耦,严格遵循MVC职责划分。
方案2:全局事件总线(通用解耦方案)
如果不想修改模型层,可以实现一个全局事件总线作为事件中转中心:
- 单例EventBus提供发布/订阅接口
- 窗口控制器发布隐藏事件,场景控制器订阅并响应
// 事件总线单例类 class EventBus : public QObject { Q_OBJECT public: static EventBus* instance() { static EventBus bus; return &bus; } // 发布事件 void publish(const QString& eventName, QVariant data = QVariant()) { emit eventPublished(eventName, data); } // 订阅事件 QMetaObject::Connection subscribe(const QString& eventName, const std::function<void(QVariant)>& callback) { return connect(this, &EventBus::eventPublished, this, [eventName, callback](const QString& name, QVariant data){ if (name == eventName) { callback(data); } }); } signals: void eventPublished(const QString& eventName, QVariant data); private: EventBus() = default; }; // 窗口控制器 class WindowController : public QObject { Q_OBJECT public: WindowController(QPushButton* button) { connect(button, &QPushButton::clicked, this, [](){ EventBus::instance()->publish("HideRectangle"); }); } }; // 场景控制器 class SceneController : public QObject { Q_OBJECT public: SceneController(QGraphicsRectItem* rect) : m_rect(rect) { EventBus::instance()->subscribe("HideRectangle", [this](QVariant){ m_rect->setVisible(false); }); } private: QGraphicsRectItem* m_rect; };
这种方式下,两个控制器无直接依赖,仅与事件总线交互,解耦程度极高。
方案3:Qt自定义事件(原生API方案)
利用Qt原生事件机制发送自定义事件:
- 定义自定义事件类
- 窗口控制器发送事件,场景控制器重写
event方法处理
// 自定义事件类 class HideRectangleEvent : public QEvent { public: static const QEvent::Type EventType; HideRectangleEvent() : QEvent(EventType) {} }; const QEvent::Type HideRectangleEvent::EventType = static_cast<QEvent::Type>(QEvent::User + 100); // 窗口控制器 class WindowController : public QObject { Q_OBJECT public: WindowController(QPushButton* button, QObject* sceneController) : m_sceneController(sceneController) { connect(button, &QPushButton::clicked, this, [this]{ QCoreApplication::postEvent(m_sceneController, new HideRectangleEvent()); }); } private: QObject* m_sceneController; }; // 场景控制器 class SceneController : public QObject { Q_OBJECT public: SceneController(QGraphicsRectItem* rect) : m_rect(rect) {} protected: bool event(QEvent* event) override { if (event->type() == HideRectangleEvent::EventType) { m_rect->setVisible(false); event->accept(); return true; } return QObject::event(event); } private: QGraphicsRectItem* m_rect; };
这种方式利用Qt原生API,无需额外中间类,仅需传递场景控制器指针(可通过依赖注入或全局获取),解耦程度略低于前两种,但依然避免了直接信号连接。
内容的提问来源于stack exchange,提问作者Ascii67
相关产品推荐
相关产品推荐

