将QML编译为C++:使类型可见

Compiling QML to C++: Making types visible

将QML编译为C++:使类型可见

Tuesday May 24, 2022 by Ulf Hermann | Comments

​2022年5月24日,星期二,乌尔夫·赫尔曼 评论

This is the third installment in the series of blog posts on how to adjust your QML application to take the maximum advantage of qmlsc. In the first post we've set up the environment. You should read that post first in order to understand the others. In the second post I've shown how to add type annotations to JavaScript functions. Now we need to make sure that all types we want to use in QML are visible at compile time.

​这是关于如何调整QML应用程序以最大限度地利用qmlsc的博客文章系列的第三部分。在第一篇文章中,我们设置了环境。为了理解其他人,你应该先读那篇文章。在第二篇文章中,我展示了如何向JavaScript函数添加类型注释。现在,我们需要确保要在QML中使用的所有类型在编译时都是可见的。

If you compile Qt Creator again, after our latest changes to the ButtonsBar.qml file, you may see some warnings like these:

如果您再次编译Qt-Creator,在我们对ButtonsBar.qml文件进行最新更改之后。您可能会看到如下警告:

Warning: ButtonsBar.qml: Object type Timeline::TimelineTheme is not derived from QObject or QQmlComponent
Warning: ButtonsBar.qml:59:34: Property "PanelStatusBarBackgroundColor" not found on type "Timeline::TimelineTheme"
        color: Theme.color(Theme.PanelStatusBarBackgroundColor)

Clearly, qmlsc has trouble identifying the type of our TimelineTheme. This means the binding for the background color of our button is not compiled to C++. Let's see how long it takes to execute this binding in its unoptimized form. QML-profile Qt Creator and load our example trace in the instance being profiled as described in the first blog post. Then look at ButtonsBar.qml again in the editor. You should see a little label to the left of the binding we're interested in.

很明显,qmlsc很难确定我们的时间表的类型。这意味着按钮背景色的绑定未编译为C++。让我们看看以未优化的形式执行此绑定需要多长时间。QML profile Qt Creator,并将我们的示例跟踪加载到第一篇博文中描述的正在分析的实例中。然后再次在编辑器中查看ButtonsBar.qml 。您应该会在我们感兴趣的装订左侧看到一个小标签。

Clicking that label focuses the respective events in the QML profiler. We note that the binding is called once, and on my computer it takes 14.2µs to evaluate. I won't repeat the point about it not being a statistically significant measurement anymore. This disclaimer holds for all such numbers from here on.

单击该标签将聚焦QML探查器中的各个事件。我们注意到绑定只调用了一次,在我的计算机上需要14.2µs来评估。我不再重复这一点,即它不再是一个具有统计意义的衡量指标。从现在起,此免责声明适用于所有此类数字。

Back to the original warning, though. Why is this type unknown to qmlsc? The base type of Timeline::TimelineTheme is Utils::Theme, as we can see in timelinetheme.h:

不过还是回到了最初的警告。为什么qmlsc不知道这种类型?Timeline::TimelineTheme的基本类型是Utils::Theme,正如我们在TimelineTheme.h中看到的那样:

class TRACING_EXPORT TimelineTheme : public Utils::Theme
{
    Q_OBJECT
    [...]

The Utils library, however, is not prepared to be integrated with a QML module. In particular, it does not generate a metatypes.json file. The QML module for our Tracing library needs such metatypes to, well, know the types it's dealing with. You can make a library generate metatypes.json files using the qt_extract_metatypes() CMake command.

​但是,Utils库不准备与QML模块集成。特别是,它不生成metatypes.json文件。我们跟踪库的QML模块需要这样的元类型,以便很好地了解它所处理的类型。您可以使库生成metatypes.json文件,使用qt_extract_metatypes()CMake命令。

There is no downside to having those metatypes generated. Therefore, let's generate them for all of the libraries in Qt Creator. For this, we adapt Qt Creator's cmake/QtCreatorAPI.cmake and add this command to add_qtc_library(), conditional on Qt Creator being compiled with Qt >= 6.2 and using CMake's AUTOMOC feature:

生成这些元类型没有坏处。因此,让我们为Qt Creator中的所有库生成它们。为此,我们采用了Qt Creator的cmake/QtCreatorAPI。cmake并添加此命令 add_qtc_library(),条件是使用Qt>=6.2编译Qt Creator并使用cmake的AUTOMOC功能:

get_target_property(have_automoc_prop ${name} AUTOMOC)
if("${Qt5_VERSION}" VERSION_GREATER_EQUAL "6.2.0" AND "${have_automoc_prop}")
  qt_extract_metatypes(${name})
endif()

We need to query for AUTOMOC as the metatypes files are generated by moc. In places where we don't run moc, we cannot generate any metatypes. However, there probably aren't any types to be exposed to QML in such places.

我们需要查询AUTOMOC,因为元类型文件是由moc生成的。在不运行moc的地方,我们无法生成任何元类型。然而,在这些地方可能没有任何类型可以暴露于QML。

Indeed this helps and the original warning is gone. However, we get a new warning in the same place:

事实上,这是有帮助的,最初的警告已经消失了。然而,我们在同样的地方得到了一个新的警告:

Warning: ButtonsBar.qml:59:22: Could not compile binding for color: type Color for argument 0 cannot be resolved
        color: Theme.color(Theme.PanelStatusBarBackgroundColor)

Why is that? The "color" method is declared in the Utils::Theme C++ type, in the file src/libs/utils/theme/theme.h, like this:

为什么会这样?“color”方法在文件src/libs/Utils/Theme/Theme.h中的Utils::Theme C++类型中声明。 像这样:

Q_INVOKABLE QColor color(Color role) const;

It's always a good idea to run the available C++ static analysis tools on all your files. If Qt Creator doesn't do it automatically, you can trigger it using the "Tools" -> "C++" -> "Analyze Current File" menu entry. Among other things, this will run the equivalent of the "clazy" tool on theme.h, which will give you a warning that tells you exactly what is wrong:

最好在所有文件上运行可用的C++静态分析工具。如果Qt Creator没有自动执行此操作,可以使用“工具”->“C++”->“分析当前文件”菜单项触发它。除其他外,这将在theme.h上运行与“clazy”工具相当的工具。 这会给你一个警告,告诉你到底出了什么问题:

theme.h:471:17: invokable arguments need to be fully-qualified (Utils::Theme::Color instead of Color) [clazy-fully-qualified-moc-types]

Indeed, the metatype system will only be able to see the argument type at compile time if you fully qualify it. If you don't, then qmlsc doesn't know it. Let's fix it:

实际上,只有在完全限定参数类型的情况下,元类型系统才能在编译时看到它。如果您不知道,那么qmlsc不知道。让我们修复它:

Q_INVOKABLE QColor color(Utils::Theme::Color role) const;

With that out of the way we're fine, one might think. Alas, not quite:

有人可能会想,这样我们就没事了。唉,不完全是这样:

Warning: ButtonsBar.qml:59:22: Could not compile binding for color: return type QColor cannot be resolved
        color: Theme.color(Theme.PanelStatusBarBackgroundColor)

What is this? The compiler does not know QColor. QColor, as you may know, is a value type in QML. You can declare properties of type "color" on your elements, and if you assign them elsewhere, they are copied, rather than referred to like QObjects. Value types, like object types, are either built-in or belong to some module. QColor is not built-in as you may verify by inspecting the qml/builtins.qmltypes file of your Qt installation. As colors are inherently a visual thing, it belongs to the QtQuick module. The documentation states as much:

​这是什么?编译器不知道QColor。您可能知道,QColor是QML中的一种值类型。您可以在元素上声明类型为“color”的属性,如果您在其他地方指定它们,它们将被复制,而不是像QObjects一样被引用。值类型与对象类型一样,要么是内置的,要么属于某个模块。QColor不是内置的,您可以通过检查Qt安装的qml/builtins.qmltypes文件来验证。由于颜色本质上是一种视觉事物,因此它属于QtQuick模块。文件说明如下:

This value type is provided by the QtQuick import.

Now, if you look at the header of ButtonsBar.qml you see:

现在,如果你看一下ButtonsBar.qml的标题。您看到:

import QtQuick 2.1

So we should be fine, right? Look at the warning again. It says "return type QColor". It does not complain about the handling of QColor in the binding on Rectangle's color. Rather, it does not know what QColor is supposed to mean in the context of the function declaration of Theme::color(). This makes sense because a C++ type can be exposed by multiple modules in different ways. Just because QtQuick happens to have a QML type for QColor, we cannot assume that this is the one to be used here. However, we don't have any special rules for QColor in the QML module QtCreator.Tracing. We just want it to be passed through. So, let's tell the compiler to depend on QtQuick for everything it does with the QtCreator.Tracing module. This is what the "DEPENDENCIES" option to the the qt_add_qml_module() CMake command is for. So, in the CMakeLists.txt for QtCreator.Tracing at src/libs/tracing/CMakeLists.txt, adjust the QML module to add the dependency:

​所以我们应该没事吧?再次查看警告。上面写着“返回类型QColor”。不要抱怨矩形颜色绑定中QColor的处理。相反,它不知道在Theme::color()的函数声明上下文中QColor应该是什么意思。这很有意义,因为一个C++类型可以由多个模块以不同的方式公开。仅仅因为QtQuick碰巧有QColor的QML类型,我们不能假设这里使用的是QML类型。但是,在QML模块QtCreator中,我们没有针对QColor的任何特殊跟踪规则。我们只想让它通过。因此,让我们告诉编译器,它对QtCreator所做的一切都依赖于QtQuick。跟踪模块。这就是qt_add_qml_module()CMake命令的“DEPENDENCIES”选项的作用。所以,在QtCreator的CMakeLists.txt中。在src/libs/Tracing/CMakeLists.txt进行跟踪。调整QML模块以添加依赖项:

qt_add_qml_module(Tracing
  URI "QtCreator.Tracing"
  VERSION "1.0"
  NO_PLUGIN
  DEPENDENCIES
    QtQuick
  QML_FILES
    ${TRACING_QML_FILES}
  RESOURCES
    ${TRACING_QML_RESOURCES}
  SOURCES
    ${TRACING_CPP_SOURCES}
)

This was the last warning in the ButtonsBar.qml file. Yay! How long does the binding on color take now? Profile again and click on the source label again. 9.17µs it says on my machine, so we've saved 5µs.

这是ButtonsBar.qml文件的最后一条警告。耶!现在绑定颜色需要多长时间?再次配置文件并再次单击源标签。我的机器上显示为9.17µs,因此我们节省了5µs。

Compatibility

兼容性

We heavily depend on declarative QML type registration for all of this. Declarative type registration has been around since Qt 5.15. qt_add_qml_module() has been available since Qt 6.2, but if you are still writing qmldir files manually, you can also just add the dependencies manually by inserting "depends" entries as described in the docs.

 ​我们严重依赖声明性QML类型注册来实现所有这些。声明式类型注册自Qt 5.15以来就一直存在。qt_add_qml_module()自qt 6.2起就已可用,但如果仍在手动编写qmldir文件,也可以通过插入文档中所述的“依赖项”条目手动添加依赖项。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值