Qt中的ui文件

Qt中的ui文件

简介

Qt中的UI文件是一种特殊的XML格式文件,用于描述应用程序的用户界面。这些文件可以使用Qt的可视化设计工具Qt Designer来创建和编辑。Qt Designer提供了直观的界面,允许用户通过拖放和配置界面元素来设计应用程序的图形用户界面(GUI)。

UI文件包含了界面上各种控件的信息,如按钮、文本框、下拉菜单等,以及它们的布局和属性设置。这些信息以XML格式存储,可以在Qt应用程序中通过Qt User Interface Compiler(uic)工具转换为C++代码,供应用程序使用。

在Qt应用程序中,UI文件通常与C++代码配合使用。开发者可以使用Qt Creator集成开发环境来创建和管理UI文件,并在C++代码中引用和操作这些文件。通过UI文件,开发者可以更加高效地设计和构建图形用户界面,提高应用程序的用户体验。

使用ui文件

默认的代码如下

//头文件
#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
//源文件
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
//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="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>370</x>
<y>240</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
  1. 代码中首先声明了ui中的类,我们看着它的名字也是Widget,但其实它和现在的Widget类是不同的类
namespace Ui {
class Widget;
}
  1. 声明了ui指针指向ui中的类
private:
Ui::Widget *ui;
  1. 包含由uic编译的ui_widget.h头文件,这个过程通常自动完成
#include "ui_widget.h"
  1. 在源文件中进行构造, 这里是使用了列表初始化相对于在构造函数中ui = new Ui::Widget;
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
  1. 在构造函数中使用setupUi使得this指针指向的窗口成为承载ui中描述的布局和空间的对象
ui->setupUi(this);

到这里已经知道了如何显示ui的步骤

探秘ui文件内部

手动编译ui文件 使用 uic ./widget.ui -o ui_widget.h

