---
title: framework-cpp-qt-01-工程文件详解
EntryName: framework-cpp-qt-01-project-file
date: 2020-04-08 16:37:37
categories:
tags:
- qt
- c/c++
---
**章节描述:**
在QT的项目中,有些文件是与QT有关而与源码无关的。

项目管理文件(.pro)

后缀为“.pro”的文件是项目的管理文件,文件名就是项目的名称。

项目管理文件用于记录项目的一些设置,以及项目包含文件的组织管理。

QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = samp2_1
TEMPLATE = app
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui

“Qt += core gui”表示项目中加入 core gui 模块。core gui 是 Qt 用于 GUI 设计的类库模块,如果创建的是控制台(Console)应用程序,就不需要添加 core gui。

Qt 类库以模块的形式组织各种功能的类,根据项目涉及的功能需求,在项目中添加适当的类库模块支持。例如,如果项目中使用到了涉及数据库操作的类就需要用到 sql 模块,在 pro 文件中需要增加如下一行: Qt +=sql

SOURCES、HEADERS、FORMS 记录了项目中包含的源程序文件、头文件和窗体文件(.ui 文件)的名称。这些文件列表是 Qt Creator 自动添加到项目管理文件里面的,用户不需要手动修改。当添加一个文件到项目,或从项目里删除一个文件时,项目管理文件里的条目会自动修改。

项目界面文件(.ui)

后缀为“.ui”的文件是可视化设计的窗体的定义文件,如 widget.ui。双击项目文件目录树中的文件 widget.ui,会打开一个集成在 Qt Creator 中的 Qt Designer 对窗体进行可视化设计。

本教程将称这个集成在 Qt Creator 中的 Qt Designer 为“UI 设计器”,以便与独立运行的 Qt Designer 区别开来。

  • 组件面板:窗口左侧是界面设计组件面板,分为多个组,如Layouts、Buttons、Display Widgets等,界面设计的常见组件都可以在组件面板里找到。
  • 中间主要区域是待设计的窗体。如果要将某个组件放置到窗体上时,从组件面板上拖放一个组件到窗体上即可。例如,先放一个 Label 和一个 Push Button 到窗体上。
  • Signals 和 Slots 编辑器与 Action 编辑器是位于待设计窗体下方的两个编辑器。Signals 和Slots 编辑器用于可视化地进行信号与槽的关联,Action 编辑器用于可视化设计 Action。
  • 布局和界面设计工具栏:窗口上方的一个工具栏,工具栏上的按钮主要实现布局和界面设计。
  • 对象浏览器(Object Inspector):窗口右上方是 Object Inspector,用树状视图显示窗体上各组件之间的布局包含关系,视图有两列,显示每个组件的对象名称(ObjectName)和类名称。
  • 属性编辑器(Property Editor):窗口右下方是属性编辑器,是界面设计时最常用到的编辑器。属性编辑器显示某个选中的组件或窗体的各种属性及其取值,可以在属性编辑器里修改这些属性的值。

选中窗体上放置的组件后,右下角会有属性编辑器。

  • 最上方显示的文字“LabDemo: QLabel”表示这个组件是一个 QLabel 类的组件
  • objectName 是LabDemo。
  • 设置其他属性的值只需在属性编辑器里操作即可。

属性编辑器的内容分为两列,分别为属性的名称和属性的值。属性又分为多个组,实际上表示了类的继承关系,可以看出 QLabel 的继承关系是QObject→QWidget→QFrame→QLabel

objectName 表示组件的对象名称,界面上的每个组件都需要一个唯一的对象名称,以便被引用。界面上的组件的命名应该遵循一定的法则,具体使用什么样的命名法则根据个人习惯而定,主要目的是便于区分和记忆,也要便于与普通变量相区分。

添加按钮

我们尝试添加一个按钮,并实现:“点击按钮就关闭窗口退出程序”的功能。

使用 Signals 和 Slots 编辑器完成这个功能

