qt学习——基本使用、对象树、按钮、信号与槽

news/2024/11/29 3:53:07/

初识qt

  • **qt**
    • **qt命名规范以及相关快捷键的使用**
    • **QPushButton**
    • **对象树**
    • **点击按钮关闭窗口**
    • **信号和槽**
    • **标准的信号和槽**
    • **自定义信号和槽**
    • **带参数的自定义信号和槽传参以及函数的二义性问题**

qt

qt命名规范以及相关快捷键的使用

优点:Qt相对于C++,有一个很好的机制是,他有自己的一套内存回收机制,在一定程度上简化了内存回收,不需要每每new申请之后总要想着delete了
widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>//包含头文件QWidget 窗口类class Widget : public QWidget
{Q_OBJECT //Q_OBJECT宏,允许类中使用信号和槽的机制public:Widget(QWidget *parent = nullptr);//构造函数~Widget();//析构函数
};
#endif // WIDGET_H

main.cpp

#include "mywidget.h"#include <QApplication>//包含一个应用程序类的头文件//argc命令行变量的数量 argv命令行变量的数组//应用程序对象,在Qt中,应用程序对象有且仅有一个
int main(int argc, char *argv[])
{QApplication a(argc, argv);//窗口对象 myWidget父类 ->QwidgetmyWidget w;//窗口对象默认不会显示,必须要调用show方法显示窗口w.show();//让应用程序对象 进入消息循环机制//让代码阻塞到这行return a.exec();
}

项目的代码解释
在这里插入图片描述
widget.cpp

#include "widget.h"//命名规范
//类名 首字母大写,单词和单词之间首字母大写
//函数名 变量名称 首字母小写,单词和单词之间首字母大写
//快捷键
//注释ctrl +l
//运行ctrl + r
//编译ctrl + b
//字体缩放ctrl +鼠标滚轮
//查找 ctrl+f
//整行移动 ctrl+shift+上键或者下键
//帮助文档 F1
//自动对齐 ctrl+i;
//同名直接的.h和.cpp切换 F4
//帮助文档 第一种方式F1 
//第二种 左侧按钮
//第三种 路径方式Widget::Widget(QWidget *parent): QWidget(parent)//初始化列表
{
}Widget::~Widget()
{
}

QPushButton

QPushButton是Qt框架中的一个类,用于创建一个可点击的按钮控件。可以设置按钮的文本、图标、样式等属性,以及连接按钮的点击事件到相应的槽函数。常用于创建用户界面中的交互按钮。
用到类的时候要将模块加入到项目里面
在Qt中,show()是QWidget类的一个成员函数,用于显示窗口小部件。当调用show()函数时,窗口小部件将被显示在屏幕上
在Qt中,QPushButton类确实有一个setParent()函数,可以用于设置按钮的父对象
与上一个一样,前面的头文件和main函数不变
父子关系:
默认情况下.按钮没有认干爹的情况,是顶层窗口
想要按钮显示在窗口上,就要跟窗口构造父子关系
1、setParent
2、构造函数传参

#include "widget.h"
#include <QPushButton>//按钮控件的头文件//命名规范
//类名 首字母大写,单词和单词之间首字母大写
//函数名 变量名称 首字母小写,单词和单词之间首字母大写
//快捷键
//注释ctrl +l
//运行ctrl + r
//编译ctrl + b
//字体缩放ctrl +鼠标滚轮
//查找 ctrl+f
//整行移动 ctrl+shift+上键或者下键
//帮助文档 F1
//自动对齐 ctrl+i;
//同名直接的.h和.cpp切换 F4
//帮助文档 第一种方式F1
//第二种 左侧按钮
//第三种 路径方式Widget::Widget(QWidget *parent): QWidget(parent)//初始化列表
{//创建一个按钮QPushButton * btn=new QPushButton;//btn->show();//show的默认是按照顶层方式弹出的控件//让btn对象 依赖在Widget窗口中btn->setParent(this);//显示文本btn->setText("第一个按钮");//创建第二个按钮  按照控件的大小来创建窗口QPushButton * btn2=new QPushButton("第二个按钮",this);//移动btn2按钮//第二种方式传入的长和宽btn2->move(200,200);按钮可不可以 重新制定大小 可以//btn->resize(50,50);//重置窗口的大小//传入的是长和宽resize(600,400);//设置固定的窗口大小setFixedSize(600,400);//设置窗口的标题setWindowTitle("第一个窗口");
}Widget::~Widget()
{
}