/********************************************************************************
** Form generated from reading UI file 'widget.ui'
**
** Created by: Qt User Interface Compiler version 6.4.3
**
** 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/QPushButton>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Widget
{
public:
QPushButton *pushButton;
void setupUi(QWidget *Widget)
{
if (Widget->objectName().isEmpty())
Widget->setObjectName("Widget");
Widget->resize(800, 600);
pushButton = new QPushButton(Widget);
pushButton->setObjectName("pushButton");
pushButton->setGeometry(QRect(370, 240, 75, 23));
retranslateUi(Widget);
QMetaObject::connectSlotsByName(Widget);
} // setupUi
void retranslateUi(QWidget *Widget)
{
Widget->setWindowTitle(QCoreApplication::translate("Widget", "Widget", nullptr));
pushButton->setText(QCoreApplication::translate("Widget", "PushButton", nullptr));
} // retranslateUi
};
namespace Ui {
class Widget: public Ui_Widget {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_WIDGET_H
  1. 前几行的说明意思是让我们不要改动这个文件,它会在ui改变时候自动重新生成

  2. setupUi 是 Qt 框架中自动生成的一个函数,通常出现在由 Qt Designer 创建的 UI 文件(.ui 文件)转换而来的 C++ 代码中。这个函数的主要作用是初始化用户界面(UI)。

    当你使用 Qt Designer 设计一个图形用户界面并保存为 .ui 文件后,Qt 的 uic 工具会将这个 .ui 文件转换为一个 C++ 类,这个类包含了一个 setupUi 方法。这个方法负责根据 .ui 文件中的设计,创建和配置界面上的所有控件(如按钮、文本框、列表等),并设置它们的属性(如位置、大小、字体等)。

    此外,setupUi 还会自动处理信号和槽的连接。在 Qt 中,信号和槽是一种用于对象间通信的机制。一个对象的信号可以在某种事件发生时被触发,而槽则是对这个信号的响应。setupUi 会根据 .ui 文件中的设置,自动将控件的信号连接到相应的槽函数上,从而实现了界面上的交互功能。

    在类的构造函数中,通常会调用 setupUi 方法来初始化界面。

  3. retranslateUi是一个Qt特有的方法,用于将UI控件中的文本从默认语言翻译为当前用户系统语言。这个方法通常在应用程序启动时调用,以确保所有UI控件的文本都是用用户的本地语言显示的。在Qt应用程序中,所有的文本字符串都应该定义在一个.ts文件中。这个文件包含所有需要翻译的字符串及其对应的翻译。然后,使用Qt的linguist工具可以将.ts文件翻译成目标语言的.qm文件。应用程序启动时,Qt将加载与用户系统语言相对应的.qm文件,并根据翻译文件中的内容更新UI控件中的文本。retranslateUi方法的作用是将当前窗口(Widget)及其子控件(如按钮)中的文本更新为翻译后的文本。在这个方法中,通过使用QCoreApplication::translate()函数将默认文本字符串转换为翻译后的字符串,并将这些字符串赋值给相应的UI控件。这样,当应用程序运行时,如果用户的系统语言与应用程序使用的语言不同,那么应用程序就会显示翻译后的文本,从而提高用户体验。

  4. 使用namespace封装ui_Widget类为Widget类主要是为了保持一个统一的形式,但是它实质上是ui_Widget类

尝试使用自定义的ui文件

自定义一个myui的ui文件

首先我们要知道我们这个myui里面的类名,这里有一个坑,它一般并不是你的文件名对应的类名,我们到设计师或者用记事本改一下就好了,这里玩改成了MyUi的对象名.

1.在widget中先做前置声明,否则编译器不知道有这个类

namespace Ui{class MyUi;}

在Qt框架中,namespace Ui { class MyUi; } 是一个前向声明,它告诉编译器有一个名为 MyUi 的类定义在 Ui 命名空间中。这通常出现在由Qt的uic工具自动生成的UI类文件中。这些文件通常是由Qt Designer工具创建的.ui文件通过uic工具转换而来的。

这里的 Ui::MyUi 类通常包含了在Qt Designer中定义的所有界面元素(如按钮、文本框等)的声明,以及布局和信号槽连接的设置。这个类通常不会被直接实例化,而是作为另一个类的成员被使用,这个类通常负责实现应用程序的逻辑。

2.声明指向Ui::MyUi的指针

Ui::MyUi * ui2;

3.包含uic自动转化过的ui_myui.h

这里有可能会报错,重新构建一下就好了,因为qmake,cmake并不是实时执行的

3.实例化ui2的对象

ui2 = new Ui::MyUi;

4.setupUi

ui2->setupUi(this);

逻辑和界面分离,使用逻辑类处理ui类中的数据

如果想在别的类中处理ui类的数据或者操纵ui里的控件,其实本质就是要明白对象之间的通信和类的封装

  1. 使用信号和槽
  2. 将this指针传递给别的类,如果想要操纵ui要将ui设置成公有的或者将将逻辑类变成ui类的友元
  3. 将ui的链接属性设置为外部的,这样可以跨文件访问
  4. 还有更多有待发掘

为什么要使用指针来指向UI中的类的对象

  1. 指针的理解
    • 指针是一个变量,它存储的是另一个变量的内存地址。通过指针,我们可以间接地访问和操作该内存地址中的数据。
    • 在C++中,指针特别重要,因为它允许我们进行动态内存分配、函数参数传递、返回多个值等操作。
    • 指针也提供了对内存的直接访问,这意味着使用指针时需要注意内存管理和安全性,以避免诸如内存泄漏、野指针等问题。
    • 指针相当于一个门,在不暴露对象内部实现的前提下我们就可以操纵对象
    • 指针的使用可以减少编译中的依赖,如果指向的对象改动,本文件也无需重新编译,因为指针实质上就是一个与位数机器字长相同的内存编号

2.使用指针来管理UI对象

在Qt中,UI通常是通过Qt Designer设计的,然后转换为.ui文件。这个文件可以在运行时通过QUiLoader类加载,或者通过uic工具转换为C++代码。通常,这些由.ui文件生成的类会包含大量的UI元素作为类的成员变量。

为了提高代码的灵活性和可重用性,Qt开发者经常将这些UI元素作为指针成员变量来管理。这样做的好处包括:

  • 延迟初始化:UI元素可以在需要时才创建,而不是在对象构造时立即创建。
  • 动态内存管理:允许动态地分配和释放UI元素的内存。
  • 可替换性:可以更容易地替换UI元素,因为它们是通过指针引用的。

例如,一个典型的Qt窗口类可能包含指向按钮、文本框等UI元素的指针:

class MyWindow : public QMainWindow {
Q_OBJECT
public:
MyWindow(QWidget *parent = nullptr);
~MyWindow();
private:
QPushButton *myButton;
QLineEdit *myLineEdit;
// ... 其他UI元素
};

在这个例子中,myButtonmyLineEdit是指向QPushButtonQLineEdit对象的指针,这些对象通常在MyWindow的构造函数中创建,并在析构函数中删除。

3.PIMPL(Pointer to Implementation)设计模式

PIMPL,也称为Opaque Pointer或Cheshire Cat技术,是一种隐藏类的实现细节的设计模式。在Qt中,PIMPL模式通常用于减少编译依赖,隐藏实现细节,以及提高二进制兼容性。

使用PIMPL模式,类的实现细节被放在一个单独的实现类(通常称为Impl)中,而公共接口类只包含一个指向实现类的私有指针。这样,当实现细节发生变化时,只要公共接口和指针类型保持不变,客户端代码就不需要重新编译。

在Qt中,PIMPL模式通常用于大型类或库,以减少编译时间和提高代码的稳定性。例如:

// MyWidget.h
class MyWidgetImpl; // 前置声明
class MyWidget {
public:
MyWidget();
~MyWidget();
void somePublicFunction();
private:
MyWidgetImpl *d; // 指向实现的指针
};
// MyWidget.cpp
#include "MyWidget.h"
#include "MyWidgetImpl.h" // 包含实现类的定义
MyWidget::MyWidget() : d(new MyWidgetImpl) {
// 初始化实现对象
}
MyWidget::~MyWidget() {
delete d; // 释放实现对象
}
void MyWidget::somePublicFunction() {
// 调用实现类的方法
d->someImplementationFunction();
}

在这个例子中,MyWidget类只包含一个指向MyWidgetImpl类的私有指针d。所有MyWidget的公共接口函数都通过d指针来调用MyWidgetImpl中的实现函数。这样,MyWidget的客户端代码不需要知道或包含MyWidgetImpl的定义,从而减少了编译依赖。

在Qt的UI编程中,PIMPL模式不常用于UI对象本身,因为UI对象通常是通过Qt Designer和.ui文件直接生成的。然而,PIMPL模式可以用于封装复杂的业务逻辑或数据模型,这些逻辑或模型与UI对象交互,但不需要暴露给UI对象的使用者。

posted @   李小飞11  阅读(751)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示