首页 > 解决方案 > 基于 Qt 的首选项面板应该如何广播首选项已更改?

问题描述

我正在尝试为我的多文档应用程序设计一个首选项面板。当给定的首选项更改时(例如字体大小),所有文档窗口都应立即更新以反映新的首选项值。我不想为所有要连接的文档窗口预先构建首选项面板,因为它包含一个QFontComboBox需要一秒钟以上的时间来设置自身(哎哟);这不是我想在启动时支付的价格。那么,我的问题是:让所有文档窗口都知道更改的首选项面板的优雅设计是什么?在我更习惯的 Cocoa 中,我会使用NSNotification从 prefs 面板广播所有文档窗口都可以观察到的通知;这提供了所需的松散耦合(因为对象可以在广播者存在之前将自己添加为观察者)。

到目前为止,我想到了两种方法:

  1. 循环topLevelWidgets,对我的文档窗口类进行动态转换,对于我找到的所有文档窗口,只需直接在它们上调用硬编码方法。

  2. 创建第二个类,PreferencesNotifier它与需要很长时间才能加载的 UI 对象分开,并在启动时构造此类的单例对象,所有文档窗口都可以连接到它们自己。当首选项面板最终创建时,它可以向 中的插槽发送信号PreferencesNotifier,然后它会调用自己的信号来通知连接的文档窗口。

两者似乎都不像 一样优雅NSNotification,我想知道我是否遗漏了什么。感谢您的任何提示。

标签: qt

解决方案


首先,不要尝试将模式(例如 Cocoa 的NSNotification/ NotificationCenter)复制到其他框架(或语言,或...)。发送消息的方式有很多种,通常每个框架都选择了一种。尝试使用您正在使用的框架选择的一种方法将导致最优雅的解决方案。

如果你真的想要,你可以实现你自己的一组类,它们会做的正是NSNotification。你会觉得它更优雅,但这只是因为你习惯了使用 Cocoa。所有其他 Qt 开发人员都会觉得很奇怪。此外,此解决方案将需要您编写大量代码,因为您将无法利用 Qt 的所有功能。

您建议的第一个解决方案有点难看,看起来更像是黑客。

当我必须在程序中处理首选项时,我所做的类似于您的解决方案 2。我创建了一个负责处理所有设置的类:读/写设置文件、更改设置、设置默认值等。通常这个类是一个单例。此类对程序其他部分的访问权限非常有限,通常根本无法访问 UI。每个需要访问首选项的组件都将使用这个类。如果你做得正确(例如 use Q_PROPERTY),如果你需要使用 Qt Quick,这个类甚至可以被 QML 访问。

class Settings: public QObject {
    Q_OBJECT
    Q_PROERTY(bool showX READ showX WRITE setShowX NOTIFY showXChanged)
public:
    bool showX() const { return m_showX; }
    void setShowX(bool show) {
        if (show == m_showX)
            return;

        m_showX = show;
        emit showXChanged(m_showX);
    }

signals:
    void showXChanged(bool);

public slots:
    void save() const; // Save to disk
    void load(); // Load from disk

private:
    QSettings m_settings; // Handle load/save from/to disk
    bool m_showX;
};

class Window {

    Window() {
        ...
        m_widgetX->setVisible(settings->showX());
        connect(settings, &Settings::showXChanged,
                this, [this](bool show) { m_widgetX->setVisible(show); }
                );
        ...
    }
};

class PrefWindow {

    PrefWindow () {
        ...
        ui->checkBoxShowX->setChecked(settings->showX());
        ...
    }

private slots:
    void on_saveButton_clicked() {
        settings->setShowX(ui->checkBoxShowX->checked()):
        settings->save();
    }
};

推荐阅读