3

在我的桌面应用程序中,我使用 QSettings 来保存各种应用程序值。例如,主窗体位置、最近的文档、连接参数和一些改变应用程序行为方式的东西,例如信息对话框上的“不再显示此消息”。

我通常的处理方法是在应用程序启动时将所有设置读入结构或对象,并在应用程序关闭时保存它们。

我还有一个对话框,使我能够编辑设置对象中的许多值,并在对话框关闭时保存它们。

许多窗口甚至可能是非可视对象都需要设置对象中的值。

做这个的最好方式是什么?

我首先将设置对象作为主窗口的成员,但随后我遇到了其他窗口需要访问主窗口成员的问题。

我确实认为我可以在它自己的 cpp 文件中创建设置对象,并在需要的地方使用#include。但我不确定这是否可能或它的语法。

这种情况的最佳做法是什么?

4

3 回答 3

7

我建议始终使用QSettings,避免使用补充结构或类。您可以在main.js中设置应用程序名称组织名称和组织域。

来自 QtDocs:

如果您在应用程序的许多地方使用 QSettings,您可能希望使用 QCoreApplication::setOrganizationName() 和 QCoreApplication::setApplicationName() 指定组织名称和应用程序名称,然后使用默认的 QSettings 构造函数:

QCoreApplication::setOrganizationName("MySoft");
QCoreApplication::setOrganizationDomain("mysoft.com");
QCoreApplication::setApplicationName("Star Runner");

然后在需要访问属性的地方使用默认构造函数:

QSettings settings;

QSettings 对象可以在堆栈或堆上创建(即使用new)。构造和销毁 QSettings 对象非常快。

您可以在程序中的任何位置进行设置:

如果已经存在具有相同键的设置,则现有值将被新值覆盖。为了提高效率,更改可能不会立即保存到永久存储中。(您可以随时调用 sync() 来提交您的更改。)

您也可以在不同的线程中使用它而不会出现问题:

QSettings 是可重入的。这意味着您可以同时在不同的线程中使用不同的 QSettings 对象。即使 QSettings 对象引用磁盘上的相同文件(或系统注册表中的相同条目),此保证仍然有效。如果通过一个 QSettings 对象修改设置,则更改将立即在任何其他在同一位置运行且存在于同一进程中的 QSettings 对象中可见。

可以从不同的进程(可以是同时运行的应用程序的不同实例或完全不同的应用程序)安全地使用 QSettings 来读取和写入相同的系统位置。它使用咨询文件锁定和智能合并算法来确保数据完整性。请注意,sync() 会导入其他进程所做的更改(除了写入此 QSettings 中的更改)。

于 2015-07-10T11:15:55.243 回答
6

QSettings 不是线程安全的。文档清楚地说明了这一点:

QSettings 是可重入的。这意味着您可以同时在不同的线程中使用不同的 QSettings 对象。即使 QSettings 对象引用磁盘上的相同文件(或系统注册表中的相同条目),此保证仍然有效。

它是可重入的,但不是线程安全的。您不能安全地使用来自多个线程的全局 QSettings 对象。如果一个线程调用 beginGroup() 然后第二个线程也调用 beginGroup() 那么你有一个问题,因为你的 QSettings 对象有错误的前缀。

对同一个文件使用多个 QSettings 对象是线程安全的。因此,您应该在堆栈上本地创建 QSettings 对象,而不是全局共享单个对象以避免竞争条件。

于 2015-12-11T08:23:52.247 回答
1

我看不到问题所在。

有两个基本选项:

  1. 一次创建一个对象并将其传递给所有窗口:为简单起见,我们假设您的设置对象是 Qsettings 类型。另外让我们假设您的应用程序不是多线程的。您在主函数中创建此对象,并将其作为参数传递给您创建的每个窗口。所有窗口都会#include <QSettings>并且知道如何访问它。如果您有自己的设置类,也是如此。该接口在它自己的头文件中,在它自己的 cpp 中实现。您创建一个并将其传递给所有窗口。
  2. 如评论中所述,您也可以使用单例。只需为设置类创建一个静态函数,该函数返回在函数内部声明为静态的相同实例。像这样:

class Settings
{
public:
    static Settings & TheSettings()
    {
        static Settings theSettings_;
        return theSettings_;
    }
    // Here go all methods for accessing the data
    // You will also want:
    ~Settings();
    Settings(const Settings &);
    Settings & operator=(const Settings &);
    // If you are using c++11 you may also want to add move constructor and assignment. 
    // Or you can just use the defaults for all the above if all your private members can destruct themselves  
private:
    Settings();
};

这是上面的 QSettings 作为设置对象:


class Settings
{
public:
    static QSettings & TheSettings()
    {
        static QSettings theSettings_;
        return theSettings_;
    }

private:
    Settings();
    Settings(const Settings &);
    Settings & operator=(const Settigns &);
};

希望这能让你走上正确的轨道

PS。对于多线程应用程序,请确保在关键部分(或互斥保护)内访问 Settings 对象内的所有内部数据

聚苯乙烯。请注意,正如 Miki 在评论中提到的那样,QSettings 是线程安全的,因此您不必在关键部分中包装对它的访问。但是,如果您曾经使用不同的底层存储(无论是文件还是另一个容器),这可能是必要的。

于 2015-07-10T11:19:06.317 回答