【问题标题】:Q_PROPERTY with parameterized read and write accessors带有参数化读写访问器的 Q_PROPERTY
【发布时间】:2016-05-23 13:14:21
【问题描述】:

我有一个Configuration,其中包含有关文件位置的一些基本信息,例如下载、安装、图片、音乐、文档等位置。 这些当前使用Q_PROPERTY 暴露于QML。它们都有自己的访问器:

Q_PROPERTY(QUrl download_location READ download_location WRITE set_download_location NOTIFY download_location_changed)

这些访问器基本上做所有相同的事情,我想摆脱我必须编写的所有这些冗余代码。

我的第一个想法是有一个小的嵌套类FileLocation,它提供了获取、设置和验证功能。但是,我如何将这些连接到Q_PROPERTY

另外,如果我有类似带参数的静态函数(例如check_validity( QUrl location )),我将如何从 QML 端交出这个参数?

我认为我在这里走错了路,所以我的问题是如何将Q_PROPERTY 上下文中的冗余代码保持在合理的范围内,避免为非常相似的编写负载和负载的 get、set 和 changed 函数对象?

这里还有一些代码:

class Configuration : public QObject
{
  QObject

  Q_PROPERTY(QUrl download_location READ download_location WRITE set_download_location NOTIFY download_location_changed)
  Q_PROPERTY(QUrl music_location READ music_location WRITE set_music_location NOTIFY music_location_changed)
  ...

signals:
  void download_location_changed();
  void music_location_changed();
  ...

public slots:
  void set_download_location(QUrl location)
  {
    download_location = location;
    emit download_location_changed(download_location);
  }

  void set_music_location(QUrl location)
  {
    music_location = location;
    emit music_location_changed(music_location);
  }
  ...

private:
  QUrl download_location,
       music_location,
       ...;
}

因此,正如您所见,有很多重复出现的代码都具有相同的功能,我想稍微缓和一下。我怎么做?我在考虑一些让成员工作的通用函数设置、获取、更改等是一个参数。但是后来我不知道如何从 qml 交出要处理的成员。

我刚刚发现了通过qmlRegisterType(...) 将 C++ 类公开给 qml 的可能性 - 也许这就是要走的路?

【问题讨论】:

  • 你能发布更多代码吗?我很难看出问题出在哪里。
  • 哪个代码是多余的?

标签: c++ qt qml


【解决方案1】:

你可以选择一个邪恶的宏:

#define IMPL(data, name) \
    inline decltype(data) name() const { return data; } \
    inline void set_##name(decltype(data) value) { if (value != data) { data = value; emit name##Changed();} }

当然,如果您不需要任何额外的东西,您可以简单地使用 MEMBER 属性并让 Qt 自动为您生成访问器。

但是,如果您需要在访问器中执行自定义操作,这将不起作用,宏将只需将您的内容添加到其中。

最后,当你声明一个Q_PROPERTY时,你可以右击属性,去重构,然后选择“generate missing members...”,Qt将为访问器生成默认存根,你只会必须添加自定义的东西。这样做的缺点是它有将生成的代码放在最愚蠢的地方的讨厌习惯,所以如果你想让你的类看起来整洁,你必须手动移动它。

qmlRegisterType() 是当您想要注册一个类型以便可以在 QML 中创建它时,您通常无需执行任何操作即可从 QML 访问 QObject 派生对象 - 它适用于 QObject 派生对象,您只需要为没有生成元信息的类型注册一个元类型。

最后但并非最不重要的一点 - 我认为将您的配置作为 C++ 对象没有任何意义,您也可以在 QML 中进行,并使用 Qt.labs.settings 进行设置执着的。 C++ 仅适用于性能关键部分。如果您在 QML 中进行配置,则无需担心任何样板代码,因为它在 QML 中是完全自动的,无需编写访问器,无需在每次微小更改时重新编译您的项目。

【讨论】:

  • 感谢您指出各种选项。我什至在我们的代码中看到了QSettings,需要弄清楚它是否没有被充分使用,或者是否有理由不按照你的建议去做。
  • @DenverCoder21 - QSettings 来自“旧时代”,当然它也可以在 QML 项目中工作,但是 QML 有 Settings 元素,如果你使用它更容易使用使用 QML 没有充分的理由使用旧的设置类,除非您想严格控制设置的存储方式。使用 QML Settings,它是全自动的,很可能默认使用与 QSettings 相同的存储方案,后者您可以自定义设置存储方案。或者如果你有一些不支持的设置类型,在 QML 中只支持字符串和数字之类的东西,通常就足够了。
  • 我认为保留QSettings 而不是Settings 的原因是能够为设置提供一个集中的位置,包括那些只使用C++ 的设置。对此有什么想法吗?
  • @DenverCoder21 - 如果它适合你,那就没问题。根据我的经验,我了解到最宝贵的资源是时间,并且在 QML 中一切都完成得更快,所以我将大部分应用程序代码保留在那里,只有在不可避免的情况下才会保留 C++。请记住,您可以轻松地从 C++ 访问 QML 对象属性。
  • 可能是个愚蠢的问题,但是:怎么会这样? (从 C++ 访问 QML 属性)如果为此找到了 findChild,还有其他方法吗?除此之外,非常感谢您的耐心和彻底的帮助。
猜你喜欢
  • 2016-03-24
  • 2021-12-21
  • 2018-08-17
  • 1970-01-01
  • 2021-09-14
  • 2012-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多