第一个窗口
在这里插入图片描述

#include "widget.h"
#include <QPushButton>
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;//添加按钮
//    QPushButton btn;
//    btn.setText("按钮1");
//    //将按钮显示出来
//    btn.show();//默认情况下没有建立父子关系,显示的都是顶层窗口//要建立父子关系//1、setParent函数QPushButton btn;btn.setText("按钮1");btn.setParent(&w);//传入的是对象指针//2、构造函数传参QPushButton btn2("按钮2",&w);//移动一下按钮位置btn2.move(100,100);btn2.resize(400,400);//按钮3,和按钮2建立父子关系QPushButton btn3("按钮3",&btn2);btn3.move(100,100);//设置窗口标题w.setWindowTitle("hello world");//设置窗口的固定大小//w.setFixedSize(800,600);//同时设置窗口的位置和大小//move和resize的集合体w.setGeometry(400,400,500,500);w.show();//顶层窗口移动到200 100//是以父窗口的左上角为0,0//以向左的方向为x的正方向//以向右的方向为y的正方向//顶层窗口是以屏幕左上角为0,0//w.move(200,100);return a.exec();
}

在这里插入图片描述

对象树

对象树之间的父子关系是对象之间的父子关系 不是类直接的父子关系
父对象在释放析构函数的时候还会释放子对象
每个窗口都有child列表

在Qt中,对象树是一种管理对象生命周期的机制。当一个对象被添加到对象树中时,它的父对象会负责管理它的内存分配和释放。这意味着,当父对象被销毁时,它的所有子对象也会被自动销毁,从而避免了内存泄漏和悬挂指针等问题。
在创建一个新的Qt对象时,我们通常需要将它添加到对象树中,以便它能够被正确地管理。这可以通过将它的父对象作为参数传递给它的构造函数来实现。这样,当父对象被销毁时,它的子对象也会被自动销毁,从而保证了对象的正确释放。
总之,传入对象树是Qt中一种重要的管理对象生命周期的机制,可以有效地避免内存泄漏和悬挂指针等问题。

在qt中创建对象的时候会提供一个Parent对象指针,下面来解释这个parent到底是干什么的
QObject是以对象树的形式组织起来的。
当你创建一个QObject对象时,会看到QObject的构造函数接收一个
QObject指针作为参数,这个参数就是 parent,也就是父对象指针。
这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children()列表。
当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类)
这种机制在GUI程序设计中相当有用。例如,一个按钮有一个QShoxtcut(快捷键)对象作为其子子对象。
当我们删除按钮的时候,这个快捷键理应被删除。这是合理的。

在这里插入图片描述
构造顺序从上到下,析构顺序从下到上
在这里插入图片描述

点击按钮关闭窗口

要四个元素:按钮、被点击、窗口、关闭
建立四者的关系
*QPushButton btn = new QPushButton(“按钮1”,this);为啥这段要传入this指针
在Qt中,每个QWidget派生类都有一个父对象,父对象负责管理其子对象的生命周期。在这个例子中,QPushButton的父对象是当前的QWidget,也就是说,当当前的QWidget被销毁时,它的所有子对象也会被自动销毁。因此,将当前QWidget的指针作为QPushButton的父对象传入,可以确保QPushButton的生命周期与当前QWidget的生命周期相同,避免了内存泄漏的问题。
*Widget::Widget(QWidget parent)
: QWidget(parent)这段代码什么意思
这段代码是一个构造函数,用于创建一个QWidget对象。其中,parent是QWidget对象的父对象,表示该QWidget对象是由哪个QWidget对象创建的。如果没有父对象,可以将parent设置为nullptr或省略。