拖拽一个pushButton,自定义一个名字。

界面中间靠下的位置,找到Action Editor那一行,点击Signals Slots Editor

点击绿色的加号,做以下选择:

  • 发送者:pushButton
  • 信号:clicked()
  • 接收者:Widget
  • 槽:close()

我们并没有写一行代码, Qt 是怎么实现这些功能的呢 ?

分析现在的文件,就可以找到答案。

项目文件分析

我们先回头去看,窗体相关的 4 个文件:

文件名 功能
widget.h 定义窗体类的头文件,定义了类Widget
widget.cpp Widget 类的功能实现源程序文件
widget.ui 窗体界面文件,由UI设计器自动生成,存储了窗体上各个组件的属性设置和布局
ui_widget.h (自动生成)编译后,根据窗体上的组件及其属性、信号与槽的关联等自动生成的一个类的定义文件,类的名称是Ui_Widget

widget.h

widget.h 文件是窗体类的头文件。在创建项目时,选择窗体基类是 QWidget,在 widget.h 中定义了一个继承自 QWidget 的类 Widget。

#ifndef WIDGET_H
#define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE class Widget : public QWidget
{
Q_OBJECT public:
Widget(QWidget *parent = nullptr);
~Widget(); private:
Ui::Widget *ui;
};
#endif // WIDGET_H

widget.h 文件有几个重要的部分。

namespace 声明

代码中有如下的一个 namespace 声明:

namespace Ui {
class Widget;
}

这是声明了一个名称为 Ui 的命名空间(namespace),包含一个类 Widget。但是这个类 Widget 并不是本文件里定义的类 Widget,而是 ui_widget.h 文件里定义的类,用于描述界面组件的。这个声明相当于一个外部类型声明(具体要看完 ui_widget.h 文件内的解释之后才能搞明白)。

Widget 类的定义

widget.h 文件的主体部分是一个继承于 QWidget 的类 Widget 的定义,也就是本实例的窗体类。

在 Widget 类中使用了宏 Q_OBJECT,这是使用 Qt 的信号与槽(signal 和 slot)机制的类都必须加入的一个宏(信号与槽在后面详细介绍)。

在 public 部分定义了 Widget 类的构造函数和析构函数。

在 private 部分又定义了一个指针。 Ui::Widget *ui; 这个指针是用前面声明的 namespace Ui 里的 Widget 类定义的,所以指针 ui 是指向可视化设计的界面,后面会看到要访问界面上的组件,都需要通过这个指针 ui。

widget.cpp

widget.cpp 文件是类 Widget 的实现代码,下面是 widget.cpp 文件的内容。

#include "widget.h"
#include "ui_widget.h" Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
} Widget::~Widget()
{
delete ui;
}

注意到,在这个文件的包含文件部分自动加入了如下一行内容: #include "ui_widget.h", 这个就是 Qt 编译生成的与 UI 文件 widget.ui 对应的类定义文件。

目前只有构造函数和析构函数。其中构造函数头部是:

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) ;其意义是:执行父类 QWidget 的构造函数,创建一个 Ui::Widget 类的对象 ui。这个 ui 就是 Widget 的 private 部分定义的指针变量 ui。

构造函数里只有一行语句: ui->setupUi(this); 执行了 Ui::Widget 类的 setupUi() 函数,这个函数实现窗口的生成与各种属性的设置、信号与槽的关联(后面会具体介绍)。

析构函数只是简单地删除用 new 创建的指针 ui。

所以,在 ui_widget.h 文件里有一个 namespace 名称为 Ui,里面有一个类 Widget 是用于描述可视化设计的窗体,且与 widget.h 里定义的类同名。在 Widget 类里访问 Ui::Widget 类的成员变量或函数需要通过 Widget 类里的 ui 指针,如同构造函数里执行 ui->setupUi( this) 函数那样。

widget.ui

