Qt源码那些事儿-Qt中 UI文件是如何转成C++文件的

发布于 2020-05-04  393 次阅读


UI文件为标准的XML
h文件为标准的Qt语法的文件。
先思考一分钟:如何让你来设计,你如何做转化?

过程

其实过程很简单
读取ui文件(即xml) -> 经过一些规则的变化-> 输出.h文件

实际上
只是单纯的规则变化 - 字符串变化,这个姑且认为是词法分析的一个简单版本吧。(应该算应该算

Qt代码以及位置

Qt对应的工程名字为UIC

代码位置

C:\Qt\Qt5.14.1\5.14.1\Src\qtbase\src\tools\uic

是一个简单的pro文件,可以直接用QtCreator打开

配置

如果平时有注意Qt的文件编译的时候会发现uic的编译过程的。建议有时间多观察下Qt代码的编译过程,对比C++的编译过程

举个栗子

我们把 form.ui 转化成 ui_form.h
需要在工程配置中
在Command line arguments里把对应的命令加上
可以看下我的配置

格式就是
源文件(.ui) -o 目标文件(.h)

然后可以直接点击调试来调试Qt的uic的源码了。

forn.ui

这里先贴上form.ui的描述

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>wpsObject</class>
 <widget class="QWidget" name="wpsObject">
  <property name="windowModality">
   <enum>Qt::ApplicationModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>481</width>
    <height>394</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>wpsTitle</string>
  </property>
 </widget>
 <resources/>
 <connections/>
</ui>

解析过程

比如如何解析UI文件中的widget的一部分信息的代码

 <widget class="QWidget" name="wpsObject">
  <property name="windowModality">
   <enum>Qt::ApplicationModal</enum>
  </property>

代码在

C:\Qt\Qt5.14.1\5.14.1\Src\qtbase\src\tools\uic\ui4.cpp

中的

    while (!reader.hasError()) {
        switch (reader.readNext()) {
        case QXmlStreamReader::StartElement : {
            const QStringRef tag = reader.name();
            if (!tag.compare(QLatin1String("author"), Qt::CaseInsensitive)) {
                setElementAuthor(reader.readElementText());
                continue;
            }
            if (!tag.compare(QLatin1String("comment"), Qt::CaseInsensitive)) {
                setElementComment(reader.readElementText());
                continue;
            }
            if (!tag.compare(QLatin1String("exportmacro"), Qt::CaseInsensitive)) {
                setElementExportMacro(reader.readElementText());
                continue;
            }
            if (!tag.compare(QLatin1String("class"), Qt::CaseInsensitive)) {
                setElementClass(reader.readElementText());
                continue;
            }
            if (!tag.compare(QLatin1String("widget"), Qt::CaseInsensitive)) {
                auto *v = new DomWidget();
                v->read(reader);
                setElementWidget(v);
                continue;
            }

重点是解析widget这句

if (!tag.compare(QLatin1String("widget"), Qt::CaseInsensitive)) {
    auto *v = new DomWidget();
    v->read(reader);
    setElementWidget(v);
    continue;
}

看里面DomWidget的实现

    while (!reader.hasError()) {
        switch (reader.readNext()) {
        case QXmlStreamReader::StartElement : {
            const QStringRef tag = reader.name();
            if (!tag.compare(QLatin1String("class"), Qt::CaseInsensitive)) {
                m_class.append(reader.readElementText());
                continue;
            }
            if (!tag.compare(QLatin1String("property"), Qt::CaseInsensitive)) {
                auto *v = new DomProperty();
                v->read(reader);
                m_property.append(v);
                continue;
            }
            if (!tag.compare(QLatin1String("script"), Qt::CaseInsensitive)) {
                qWarning("Omitting deprecated element <script>.");
                reader.skipCurrentElement();
                continue;
            }
            if (!tag.compare(QLatin1String("widgetdata"), Qt::CaseInsensitive)) {
                qWarning("Omitting deprecated element <widgetdata>.");
                reader.skipCurrentElement();
                continue;
            }
            if (!tag.compare(QLatin1String("attribute"), Qt::CaseInsensitive)) {
                auto *v = new DomProperty();
                v->read(reader);
                m_attribute.append(v);
                continue;
            }

重点是这一句

if (!tag.compare(QLatin1String("attribute"), Qt::CaseInsensitive)) {
    auto *v = new DomProperty();
    v->read(reader);
    m_attribute.append(v);
    continue;
}

回头再看看我们要解析的ui文件的那部分

 <widget class="QWidget" name="wpsObject">
  <property name="windowModality">
   <enum>Qt::ApplicationModal</enum>
  </property>

widget中的property元素就是在这里解析的。

是不是超级简单???!!!!

总结

这部分代码个人觉得连编译过程中的语法解析都算不上。只是按照规则,将XML转化成了CPP语法的文件。好吧,听起来也算是语法解析。不过这次算是我们肉眼能够看到的。

欢迎关注我的小程序,小程序内容与网站自动保持同步

欢迎关注我的微信公众号,本网站所有的文章以及更新以后都会手动同步到微信公众号上。


公交车司机终于在众人的指责中将座位让给了老太太