zoukankan      html  css  js  c++  java
  • 在Qt中手动添加ui文件

    1.怎么添加UI文件

    我们知道在新建项目的时候,可以选择添加*.ui和不添加两种。

    当添加上ui 文件的时候,我们可以利用designer来添加控件,直观上看到界面的布局,控件的外观

    如果没有添加ui文件,那么久只能用代码生成。

    那么如果有一个现有的类(不带ui文件),可否给他新增ui文件呢?

    答案是可以。毕竟qt designer form 的简介就是

    Creates a Qt Designer form that you can add to a Qt Widget Project. This is useful if you already have an existing class for the UI business logic.

    目录结构:

    第一步:右键项目名称->添加新文件->Qt->Qt designer Form->Widget->**.ui

    第二步:编译。编译下会生成ui_**.h

    第三步:在要添加界面的类的头文件内这样写:

    #ifndef WIDGET1_H
    #define WIDGET1_H
    
    #include <QWidget>
    
    namespace Ui {   //新增的
     class Form;
    }
    
    class Widget1 : public QWidget
    {
        Q_OBJECT
    
        public:
        Widget1(QWidget *parent = 0);
        ~Widget1();
        private :
        Ui::Form *ff;   //新增的
    };
    
    #endif // WIDGET1_H

    第四步:在其对应的.cpp文件内:

    #include "widget1.h"
    #include "QPushButton"
    #include "ui_form.h"   //新增的
    #include <QLabel>
    
    
    Widget1::Widget1(QWidget *parent)
        : QWidget(parent),ff(new Ui::Form)  //新增的
    
    {
    
        QPushButton *a=new QPushButton(this);
        a->setText("a");
        QLabel *vv=new QLabel(this);
        vv->setText("shsh");
        vv->move(100,20);
        ff->setupUi(this);
    }
    
    Widget1::~Widget1()
    {
    
    }

    5.在ui界面的头文件内这样写改

    /********************************************************************************
    ** Form generated from reading UI file 'form.ui'
    **
    ** Created by: Qt User Interface Compiler version 5.11.1
    **
    ** WARNING! All changes made in this file will be lost when recompiling UI file!
    ********************************************************************************/
    
    #ifndef UI_FORM_H
    #define UI_FORM_H
    
    #include <QtCore/QVariant>
    #include <QtWidgets/QApplication>
    #include <QtWidgets/QPushButton>
    #include <QtWidgets/QWidget>
    
    QT_BEGIN_NAMESPACE
    
    class Ui_Form
    {
    public:
        QPushButton *pushButton;
    
        void setupUi(QWidget *Form)
        {
            if (Form->objectName().isEmpty())
                Form->setObjectName(QStringLiteral("Form"));
            Form->resize(400, 300);
            pushButton = new QPushButton(Form);
            pushButton->setObjectName(QStringLiteral("pushButton"));
            pushButton->setGeometry(QRect(240, 180, 75, 23));
    
            retranslateUi(Form);
    
            QMetaObject::connectSlotsByName(Form);
        } // setupUi
    
        void retranslateUi(QWidget *Form)
        {
            Form->setWindowTitle(QApplication::translate("Form", "Form", nullptr));
            pushButton->setText(QApplication::translate("Form", "PushButton", nullptr));
        } // retranslateUi
    
    };
    
    namespace Ui {
        class Form: public Ui_Form {};
    } // namespace Ui
    
    QT_END_NAMESPACE
    
    #endif // UI_FORM_H

    6.试一试:

    在ui界面上直接拖拽控件,看最终的显示结果:

     7.显示结果:

     2.为什么?

    单继承方式是相对于后面要讲的多继承方式,单继承方式也称组合(即委托或代理)方式。单继承方式简单来说就是在代码中首先要自定义一个子类(例如下文中的GoToCellDialog类),该类要从form对应的窗体类(或其兼容的子类)派生;并用ui生成的类定义一个类里的成员变量,该成员变量可以是值也可以是指针,根据使用成员变量的形式不同,又分为成员变量和指针成员变量两种形式。这样在GoToCellDialog的构造函数中可以直接调用ui和ui中的变量和函数,使用起来很方便。

    • 使用成员变量

          即将 Ui::GotoCellDialog ui; 作为类GotoCellDialog(只继承自QDialog,单一继承)的成员变量。这里有一点值得注意的地方,就是ui文件提供的类被包含在了名为Ui的name space里,这样做的目的是将ui文件的命名空间与用户的代码分离,避免两者出现命名冲突的情况。

    • 使用指针成员变量

           与成员变量形式相似,唯一不同的是,将Ui::GoToCellDialog声明为指针成员,即 Ui::GoToCellDialog *ui;
    3.更加详细的资料补充

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

    集成在 Qt Creator中的 UI 设计器
    图 1 集成在 Qt Creator中的 UI 设计器

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

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

    图 2 显示的是选中窗体上放置的标签组件后属性编辑器的内容。最上方显示的文字“LabDemo: QLabel”表示这个组件是一个 QLabel 类的组件,objectName 是LabDemo。

    界面组件的属性编辑器
    图 2 界面组件的属性编辑器

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

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

    设置其他属性的值只需在属性编辑器里操作即可,如设置 LabDemo 的 text 属性为“Hello,World”,只需像图 2 那样修改 text 属性的值即可。

    提示,标准 C++ 语言里并没有 property 关键字,property 是 Qt 对标准 C++ 的扩展,使得在 Qt Designer 里就可以可视化设置类的数据。

    在图 1 显示的设计窗体上,放置一个 Label 和一个 Push Button 组件,它们的主要属性设置见表 3。

    表 3 界面组件的属性设置 ObjectName 类名称  属性设置 备注
    LabDemo QLabel Text=”Hello, World”
    Font.PointSize=20
    Font.bold=true
    设置标签显示文字和字体
    btnClose QPushButton Text=”Close”  设置按钮的文字

    编辑完属性之后,再为 btnClose 按钮增加一个功能,就是单击此按钮时,关闭窗口,退出程序。使用 Signals 和 Slots 编辑器完成这个功能,如图 4 所示。

    信号与槽编辑器中设计信号与槽的关联
    图 4 信号与槽编辑器中设计信号与槽的关联

    在信号与槽编辑器的工具栏上单击“Add”按钮,在出现的条目中,Sender 选择 btnClose,Signal 选择 clicked(),Receiver 选择窗体 Widget,Slot 选择 close()。这样设置表示当按钮 btnClose 被单击时,就执行 Widget 的 close() 函数,实现关闭窗口的功能。

    然后对项目进行编译和运行,可以出现如图 5 所示的窗口,单击“Close”按钮可以关闭程序。

    具有 Close 按钮的“Hello World”程序
    图 5 具有 Close 按钮的“Hello World”程序

    标签的文字内容和字体被修改了,窗口标题也显示为所设置的标题,而我们并没有编写一行程序语句,Qt 是怎么实现这些功能的呢?

    为了搞清楚窗体类的定义,以及界面功能的实现原理,这里将项目进行编译。编译后在项目目录下会自动生成一个文件 ui_widget.h,这样对于一个窗体,就有 4 个文件了,各文件的功能说明见表 6。

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

    下面分别分析各个文件的内容及其功能,以及它们是如何联系在一起工作,实现界面的创建与显示的。

    widget.h 文件

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

    下面是 widget.h 文件的内容:
    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    
    namespace Ui {
    class Widget;
    }
    
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Widget(QWidget *parent = 0);
        ~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 文件是怎么生成的。

    下面是 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>336</width>
        <height>216</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>My First Demo</string>
      </property>
      <widget class="QLabel" name="Lablabel">
       <property name="geometry">
        <rect>
         <x>100</x>
         <y>70</y>
         <width>141</width>
         <height>61</height>
        </rect>
       </property>
       <property name="font">
        <font>
         <pointsize>12</pointsize>
         <weight>75</weight>
         <bold>true</bold>
        </font>
       </property>
       <property name="text">
        <string>Hello,World</string>
       </property>
      </widget>
      <widget class="QPushButton" name="btnClose">
       <property name="geometry">
        <rect>
         <x>210</x>
         <y>150</y>
         <width>75</width>
         <height>23</height>
        </rect>
       </property>
       <property name="text">
        <string>Close</string>
       </property>
      </widget>
    </widget>
    <layoutdefault spacing="6" margin="11"/>
    <resources/>
    <connections>
      <connection>
       <sender>btnClose</sender>
       <signal>clicked()</signal>
       <receiver>Widget</receiver>
       <slot>close()</slot>
       <hints>
        <hint type="sourcelabel">
         <x>247</x>
         <y>161</y>
        </hint>
        <hint type="destinationlabel">
         <x>167</x>
         <y>107</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 也没有必要添加到项目里。

    下面是 ui_widget.h 文件的内容:
    1. /********************************************************************************
    2. ** Form generated from reading UI file 'widget.ui'
    3. **
    4. ** Created by: Qt User Interface Compiler version 5.9.1
    5. **
    6. ** WARNING! All changes made in this file will be lost when recompiling UI file!
    7. ********************************************************************************/
    8. #ifndef UI_WIDGET_H
    9. #define UI_WIDGET_H
    10. #include <QtCore/QVariant>
    11. #include <QtWidgets/QAction>
    12. #include <QtWidgets/QApplication>
    13. #include <QtWidgets/QButtonGroup>
    14. #include <QtWidgets/QHeaderView>
    15. #include <QtWidgets/QLabel>
    16. #include <QtWidgets/QPushButton>
    17. #include <QtWidgets/QWidget>
    18. QT_BEGIN_NAMESPACE
    19. class Ui_Widget
    20. {
    21. public:
    22. QLabel *label;
    23. QPushButton *btnClose;
    24. void setupUi(QWidget *Widget)
    25. {
    26. if (Widget->objectName().isEmpty())
    27. Widget->setObjectName(QStringLiteral("Widget"));
    28. Widget->resize(336, 216);
    29. label = new QLabel(Widget);
    30. label->setObjectName(QStringLiteral("label"));
    31. label->setGeometry(QRect(100, 70, 141, 61));
    32. QFont font;
    33. font.setPointSize(12);
    34. font.setBold(true);
    35. font.setWeight(75);
    36. label->setFont(font);
    37. btnClose = new QPushButton(Widget);
    38. btnClose->setObjectName(QStringLiteral("btnClose"));
    39. btnClose->setGeometry(QRect(210, 150, 75, 23));
    40. retranslateUi(Widget);
    41. QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close()));
    42. QMetaObject::connectSlotsByName(Widget);
    43. } // setupUi
    44. void retranslateUi(QWidget *Widget)
    45. {
    46. Widget->setWindowTitle(QApplication::translate("Widget", "My First Demo", Q_NULLPTR));
    47. label->setText(QApplication::translate("Widget", "Hello357274214World", Q_NULLPTR));
    48. btnClose->setText(QApplication::translate("Widget", "Close", Q_NULLPTR));
    49. } // retranslateUi
    50. };
    51. namespace Ui {
    52. class Widget: public Ui_Widget {};
    53. } // namespace Ui
    54. QT_END_NAMESPACE
    55. #endif // UI_WIDGET_H

    查看 ui_widget.h 文件的内容,发现它主要做了以下的一些工作:
    1. 定义了一个类 Ui_Widget,用于封装可视化设计的界面。
    2. 自动生成了界面各个组件的类成员变量定义。在 public 部分为界面上每个组件定义了一个指针变量,变量的名称就是设置的 objectName。比如,在窗体上放置了一个 QLabel 和一个 QPushButton 并命名后,自动生成的定义是:

      QLabel *LabDemo;
      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 指针可以访问可视化设计的界面组件就可以了。

    相关文件推荐:
    Qt .ui文件介绍相关软件推荐
    谈.ui文件的用法 这是一篇对Qt项目中ui文件用法的软件,有对.ui文件的详细介绍
    Qt之UI文件设计和运行机制 这是一篇对Qt项目中各个文件整体介绍的一篇软文,讲的很详细
    Qt中.ui文件的使用 .ui文件有3种使用形式在这篇文章中得到了很好的阐述
  • 相关阅读:
    Java安全之JNDI注入
    Visual Studio 2019 升级16.8之后(升级.Net 5),RazorTagHelper任务意外失败
    .Net Core 3.1升级 .Net 5后出现代码错误 rzc generate exited with code 1.
    重走py 之路 ——普通操作与函数(三)
    重走py 之路 ——字典和集合(二)
    设计模式结(完结篇)
    重走py 之路 ——列表(一)
    RestfulApi 学习笔记——分页和排序(五)
    RestfulApi 学习笔记——查询与过滤还有搜索(五)
    Android开发 Error:The number of method references in a .dex file cannot exceed 64K.Android开发 Error:The number of method references in a .dex file cannot exceed 64K
  • 原文地址:https://www.cnblogs.com/sggggr/p/12680756.html
Copyright © 2011-2022 走看看