【Q&A】观察者模式在QT有哪些应用?

1. 信号与槽机制

Qt的**信号与槽(Signals & Slots)**是观察者模式的典型实现,通过元对象系统(Meta-Object System)实现松耦合通信。

  • 核心特点:

    • 类型安全:编译时检查参数匹配
    • 跨线程支持 :通过Qt::QueuedConnection实现线程安全通信
    • 动态连接:运行时可添加/移除槽函数
  • 代码示例:

    cpp 复制代码
    // 发射信号(带参数)
    emit dataFetched("Hello", timestamp); 
    
    // 连接信号与槽
    QObject::connect(button, &QPushButton::clicked, 
                     label, &QLabel::clear); 
  • Mermaid序列图:

DataFetcher DataProcessor mDataLabel QWidget QApplication paintEvent dataFetched(data="Hello", timestamp=123) 发射信号 process_data(const QString&, int) setText("收到数据:%1 (%2秒)".arg(data).arg(timestamp)) 触发重绘请求 update() 显式触发界面刷新 postEvent(QPaintEvent) deliverEvent(QPaintEvent) 执行绘制逻辑 loop \[Qt事件循环] DataFetcher DataProcessor mDataLabel QWidget QApplication paintEvent


2. 事件处理机制

Qt通过事件系统 实现观察者模式,事件对象(QEvent)继承自QObject,通过重写事件处理函数响应特定事件。

  • 关键函数 :

    • mousePressEvent(QMouseEvent*):处理鼠标点击
    • keyPressEvent(QKeyEvent*):处理键盘输入
    • paintEvent(QPaintEvent*):处理界面重绘
  • 代码示例 :

    cpp 复制代码
    // 重写鼠标事件处理
    void MyWidget::mousePressEvent(QMouseEvent *event) {
        if (event->button() == Qt::LeftButton) {
            qDebug() << "左键点击坐标:" << event->pos(); // 
        }
    }
  • Mermaid类图 :
    处理 1 * QEvent +QEvent::Type type +QCoreApplication::postEvent() QMouseEvent +Qt::MouseButton button +QPoint pos QWidget +void mousePressEvent(QMouseEvent*) +void paintEvent(QPaintEvent*)


3. 事件过滤器(Event Filter)

通过installEventFilter实现跨控件事件监听,适用于非父子关系的对象通信。

  • 实现步骤 :

    1. 安装过滤器:widget->installEventFilter(this)
    2. 重写eventFilter(QObject*, QEvent*)
  • 代码示例 :

    cpp 复制代码
    // 安装事件过滤器
    label->installEventFilter(this); // 
    
    // 拦截Resize事件
    bool MyClass::eventFilter(QObject *obj, QEvent *event) {
        if (event->type() == QEvent::Resize) {
            qDebug() << "控件尺寸变化:" << obj->size(); // 
            return true; // 停止事件传播
        }
        return QWidget::eventFilter(obj, event);
    }
  • Mermaid序列图 :
    Widget MyClass installEventFilter() 事件触发时调用eventFilter() 处理事件(如Resize) 返回处理结果 Widget MyClass


4. 全局观察者模式

通过单例类实现跨层级消息传递,避免逐层转发。

  • 实现代码 :

    cpp 复制代码
    // 全局观察者类(单例)
    class GlobalObserver : public QObject {
    public:
        static GlobalObserver& instance() {
            static GlobalObserver observer;
            return observer;
        }
        
        void notify(const QString& msg) {
            QMetaObject::invokeMethod(receiver, "update", Qt::QueuedConnection,
                                    Q_ARG(QString, msg));
        }
        
    private:
        QList<QObject*> m_receivers;
    }; // 
  • 使用示例 :

    cpp 复制代码
    // 注册观察者
    GlobalObserver::instance().connect(this, &MyWidget::update);
    
    // 发送全局消息
    GlobalObserver::instance().notify("数据已更新"); // 
  • Mermaid类图 :
    观察者 1 * GlobalObserver +QList m_receivers +static GlobalObserver& instance() +void notify(const QString&) MyWidget +void update(const QString&)


5. 自定义观察者模式实现

手动实现接口和聚合关系,适用于复杂业务逻辑。

  • 代码示例 :

    cpp 复制代码
    // 抽象主题接口
    class ISubject {
    public:
        virtual void registerObserver(IObserver*) = 0;
        virtual void removeObserver(IObserver*) = 0;
        virtual void notifyObservers() = 0;
    };
    
    // 具体主题
    class WeatherData : public ISubject {
    private:
        QList<IObserver*> m_observers;
        double m_temperature;
    public:
        void registerObserver(IObserver* observer) override {
            m_observers.append(observer);
        }
        void notifyObservers() override {
            for (auto observer : m_observers) {
                observer->update(m_temperature);
            }
        }
    }; // 
  • Mermaid类图 :
    ISubject +registerObserver(IObserver*) +removeObserver(IObserver*) +notifyObservers() IObserver +void update(double) WeatherData +QList m_observers +double m_temperature +registerObserver(IObserver*) +notifyObservers() WeatherDisplay


总结

Qt通过信号与槽 、事件系统 和事件过滤器 原生支持观察者模式,适用于UI交互、多线程通信等场景。对于复杂业务逻辑,可手动实现接口和聚合关系,或通过全局单例类实现跨层级通信。这些机制共同体现了Qt在解耦对象交互、提升扩展性方面的设计优势。

相关推荐
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
伞伞悦读2 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
C语言小火车2 天前
C/C++ 为什么需要编译器?
开发语言·c++
霍霍的袁3 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
孙启超3 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust
此生决int3 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++
慧都小项3 天前
当边缘AI上产线:QtitanDocking 如何让工业 HMI 实现多视图协同
人工智能·qt·ui·边缘计算·qt6.3
CoderYanger3 天前
A.每日一题:835. 图像重叠
java·开发语言·程序人生·leetcode·面试·职场和发展·学习方法
伞伞悦读3 天前
【第37期】Python JSON 与配置详解:序列化、反序列化、嵌套结构和配置文件
开发语言·python·json
CCCCCCCCharlie3 天前
Linux进程控制四大核心操作
linux·开发语言