当前位置: 首页 > news >正文

【Qt】项目的创建和各个控件的使用

一、项目的创建

🔍然后点击新建项目。

📖注意:路径不要带有中文,不然运行不了代码。

📖qmake是一个构建工具,在 Qt 写的程序,设计的到一系列的 "元编程"  技术,什么是元编程技术?就是说 Qt 框架会在编译的时候自动调用一系列的生成工具,当然是基于你写的代码生成一系列的代码,最终编译的代码也是这些最后生成的这些代码。我们经常使用的qmake。

1.qmake是老牌的 Qt 工具

2.CMake 并非 Qt 专属,很多的开源项目也会使用。

3.Qbs 是新一代的 Qt 构建工具(实际上用的人非常少)

使用 Qt Creator 创建的项目会自动生成一些代码出来,生成的代码就包含一个类,此处就是要选择这个自动生成的类的父类是谁。我们选择的是 QWidget。

1.QMainWindows 完整的应用程序窗口(包含菜单栏、工具栏、状态栏......)

2.QWidget 表示一个控件(窗口上的一个具体的元素,输入栏,按钮,下拉框,单选按钮,复选按钮.......)

3.QDialog 表示一个对话框。

注意:form file 非常关键,在 Qt 中创建图形化界面的程序主要有两种:

1)直接通过C++代码的方式来创建界面。

2)通过 form file,以图形化界面的方式来生成界面。这时候就可以使用 Qt Designer 或者直接使用Qt Creator 来编辑这个 ui 文件从而以图形化的方式来快速方便的生成图形化界面。

✍从这个名字就知道这是一个翻译性文件,我们可以在这里选择翻译文件(对应的语言),语言和国际化有关,这里不过多关注。

✍选择基于哪个编译器的 Qt SDK 来构建后续代码。

二、各个文件代码解释

注意:exec是让程序执行起来。它和 Linux 的 exec 不一样。

✍当我们双击 ui 文件时,此时Qt Creator 就会自动调用 Qt Designer ,打开 ui 文件(图形化界面编辑器)

三、Hello world 的实现

1)拖拽控件实现

2)代码实现

#include "widget.h"
#include "ui_widget.h"
#include<QLabel>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QLabel* label = new QLabel(this);label->setText("Hello world!");
}Widget::~Widget()
{delete ui;
}

注意:Qlabel(this) 中的 this 是给当前的label对象指定一个父对象。我们既然new了一个对象出来,为什么不手动释放呢?这样不就造成内存泄漏了吗?答案是不会因为label会在合适的时候被析构释放,类似于C++的智能指针,之所以能被释放,我们把对象挂到了对象树上,主要靠 this 实现。当我们的 label 定义在栈上的时候,我们是需要手动释放的。

✍注意:创建的QLabel默认是在左上角。在前端开发(网页开发)也涉及到类似的对象树(DOM),它的本质也是一个树状结构(N叉树),通过树形结构把界面上的各种元素组织起来。

小贴士:使用快捷键:F4可以快速切换对应的头文件和.cpp文件。写完函数的声明之后可以按下 alt + enter 就可以在对应的 .cpp文件添加函数的定义了。

✍补充知识:我们在Qt中输入的汉字占几个字节?由于编码的不同,一个汉字占的空间也不一样,目前表示汉字字符集主要有两种方式:

1、GBK(中国大陆)使用2个字节表示一个汉字。例如:Windows简体中文版默认是GBK

2、UTF-8/UTF8,变长编码,表示一个符号使用的字节数有变化,范围(2,4);一般来说UTF8默认是一个3个字节。例如:Linux默认使用的UTF8。


我们在Qt Creator 中使用编写代码时,如果 std::cout 出现乱码,代表着编码出现了问题;什么是乱码呢?

如果你的字符串本身是 UTF8 编码的,都是终端控制台是按照 GBK 来解析显示的,此时就会出现乱码,解决编码问题直接到出现编码的文件打开对应的文档,改变编码方式,如果出现UTF8声明这个文件就是UTF8编码,出现 ANSI 就是GBK编码。但是当前主流的表示中文编码方式是UTF8,使用这里不好改;所以我们使用 Qt 的QString,它可以帮我们自动处理编码问题,当然也提供了专门的日志工具也能处理编码问题。例如:qDebug()工具;

#include "widget.h"
#include "ui_widget.h"
#include<QLabel>
#include<QDebug>
#include<iostream>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QLabel* label = new QLabel(this);label->setText("Hello world!");
}Widget::~Widget()
{//std::cout << "析构" << std::endl;qDebug() << "析构";delete ui;
}