widget.ui 是窗体界面定义文件,是一个 XML 文件,定义了窗口上的所有组件的属性设置、布局,及其信号与槽函数的关联等。用UI设计器可视化设计的界面都由 Qt 自动解析,并以 XML 文件的形式保存下来。在设计界面时,只需在 UI 设计器里进行可视化设计即可,而不用管 widget.ui 文件是怎么生成的。

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Widget</string>
</property>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>150</x>
<y>230</y>
<width>111</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<family>Adobe Devanagari</family>
<pointsize>11</pointsize>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>330</x>
<y>170</y>
<width>111</width>
<height>71</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>pushButton</sender>
<signal>clicked()</signal>
<receiver>Widget</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>387</x>
<y>181</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections>
</ui>

ui_widget.h

ui_widget.h 是在对 widget.ui 文件编译后生成的一个文件,ui_widget.h 会出现在编译后的目录下,或与 widget.ui 同目录(与项目的 shadow build 编译设置有关)。

文件 ui_widget.h 并不会出现在 Qt Creator 的项目文件目录树里,当然,可以手工将 ui_widget.h 添加到项目中。方法是在项目文件目录树上,右击项目名称节点,在调出的快捷菜单中选择“Add Existing Files…”,找到并添加 ui_widget.h 文件即可。

注意,ui_widget.h 是对 widget.ui 文件编译后自动生成的,widget.ui 又是通过 UI 设计器可视化设计生成的。

所以,对 ui_widget.h 手工进行修改没有什么意义,所有涉及界面的修改都应该直接在UI 设计器里进行。所以,ui_widget.h 也没有必要添加到项目里。

