【问题标题】:Cannot get QSettings to read from custom storage format无法让 QSettings 从自定义存储格式中读取
【发布时间】:2017-05-20 15:06:49
【问题描述】:

我正在尝试为 QSettings 创建自定义格式,但无法从存储中读取它。

在下面的代码中,如果我运行settings.setValue("test", 123"),它会正确调用写入函数并打印Calling writeSqlite。但是,如果我尝试settings.value("test"),它不会调用读取函数并且不会打印Calling readSqlite

知道可能是什么问题吗?

bool readSqlite(QIODevice &device, QSettings::SettingsMap &map) {
    qDebug() << "Calling readSqlite";
    return true;
}

bool writeSqlite(QIODevice &device, const QSettings::SettingsMap &map) {
    qDebug() << "Calling writeSqlite";
    return true;
}

void Settings::initialize() {
    const QSettings::Format SqliteFormat = QSettings::registerFormat("sqlite", &readSqlite, &writeSqlite);
    QSettings::setDefaultFormat(SqliteFormat);

    QSettings settings;
    // This doesn't work:
    // qDebug() << settings.value("test");

    // This works:
    // settings.setValue("test", 123456);
}

【问题讨论】:

  • 您已配置 QApplication。 {您的应用程序}.setApplicationName(""), setOrganizationName('')
  • @eyllanesc,在我的应用程序的开头,我添加了QCoreApplication::setOrganizationName(...) 等,实际上QSettings 使用默认存储,所以我认为组织、应用程序名称等已设置正确。

标签: qt sqlite qt5 storage qsettings


【解决方案1】:

QSettings 不会调用自定义读取函数(在您的情况下为 readSqlite),除非设置文件 可读 并且 具有非零大小(显然, 不满足这些条件就不需要调用了)。见source code here

由于您的自定义写入函数并未真正向device 写入任何内容,因此您的设置文件为空,并且不会调用readSqlite

如果你想看到你的readSqlite 函数被调用,你可以在你的设置文件中添加一些任意数据,或者在你的writeSqlite 实现中添加一些device.write() 调用,你的readSqlite 函数将得到在下一次运行中调用。

【讨论】:

  • 谢谢,确实是这个原因。但是我想知道是否有可能让它与数据库或 Windows 注册表之类的虚拟存储(不与特定文件关联)一起使用?
  • 我认为这值得单独提出一个问题。无论如何,乍一看,我可以说你可能需要一个自定义的QIODevice,它可以正确封装你的存储介质(无论是数据库还是windows注册表),这样write()ing到那个QIODevice就会将记录/键插入数据库/注册表,read()ing 将检索这些记录/键。
  • @Mike 这正是这里所需要的。需要一个假的QIODevice
  • @KubaOber,感谢您的确认。既然你在这里,我在考虑如何实现,我得出的结论是,这甚至需要对QSettings 进行子类化(以便它采用表名/注册表路径而不是文件名),甚至原来的 QSettings 构造函数采用 filename 应该不再可用。所以,似乎根本不需要使用QSettings,从头开始,对吗?还是我想错了?
  • 我写了一个关于你的任务的完整示例here
【解决方案2】:

根据 Mike 的回答,这是我寻求的解决方案。不漂亮,但它有效:

bool readSqlite(QIODevice &device, QSettings::SettingsMap &map) {
    // Read the map from SQL database
    return true;
}

bool writeSqlite(QIODevice &device, const QSettings::SettingsMap &map) {
    device.write("X", 1); // HACK - required to get readSqlite to work
    // Write the map to SQL database
    return true;
}

void Settings::initialize() {
    const QSettings::Format SqliteFormat = QSettings::registerFormat("sqlite", &readSqlite, &writeSqlite);
    QSettings::setDefaultFormat(SqliteFormat);
}

【讨论】:

  • 这将导致未使用的配置文件在每次调用writeSqlite 时不必要地增长一个字节。如果您将使用此解决方案,请忽略write 调用并为您的应用程序提供一个非空配置文件(您必须在QSettings 中使用此配置文件),或者仅在中添加write 调用如果配置文件为空(例如if(device.size() == 0) device.write("X");)。
  • @Mike,最初我只向这个设备写入一次,但似乎 Qt 在每次调用 writeSqlite 之前都会清除设备(这再次导致 readSqlite 没有被调用),所以这就是我为什么也结束了每次都给它写信。不过,以防万一,对device.size() 进行额外检查确实有意义。
  • 是的,你是对的。 QSettings 将始终以只写模式打开文件,因此文件将始终被设置映射中的新数据覆盖。在写入设备之前,device.size() 将始终在自定义写入函数中返回 0。抱歉,我在写第一条评论时错过了这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-11
  • 1970-01-01
  • 1970-01-01
  • 2017-05-06
  • 1970-01-01
  • 2011-11-12
  • 2021-09-11
相关资源
最近更新 更多