注意:QDebug 文件是 Qt 中的类,但是又不直接使用这个类;qDebug()一个宏,这个宏封装了QDebug 对象,直接使用 qDebug()可以当做 cout 使用。使用qDebug()输出信息,他只能在开发阶段(debug版本)能看到,发给用户的 release 版本用户是看不到的。

3)使用编辑框实现

♐也可以使用代码实现:

#include "widget.h"
#include "ui_widget.h"
#include<QLabel>
#include<QDebug>
#include<iostream>
#include<QLineEdit>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QLabel* label = new QLabel(this);label->setText("Hello world!");QLineEdit* edit = new QLineEdit(this);edit->setText("拜拜了您勒!!");}Widget::~Widget()
{//std::cout << "析构" << std::endl;qDebug() << "析构";delete ui;
}

♐也可以通过按钮来实现:

Push Button 是一个按钮,既然是按钮就可以单击,这就说到 Qt 中的信号槽机制,什么是信号槽呢?信号槽的本质是给一个按钮的点击操作关联上一个处理函数,当用户点击的时就会执行这个处理函数,这个处理函数就是 connect ,他是QObject 这个类提供的静态函数,它的作用就是连接信号和槽,但是他和 TCP 的建立没有任何关系。

信号的接收和处理

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void handleClick();//声明private:Ui::Widget *ui;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include<QLabel>
#include<QDebug>
#include<iostream>
#include<QLineEdit>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
//    QLabel* label = new QLabel(this);
//    label->setText("Hello world!");//    QLineEdit* edit = new QLineEdit(this);
//    edit->setText("拜拜了您勒!!");connect(ui->pushButton,&QPushButton::clicked,this,&Widget::handleClick);//从界面文件中访问到了按钮,记住一定要拖拽按钮之后再写代码//第二参数就是用户点击这个按钮之后触发处理函数//第一个参数是谁发出的信号//第二个参数发出了个啥信号,点击按钮的时候就会自动触发这个信号//第三个参数,谁来处理这个参数//第四个参数,具体怎么处理}Widget::~Widget()
{//std::cout << "析构" << std::endl;qDebug() << "析构";delete ui;
}void Widget::handleClick()
{//当按钮被点击之后,就把按钮中的文本进行切换if(ui->pushButton->text() == QString("hello world"))ui->pushButton->setText("hello QT");elseui->pushButton->setText("hello world");
}

注意:ui -> pushButton 访问到 form file(ui 文件)中创建的控件。在Qt Designer 中创建一个控件的时候,此时就会给这个控件分配一个 ojectName 属性,这个属性的值(可以修改),要求是界面中得是唯一的(不能重复);qmake 在预处理 .ui 文件时就会根据这里的 objectName 生成对应的C++ 代码,C++代码中该 QPushButton 对象的变量名字就是这里的 objectName,该变量是 ui 属性中的成员变量。

♐纯代码实现按钮:

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include<QPushButton>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void handleClick();private:Ui::Widget *ui;QPushButton* myButton;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);myButton = new QPushButton(this);myButton->setText("hello world!");connect(myButton,&QPushButton::clicked,this,&Widget::handleClick);
}Widget::~Widget()
{delete ui;
}void Widget::handleClick()
{if(myButton->text() == QString("hello world")){myButton->setText("hello qt");}else{myButton->setText("hello world");}
}

四、Qt 中的命名规范和快捷键

1)命名规范

        在C++代码中我们一般使用蛇形命名法,什么是蛇形命名法?例如:student_count,priority_queue.......

        在Qt 中我们使用的是驼峰命名法,例如:studentCount,QWidget......首字母是大写的是大驼峰,一般是给变量和函数命名,首字母是小写的是小驼峰,一般是给类命名。

2)快捷键

注释:ctrl+/
运行:ctrl+R
编译:ctrl+B
字体缩放:ctrl+鼠标滑轮
查找:ctrl+F
整行移动:ctrl +shift+向上的箭头或向下的箭头
帮助文档:F1
自动对齐:ctrl+i
同名之间的.h和.cpp的切换:F4
生成函数声明的对应定义:alt +enter

五、帮助文档

打开帮助文档有三种方式.实际编程中使用哪种都可以。

1、光标放到要查询的类名/方法名上,直接按F1

2、Qt Creator 左侧边栏中直接用鼠标单击"帮助"按钮:

六、Qt 窗口坐标体系

坐标体系:以左上角为原点(0,0),X向右增加,Y向下增加。

坐标系的原点(0,0)是窗口的或者屏幕的左上角,因为给 Qt 的某个控件设置位置的时候就需要指定坐标,对于这个控件来说坐标原点就是相对于父窗口/父控件的。

#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* button = new QPushButton(this);button->setText("按钮");
}Widget::~Widget()
{delete ui;
}

