Qt中 UI文件是如何转成C++文件的—UIC工程(Qt源码剖析)

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语法的文件。好吧,听起来也算是语法解析。不过这次算是我们肉眼能够看到的。


文章作者: 张小飞
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 张小飞 !
 上一篇
Linux下Qt关于fctix输入法的问题 Linux下Qt关于fctix输入法的问题
前言由于我这里一直在用ibus输入法,还用的Qt5.12安装包自带的qtcreator(4.9.2),一直没问题,最近切了个搜狗输入法,然后发现QtCreator也输入不了中文了。就这里总结下自己的解决方案 QtCreator输入中文其实方
2020-06-29
下一篇 
[转]Deepin开发解决系统字体bug的过程 [转]Deepin开发解决系统字体bug的过程
今天又被 fontconfig 坑到了……仔细想想,半年到一年前我还对 fontconfig 狗屁不通呢,而现在我已经被 fontconfit 坑了有几次了,这印证了一个真理:“只要你足够迟钝,世界就是美好的,一旦你有了某种能力,麻烦就会找
2020-06-29
  目录