#include "widget.h"
#include<QPushButton>Widget::Widget(QWidget *parent): QWidget(parent)
{QPushButton *btn = new QPushButton("按钮1",this);//关闭 this->close//建立四者的关系connect(btn,&QPushButton::clicked,this,&Widget::close);}Widget::~Widget()
{
}

信号和槽

信号和槽机制
信号:各种事件
槽:响应信号的动作
当某个事件发生后,如某个按钮被点击了一下,它就会发出一个被点击的信号(signal)
某个对象接收到这个信号之后,就会做一些相关的处理动作(称为槽slot)。
但是Qt对象不会无故收到某个信号,要想让一个对象收到另一个对象发出的信号,这时候需要建立连接(connect)

*QPushButton btn = new QPushButton(“按钮1”,this);
connect(btn,&QPushButton::clicked,this,&Widget::close);
这两句代码什么意思

这两句代码是在Qt框架下编写的,作用是创建一个名为"按钮1"的QPushButton对象,并将其添加到当前窗口中(this表示当前窗口),然后将该按钮的clicked信号与当前窗口的close槽函数连接起来。也就是说,当用户点击该按钮时,会触发clicked信号,从而执行当前窗口的close槽函数,关闭当前窗口。
具体来说,&QPushButton::clicked是一个信号,表示按钮被点击时会发出该信号;this是当前窗口的指针,表示将该信号连接到当前窗口上;&Widget::close是一个槽函数,表示当按钮被点击时会执行当前窗口的close槽函数,从而关闭当前窗口。
使用了函数指针。这里,我们将btn的clicked信号与Widget对象的close槽函数连接起来,使用了&QPushButton::clicked和&Widget::close来分别表示这两个函数的指针。

#include "widget.h"
#include<QPushButton>Widget::Widget(QWidget *parent): QWidget(parent)
{QPushButton *btn = new QPushButton("按钮1",this);//关闭 this->close//按钮//被点击//窗口//关闭//建立四者的关系connect(btn,&QPushButton::clicked,this,&Widget::close);//信号发送者//信号//信号接收者//槽:信号的处理动作//通过connect建立四者的关系//connect(信号发送者,信号,信号接收者,槽)
}Widget::~Widget()
{
}

标准的信号和槽

具体有哪些:自己查
标准的槽
在这里插入图片描述
标准的信号
在这里插入图片描述
继承过来看父类

在这里插入图片描述

#include "widget.h"
#include<QPushButton>Widget::Widget(QWidget *parent): QWidget(parent)
{QPushButton *btn = new QPushButton("按钮1",this);//关闭 this->close//按钮//被点击//窗口//关闭//建立四者的关系//关闭//connect(btn,&QPushButton::clicked,this,&Widget::close);//最大化//connect(btn,&QPushButton::clicked,this,&Widget::showMaximized);//最小化connect(btn,&QPushButton::clicked,this,&Widget::showMinimized);//隐藏  但是在运行  任务管理器可以结束进程connect(btn,&QPushButton::clicked,this,&Widget::hide);//信号发送者//信号//信号接收者//槽:信号的处理动作//通过connect建立四者的关系//connect(信号发送者,信号,信号接收者,槽)
}Widget::~Widget()
{
}

指针指向函数时,可以不加&符号,因为函数名本身就代表了函数的地址。
例如:

void func() {// do something
}int main() {void (*p)() = func; // 不加&符号p(); // 调用函数return 0;
}

在上面的代码中,p 是一个指向函数的指针,它直接赋值为 func,不需要加上 & 符号
在这里插入图片描述

自定义信号和槽

在这里插入图片描述
在这里插入图片描述
从上到下依次为

#ifndef STUDENT_H
#define STUDENT_H#include <QObject>class Student : public QObject
{Q_OBJECT
public:explicit Student(QObject *parent = nullptr);signals:public slots://学生请吃饭void treat();
};#endif // STUDENT_H
#ifndef TEACHER_H
#define TEACHER_H#include <QObject>class Teacher : public QObject
{Q_OBJECT
public:explicit Teacher(QObject *parent = nullptr);signals:
void hungry();public slots:};#endif // TEACHER_H
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "student.h"
#include "teacher.h"class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void classIsOver();private:Teacher *pTeacher;Student *pStudent;
};
#endif // WIDGET_H
#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}
#include "student.h"
#include <QDebug>Student::Student(QObject *parent) : QObject(parent)
{}void Student::treat()
{qDebug()<<"Student treat teacher";
}
#include "teacher.h"Teacher::Teacher(QObject *parent) : QObject(parent)
{}
#include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent)
{//new的时候要加入对象树//老师和学生的两个对象创建pTeacher=new Teacher(this);pStudent=new Student(this);//建立连接connect(pTeacher,&Teacher::hungry,pStudent,&Student::treat);//下课了this->classIsOver();
}void Widget::classIsOver()
{//触发老师饿了的信号emit pTeacher->hungry();
}Widget::~Widget()
{
}