注意:除了红色箭头的部分是 Widget 的范围,其他的是系统自动生成的,不在 Widget 范围之内。

♐使用 move 设置按钮的位置:

#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* button = new QPushButton(this);button->setText("按钮");button->move(500,400);//单位是像素
}Widget::~Widget()
{delete ui;
}

♐设置 Widget 的位置:

#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* button = new QPushButton(this);button->setText("按钮");button->move(500,500);//控件的位置this->move(1000,200);//设置Widget的位置
}Widget::~Widget()
{delete ui;
}

七、信号和槽

       🔍 Linux  信号 signal 是系统内部的通知机制,是进程之间的通信方式。

        那么我们可以知道:

        1)信号源:谁发的信号。

        2)信号的类型:哪种类别的信号。

        3)信号的处理方式:注册信号处理函数,在信号被触发的时候自动执行。

        显然Qt 中的信号和 Linux  中的信号虽然不是一样的概念但是确实有相似之处。

       🔍 在 Qt 中也是涉及到三个元素:

        信号源:是哪个控件发出从信号。

        信号的类型:用户进行不同的操作,就可能触发不同的信号。

        信号的处理方式:槽(slot) 函数,Qt 中使用 connect 这样的函数把一个信号和槽关联起来,只要用户触发信号 Qt 就会自动执行槽函数。槽函数本质上是一种回调函数(callback)


        在 Qt 中,用户和控件的每次交互过程称为一个事件。比如 "用户点击按钮" 是一个事件,“用户关闭窗口“ 也是一个事件。每个事件都会发出一个信号,例如用户点击按钮会发出"按钮被点击”的信号,用户关闭窗口会发出“窗口被关闭”的信号。

        Qt 中的所有控件都具有接收信号的能力,一个控件还可以接收多个不同的信号。对于接收到的每个信号,控件都会做出相应的响应动作。例如:按钮所在的窗口接收到 "按钮被点击" 的信号后,会做出"关闭自己"的响应动作;再比如输入框自己接收到 "输入框被点击" 的信号后,会做出 "显示闪烁的光标,等待用户输入数据" 的响应动作。在 Qt 中,对信号做出的响应动作就称之为槽。

        信号和槽是 Qt 特有的消息传输机制,它能将相互独立的控件关联起来。比如:"按钮" 和" 窗口" 本身是两个独立的控件,点击 "按钮" 并不会对 "窗口" 造成任何影响。通过信号和槽机制,可以将 "按钮" 和 "窗口" 关联起来,实现”点击按钮会使窗口关闭”的效果。

🔍信号的本质:

        信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时Qt对应的窗口类会发出某个信号,以此对用户的操作做出反应。因此,信号的本质就是事件。如:

1)按钮单击、双击
2)窗囗刷新鼠标移动、鼠标按下、鼠标释放
3)键盘输入

📖那么在Qt中信号是通过什么形式呈现给使用者的呢?

1)我们对哪个窗口进行操作,哪个窗口就可以捕捉到这些被触发的事件。

2)对于使用者来说触发了一个事件我们就可以得到 Qt 框架给我们发出的某个特定信号。

3)信号的呈现形式就是函数,也就是说某个事件产生了,Qt框架就会调用某个对应的信号函数,通知使用者。

在Qt中信号的发出者是某个实例化的类对象。

槽的本质:
📖 槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的C++函数是一样的,可以定义在类的任何位置(public、protected或private),可以具有任何参数,可以被重载,也可以被直接调用(但是不能有默认参数)。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。

🔍说明:

        (1)信号和槽机制底层是通过函数间的相互调用实现的。每个信号都可以用函数来表示,称为信号数;每个槽也可以用函数表示,称为槽函数。例如:"按钮被按下”这个信号可以用clicked()函数表示,“窗口关闭”这个槽可以用close()函数表示,假如使用信号和槽机制一实现:"点击按钮会关闭窗口”的功能,其实就是clicked()函数调用close()函数的效果。
(2)信号函数和槽函数通常位于某个类中,和普通的成员函数相比,它们的特别之处在于:

        信号函数用 signals 关键字修饰,槽函数用 public slots、protected slots 或者 private slots 修饰。signals和slots 是 Qt 在 C++ 的基础上扩展的关键字,专门用来指明信号函数和槽函数;

        信号函数只需要声明,不需要定义(实现),而槽函数需要定义(实现)。

1、信号和槽的使用

        Qt 中提供的这些类,本身存在一定的继承关系,例如:QWedget 继承 QObject ,QPushbutton 继承 QWedget 。

       🔍 connect 的原型:

// 通用原型(适用于任意信号-槽关联)
template <typename Func1, typename Func2>
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object* sender,  // 发送者对象(指针)Func1 signal,                                                      // 发送者的信号(函数指针)const typename QtPrivate::FunctionPointer<Func2>::Object* receiver,// 接收者对象(指针,可 nullptr)Func2 slot,                                                        // 接收者的槽/ Lambda(函数指针)Qt::ConnectionType type = Qt::AutoConnection                       // 连接类型(默认自动选择)
);

🔍实例:点击按钮,Widget 窗口关闭:

#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* button = new QPushButton(this);button->setText("关闭");button->move(200,200);//控件的位置connect(button,&QPushButton::clicked,this,&Widget::close);//click 是一个 slot 函数,作用是调用是时候相当于点击了一下按钮;//clicked 过去分词,点完了之后,才是要触发的点击信号。//close 是 QWidget 内置的槽函数,Widget 继承 QWidget,也就继承了父亲的槽函数//close 功能是关闭当前的窗口/控件
}Widget::~Widget()
{delete ui;
}

connect 要求:类型如果是QPushButton* 此时第二个参数必须是 QPushButton 内置的信号(父类的信号),不能是一个其他的类例如:QLineEdit 信号。

        🔍各位由于信号和槽的知识点篇幅过大,所以后文留到下篇的博客详写!

               🍁🍁请各位道友,敬请期待下文,完!!


文章转载自:

http://fuQfusVo.djbhz.cn
http://MmSNjd57.djbhz.cn
http://jga7VjGa.djbhz.cn
http://3fZ60NOB.djbhz.cn
http://RxHb9H9n.djbhz.cn
http://Hd0rkFWW.djbhz.cn
http://l6bP0tCv.djbhz.cn
http://X0TuvthM.djbhz.cn
http://pn4ctpfX.djbhz.cn
http://vepgUcs2.djbhz.cn
http://gjTcxK3s.djbhz.cn
http://eizfRtgM.djbhz.cn
http://SmSFExxl.djbhz.cn
http://stkClQSw.djbhz.cn
http://ITZ4ac9q.djbhz.cn
http://qWwI0uXB.djbhz.cn
http://HRQzmaQQ.djbhz.cn
http://DpFunrEX.djbhz.cn
http://tuMQ0NQP.djbhz.cn
http://QF4j6tga.djbhz.cn
http://biolw8Fz.djbhz.cn
http://rPoUG1x9.djbhz.cn
http://pqe5VEjR.djbhz.cn
http://87gkqflj.djbhz.cn
http://a3blm8ln.djbhz.cn
http://n68XfzEK.djbhz.cn
http://kzpM7gd9.djbhz.cn
http://vjW9IH1l.djbhz.cn
http://Baa1Br0G.djbhz.cn
http://BG3HLWtd.djbhz.cn
http://www.dtcms.com/a/371698.html

相关文章:

  • Python高级技巧(七):装饰器
  • C#有人IO模块USR-IO808的完整指南
  • Apache Dubbo学习笔记-使用Dubbo发布、调用服务
  • CTFshow系列——PHP特性Web97-
  • Photoshop - Photoshop 创建图层蒙版
  • DevOps实战(3) - 使用Arbess+GitLab+Hadess实现Java项目自动化部署
  • Python从入门到精通_00_初识python
  • LabVIEW 与 PLC 通讯
  • 项目介绍:图像分类项目的最小可用骨架--代码细节讲解
  • 【.Net技术栈梳理】01-核心框架与运行时(CLR与GC)
  • 简述ajax、node.js、webpack、git
  • Java安全体系深度研究:技术演进与攻防实践
  • Drupal XSS漏洞复现:原理详解+环境搭建+渗透实践(CVE-2019-6341)
  • Mybatis常见问题
  • Python基础语法篇:布尔值是什么?True 和 False 的实际用途
  • FMI(Functional Mock-up Interface,功能模型接口)
  • macOS中设置环境变量的各文件及作用域
  • Python+DRVT 从外部调用 Revit:批量创建楼板
  • 课前准备--解码乳腺癌进展:单细胞基因组与转录组的联合分析
  • 机器学习中的损失函数是什么
  • P5019 [NOIP 2018 提高组] 铺设道路
  • 【 苍穹外卖 | Day2】
  • 简单的说一说前端开发语言React
  • 跨域解决方案——CORS学习了解
  • leetcode 1304. 和为零的 N 个不同整数 简单
  • LeetCode 面试经典 150 题:合并两个有序数组(双指针解法详解)
  • Nestjs框架: 基于策略的权限控制(ACL)与数据权限设计
  • Go语言实战案例-实现简易定时提醒程序
  • 如何在项目中使用 Claude 记忆库系统(二开场景指南)
  • Matlab Simulink中的一些记录