/********************************************************************************
** Form generated from reading UI file 'widget.ui'
**
** Created by: Qt User Interface Compiler version 5.12.5
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/ #ifndef UI_WIDGET_H
#define UI_WIDGET_H #include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QWidget> QT_BEGIN_NAMESPACE class Ui_Widget
{
public:
QLabel *label;
QPushButton *pushButton; void setupUi(QWidget *Widget)
{
if (Widget->objectName().isEmpty())
Widget->setObjectName(QString::fromUtf8("Widget"));
Widget->resize(800, 600);
label = new QLabel(Widget);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(150, 230, 111, 41));
QFont font;
font.setFamily(QString::fromUtf8("Adobe Devanagari"));
font.setPointSize(11);
label->setFont(font);
pushButton = new QPushButton(Widget);
pushButton->setObjectName(QString::fromUtf8("pushButton"));
pushButton->setGeometry(QRect(330, 170, 111, 71)); retranslateUi(Widget);
QObject::connect(pushButton, SIGNAL(clicked()), Widget, SLOT(close())); QMetaObject::connectSlotsByName(Widget);
} // setupUi void retranslateUi(QWidget *Widget)
{
Widget->setWindowTitle(QApplication::translate("Widget", "Widget", nullptr));
label->setText(QApplication::translate("Widget", "TextLabel", nullptr));
pushButton->setText(QApplication::translate("Widget", "PushButton", nullptr));
} // retranslateUi }; namespace Ui {
class Widget: public Ui_Widget {};
} // namespace Ui QT_END_NAMESPACE #endif // UI_WIDGET_H

查看 ui_widget.h 文件的内容,发现它主要做了以下的一些工作:

1)定义了一个类 Ui_Widget,用于封装可视化设计的界面。

2) 自动生成了界面各个组件的类成员变量定义。在 public 部分为界面上每个组件定义了一个指针变量,变量的名称就是设置的 objectName。比如,在窗体上放置了一个 QLabel 和一个 QPushButton 并命名后,自动生成的定义是:

QPushButton *btnClose;

3) 定义了 setupUi() 函数,这个函数用于创建各个界面组件,并设置其位置、大小、文字内容、字体等属性,设置信号与槽的关联。setupUi() 函数体的第一部分是根据可视化设计的界面内容,用 C++ 代码创建界面上各组件,并设置其属性。

接下来,setupUi() 调用了函数 retranslateUi(Widget),用来设置界面各组件的文字内容属性,如标签的文字、按键的文字、窗体的标题等。将界面上的文字设置的内容独立出来作为一个函数 retranslateUi(),在设计多语言界面时会用到这个函数。

setupUi() 函数的第三部分是设置信号与槽的关联,本文件中有以下两行:

QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close()));
QMetaObject::connectSlotsByName(Widget);

第1 行是调用 connect() 函数,将在 UI 设计器里设置的信号与槽的关联转换为语句。这里是将 btnClose 按键的 clicked() 信号与窗体 Widget 的 close() 槽函数关联起来,就是在图 4 中设置的信号与槽的关联的程序语句实现。这样,当单击 btnClose 按钮时,就会执行 Widget 的 close() 槽函数,而 close() 槽函数的功能是关闭窗口。

第 2 行是设置槽函数的关联方式,用于将 UI 设计器自动生成的组件信号的槽函数与组件信号相关联。

所以,在Widget 的构造函数里调用 ui->setupUI(this),就实现了窗体上组件的创建、属性设置、信号与槽的关联。

我们将在不久的章节中,对“信号-槽”机制做出介绍。

4) 定义 namespace Ui,并定义一个从Ui_Widget 继承的类Widget。

namespace Ui {
class Widget: public Ui_Widget {};
}

提示:ui_widget.h 文件里实现界面功能的类是 Ui_Widget。再定义一个类 Widget 从 Ui_Widget 继承而来,并定义在 namespace Ui 里,这样 Ui:: Widget 与 widget.h 里的类 Widget 同名,但是用 namespace 区分开来。所以,界面的 Ui:: Widget 类与文件 widget.h 里定义的 Widget 类实际上是两个类,但是 Qt 的处理让用户感觉不到 Ui:: Widget 类的存在,只需要知道在 Widget 类里用 ui 指针可以访问可视化设计的界面组件就可以了。

main.cpp

main.cpp 是实现 main() 函数的文件,下面是 main.cpp 文件的内容。

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}

main() 函数是应用程序的入口。它的主要功能是创建应用程序,创建窗口,显示窗口,并运行应用程序,开始应用程序的消息循环和事件处理。

QApplication 是 Qt 的标准应用程序类,第 1 行代码定义了一个 QApplication 类的实例 a,就是应用程序对象。

然后定义了一个 Widget 类的变量 w,Widget 是本实例设计的窗口的类名,定义此窗口后再用 w.show() 显示此窗口。

最后一行用 a.exec() 启动应用程序的执行,开始应用程序的消息循环和事件处理。

QT学习:01 工程文件详解的更多相关文章

  1. QT学习日记篇01(1)-QT界面初探- *.pro文件详解

    一: 项目管理文件(.pro文件) 项目管理文件用于记录项目的一些设置,以及项目包含文件的组织管理 后缀为".pro"的 文件是项目的管理文件,文件名就是项目的名称,如Demo.p ...

  2. Qt *.pro工程文件 详解

    先介绍一下QT中关于项目的相关介绍 app - 建立一个应用程序的makefile.这是默认值,所以如果模板没有被指定,这个将被使用. lib - 建立一个库的makefile. vcapp - 建立 ...

  3. Docker学习笔记-Dockerfile文件详解

    什么是Dockerfile? Docker中有个非常重要的概念叫做--镜像(Image).Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序.库.资源.配置等文件外,还包含了一些为运 ...

  4. Docker学习(六)——Dockerfile文件详解

    Docker学习(六)--Dockerfile文件详解 一.环境介绍 1.Dockerfile中所用的所有文件一定要和Dockerfile文件在同一级父目录下,可以为Dockerfile父目录的子目录 ...

  5. J2EE学习篇之--Struts1详解

    今天来看一下Struts1的相关知识,其实Struts现在是出名的,每个Web开发者都会知道的,也是现在比较流行的框架,下面就来看一下我们为什么要用Struts框架呢? 摘要 1.建立在mvc这种好的 ...

  6. delphi 资源文件详解

    delphi资源文件详解 一.引子: 现在的Windows应用程序几乎都使用图标.图片.光标.声音等,我们称它们为资源(Resource).最简单的使用资源的办法是把这些资源的源文件打入软件包,以方便 ...

  7. Angular Npm Package.Json文件详解

    Angular7 Npm Package.Json文件详解   近期时间比较充裕,正好想了解下Angular Project相关内容.于是将Npm官网上关于Package.json的官方说明文档进行了 ...

  8. Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)

    [Android布局学习系列]   1.Android 布局学习之——Layout(布局)详解一   2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)   3.And ...

  9. Activiti工作流学习之流程图应用详解

    Activiti工作流学习之流程图应用详解 1.目的  了解Activiti工作流是怎样应用流程图的. 2.环境准备2.1.相关软件及版本    jdk版本:Jdk1.7及以上 IDE:eclipse ...

  10. AndroidManifest.xml文件详解

    本文为安全专家李洋的最新一篇专栏文章<AndroidManifest.xml文件详解>.AndroidManifest.xml是一个跟安全相关的配置文件,该配置文件是Android安全保障 ...

随机推荐

  1. Linux基础-02:Linux目录操作命令

    Linux中目前可以识别的命令有上万条,如果没有分类,那么学习起来一定痛苦不堪. 所以我们把命令分门别类,主要是为了方便学习和记忆. 下面我们先来学习最为常用的和目录相关的操作命令 最近无意间获得一份 ...

  2. linux终端显示git分支的配置

    1.查看现有配置 $ echo $PS1 2.显示git分支 打开./.bashrc文件 添加以下几行命令: git_branch() { git branch 2> /dev/null | s ...

  3. js中关于return和if条件处理

    好玩的 // if (true) { // return // } // // 不会打印 // console.log('1') // if (false) { // return // } // / ...

  4. 可以远程剪视频、做PS设计的远程控制软件体验

    ​ 编辑切换为居中 在这里插入图片描述 远程连接 资源共享的新时代 过去很长一段时间,计算机网络最主要的用途就是分享数据资源.进入新时代,伴随网络的高速发展以及云计算等技术的发展,我们进入了不仅仅是数 ...

  5. pageoffice 6 实现word文件添加水印

    在很多场景下,Word文档正式发文之前,或者说形成最终文档之前,常常需要往Word文件中添加水印,并且会根据文件类型或内容的不同,需要添加的水印也不一样. 添加水印是Word软件里的一个简单功能,直接 ...

  6. Java生成微信小程序码

    官网文档地址:获取小程序码 package test; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.cor ...

  7. linux下使用chattr创建一个连root都无法删除的文件

    一.关于chattr,lsattr 1.chattr 的作用:改变一个Linux文件系统上的文件属性. 2.chattr用来改变文件.目录的属性,lsattr用来查看文件.目录的属性. 3.chatt ...

  8. 《最新出炉》系列入门篇-Python+Playwright自动化测试-47-自动滚动到元素出现的位置

    1.简介 在我们日常工作中或者生活中,经常会遇到我们的页面内容较多,一个屏幕范围无法完整展示内容,我们就需要滚动滚动条去到我们想要的地方,如下图页面,我们虽然在豆瓣首页,但是内容并不完整,如果我们想要 ...

  9. C# ScottPlot 绘图控件 源码阅读心得体会

    ScottPlot的介绍可以看这篇博客:https://www.cnblogs.com/myshowtime/p/15606399.html 我对代码的理解是这样的: 图像的呈现是靠bitmap,每进 ...

  10. 记录一次 对应用程序日志排查,老是刷出有本地ip登录Sqlserver数据库失败的日志

    在我电脑-计算机管理-事件查看器-windows日志-应用程序里 1秒中就刷很多条 用户sa登录某个数据库失败,客户端ip:192....; 我查看ip发现是本机的ip地址.也就是说有本地的应用程序在 ...