在这里插入图片描述

带参数的自定义信号和槽传参以及函数的二义性问题

在上面的场景再引入
在这里插入图片描述
void (Teacher::*teacher_qString)(QString)=&Teacher::hungry;啥意思
这行代码定义了一个指向 Teacher 类的成员函数的指针,该成员函数的参数为 QString 类型,函数名为 hungry。具体来说,Teacher::*teacher_qString 表示指向 Teacher 类的成员函数指针,QString 表示该成员函数的参数类型,&Teacher::hungry 表示该成员函数的地址。这个指针可以用来调用 Teacher 类的成员函数 hungry
函数重载是指在同一个作用域内定义了多个同名函数,但是它们的参数类型、个数或顺序不同。在调用这些同名函数时,编译器需要根据传入的参数类型、个数或顺序来确定调用哪一个函数。
使用函数指针可以解决函数重载问题,是因为函数指针是一个指向函数的指针变量,它指向的是函数的入口地址,而不是函数本身。因此,不同的函数可以有不同的入口地址,即使它们的函数名相同。通过定义不同的函数指针类型,可以指向不同的函数,从而实现函数重载的效果。
例如,假设有两个同名函数 foo,一个参数类型为 int,另一个参数类型为 float,可以定义两个不同的函数指针类型,分别指向这两个函数:
void (*foo_int)(int);
void (*foo_float)(float);
然后,根据需要,可以将不同的函数指针指向不同的函数,从而实现函数重载的效果:
void foo1(int x) { … }
void foo2(float x) { … }
foo_int = foo1;
foo_float = foo2;
foo_int(1); // 调用 foo1
foo_float(1.0); // 调用 foo2
在这里插入图片描述
student.h

#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>class Student : public QObject
{Q_OBJECT
public:explicit Student(QObject *parent = nullptr);signals:public slots://学生请吃饭void treat();void treat(QString what);
};#endif // STUDENT_H

teacher.h

#ifndef TEACHER_H
#define TEACHER_H#include <QObject>class Teacher : public QObject
{Q_OBJECT
public:explicit Teacher(QObject *parent = nullptr);signals:
void hungry();
void hungry(QString what);public slots:};#endif // TEACHER_H

wight.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "student.h"
#include "teacher.h"class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void classIsOver();private:Teacher *pTeacher;Student *pStudent;
};
#endif // WIDGET_H

main.cpp

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

student.cpp

#include "student.h"
#include <QDebug>Student::Student(QObject *parent) : QObject(parent)
{}void Student::treat()
{qDebug()<<"Student treat teacher";
}void Student::treat(QString what)
{qDebug()<<"Student treat teacher"<<what;
}

teacher.cpp

#include "teacher.h"Teacher::Teacher(QObject *parent) : QObject(parent)
{}

wight.cpp

#include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent)
{//new的时候要加入对象树//老师和学生的两个对象创建pTeacher=new Teacher(this);pStudent=new Student(this);//建立连接//两个函数发生了重载//connect(pTeacher,&Teacher::hungry,pStudent,&Student::treat);//老师说要吃黄焖鸡,学生就请吃黄焖鸡//hungry里面多加入一个参数 Qstring类型//treat里面也需要传入一个参数 Qstring//因为函数发生了重载  所以要解决/** 1、使用函数指针赋值  让编译器挑选符合类型* 2、使用static_cast 强制转换,也是让编译器自动挑选符合类型的函数*///传入的是string类型void (Teacher::*teacher_qString)(QString)=&Teacher::hungry;void (Student::*student_qString)(QString)=&Student::treat;connect(pTeacher,teacher_qString,pStudent,student_qString);//使用static_cast来转换无参的函数connect(pTeacher,static_cast <void (Teacher::*)()>(&Teacher::hungry),pStudent,static_cast <void (Student::*)()>(&Student::treat));//下课了this->classIsOver();
}void Widget::classIsOver()
{//触发老师饿了的信号emit pTeacher->hungry();//带参数的信号发射emit pTeacher->hungry("黄焖鸡");
}Widget::~Widget()
{
}

这里会发生函数重载有二义性 解决方法:
* 1、使用函数指针赋值 让编译器挑选符合类型
* 2、使用static_cast 强制转换,也是让编译器自动挑选符合类型的函数**


http://www.ppmy.cn/news/360229.html

相关文章

上海清洁公司一览表

飞鸽物业管理有限公司 肇周路78弄13号 63285496 飞鄂装潢清洗有限公司 崂山东路571弄1号楼1 58359502 飞跃灯饰实业公司装潢 蔑竹路206号 63186345 保洁清洗有限公司 中山西路1350号9号别 62084247 地铁清洁工程有限 梅园路58号 33030539 大辉保洁有限公司 世纪大道1500号827 2…

7. WebGPU 是如何工作的

让我们通过JavaScript 来模拟WebGPU的实现&#xff0c; 来尝试解释 GPU如何使用顶点着色器和片段着色器 。这样会对对真正发生的事情有一个直观的感受。 如果你熟悉 Array.map&#xff0c;稍微认真思考一下&#xff0c;就可以了解这两种不同类型的着色器函数是如何工作的。使用…

警惕超声波工艺对晶振造成损伤

超声波技术被广泛应用于工业生产中&#xff0c;常见的超声波工艺有&#xff1a;超声波清洗工艺、焊接工艺。 使用该两种工艺时&#xff0c;超声波仪器通常以20KHz至60KHz的频率运行。 清洗工艺是指清除工件表面上液体或固体的污染物&#xff1b;而焊接工艺中&#xff0c;高频机…

JavaWeb笔记(二)

数据库基础 数据库是学习JavaWeb的一个前置&#xff0c;只有了解了数据库的操作和使用&#xff0c;我们才能更好地组织和管理网站应用产生的数据。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IJ1neG69-1686619058026)(null)] 什么是数据库 数…

java设计模式之:组合模式

文章目录 1、什么是组合模式&#xff1f;2、组合模式定义3、组合模式通用代码实现4、组合模式优点5、组合模式应用场景 相信树形结构大家都知道&#xff0c;但是你是否知道用到了什么设计模式吗&#xff1f; 1、什么是组合模式&#xff1f; Compose objects into tree structu…

今天给大家分享VGA系列的教程【很适合刚学零基础学习】

今天给大家分享一下我们 VGA 的系列教程 内容包括&#xff1a;VGA显示原理及开发板VGA介绍、VGA显示颜色、VGA显示矩形、VGA显示图片、VGA显示圆、VGA显示颜色vivado工程创建和上板、VGA显示矩形vivado工程创建和上板、VGA显示圆vivado工程创建和上板、VGA显示图片vivado工程创…

英语学习电影场景

1、卡通 2、情景喜剧

推荐4款超简单的画平面图的软件

本篇文章将介绍 4 款目前热门的绘制平面图软件&#xff0c;包括即时设计、DRAW、Adobe PhotoShop 和 Adobe Illustrator。每一款软件的设计功能、易学性、性价比都不同&#xff0c;适用于不同的用户需求。其中&#xff0c;即时设计是一款新一代的协同设计工具&#xff0c;适用于…