目录
学习内容:
1. 常用类
1.1 信息调试类QDebug
1> 该类中使用qDebug()来完成信息的调试功能
2> 使用方式:
qDebug("%d", 520); //类似于printf
qDebug()<<"hello";//类似于cout
1.2 按钮类(QPushButton)
1> 该类提供了一个普通按钮
2> 该类的常用函数
//1、使用无参构造,构造一个按钮
//QPushButton btn1(this); //不能在栈区申请,否则会被刷新掉
QPushButton *btn1 = new QPushButton; //调用无参构造,构造一个按钮
//btn1->show(); //如果没有指定父组件,那么该组件就是游离的
btn1->setParent(this); //将自定义的界面当作按钮类的父组件
btn1->setText("支付"); //设置按钮文本内容
qDebug() << "btn1.size = "<<btn1->size(); //获取按钮尺寸
btn1->resize(80,40); //设置按钮大小
btn1->move(100,200); //移动按钮位置
btn1->setStyleSheet("background-color:skyblue; border-radius:10;"); //设置样式表
btn1->setIcon(QIcon("D:\\24061QT\\day1\\icon\\weixinzhifu.png")); //设置按钮图标
//2、构造按钮时,直接指定父组件
QPushButton *btn2 = new QPushButton(this);
btn2->setText("取消");
btn2->move(btn1->x()+btn1->width()+2, btn1->y()); //相对于btn1的位置进行定位
btn2->resize(btn1->size()); //设置按钮尺寸
btn2->setEnabled(false); //设置按钮不可用
//3、构造按钮时,指定父组件并且设置文本内容
QPushButton *btn3 = new QPushButton("确定", this);
btn3->resize(btn1->size()); //重置大小
btn3->move(btn2->x()+btn2->width()+2, btn2->y());
//4、构造按钮时,指定父组件并设置文本内容,并设置按钮图标
QPushButton *btn4 = new QPushButton(QIcon("D:\\24061QT\\day1\\icon\\wode.png"), "注册", this);
btn4->resize(btn1->size());
btn4->move(btn3->x()+btn3->width(), btn3->y());
1.3 行编辑器类(QLineEdit)
1> 该类提供了一个行编辑器,输入文本只在一行内展示
2> 所需头文件:#include
3> 常用函数:
QLineEdit *edit1 = new QLineEdit;
edit1->setParent(this); //指定父组件
edit1->resize(300, 30); //重新设置大小
edit1->move(lab1->x()+lab1->width()+2, lab1->y()); //移动位置
//2、使用有参构造完成构造一个行编辑器
QLineEdit *edit2 = new QLineEdit("密码", this);
edit2->resize(300, 30); //重新设置大小
edit2->move(lab2->x()+lab1->width()+2, lab2->y()); //移动位置
edit2->clear(); //清空内容
edit2->setPlaceholderText("密码"); //设置占位文本
edit2->setEchoMode(QLineEdit::Password); //设置回显模式
1.4 标签类(QLabel)
1> 该类提供的能够展示文本内容或者图片的容器
2> 所需头文件:#include
3> 常用函数
//1、使用无参构造完成构造一个标签
QLabel *lab1 = new QLabel;
lab1->setParent(this); //设置父组件
lab1->setText("账号:"); //设置文本内容
lab1->move(btn1->x(), btn1->y()-90); //设置坐标
//2、使用有参构造完成构造一个标签
QLabel *lab2 = new QLabel("密码:", this);
lab2->move(lab1->x(), lab1->y()+40);
//3、调用有有参构造,指定父组件,构造一个lab
QLabel *lab3 = new QLabel(this);
lab3->resize(500, 100);
lab3->setStyleSheet("background-color:pink;"); //设置样式表
//给标签设置动图
//创建一个movie对象
QMovie *movie = new QMovie("D:\\24061QT\\day1\\pictrue\\zz.gif");
//将动图对象放入到标签中
lab3->setMovie(movie);
//让动图动起来
movie->start();
//让标签内容自适应大小
lab3->setScaledContents(true);
//给标签设置静态图
lab1->resize(30,30);
lab1->setPixmap(QPixmap("D:\\24061QT\\day1\\pictrue\\userName.jpg"));
lab1->setScaledContents(true);
lab2->resize(30,30);
lab2->setPixmap(QPixmap("D:\\24061QT\\day1\\pictrue\\passwd.jpg"));
lab2->setScaledContents(true);
2. 对象树模型
2.1 对象树模型的概述
1> 在对象树模型中,子组件构造时,需要指定父组件而存在
2> 子组件的生命周期由父组件进行管理
3> 当父组件展示时,会将子组件一并展示,当父组件释放空间时,会将加载在该组件上的所有子组件的空间全部释放
4> 对象树模型保证了,各个组件的内存不会泄露
5> 在栈区申请的组件,程序结束后,由系统自动回收,在堆区申请的组件,结束后,由其父组件进行回收资源
6> 父组件和子组件要用于共同的祖先类,实现的理论基础为多态
7> 每一个组件中都会拥有一个父组件指针和一个子组件链表
2.2 使用C++证明对象树模型的内部实现
#include <iostream>
#include<list>
using namespace std;
class Obj;
typedef list<Obj *> childList;
class Obj
{
public:
Obj(Obj* parent = nullptr)
{
if(parent != nullptr)
{
parent->child.push_back(this);
}
}
virtual ~Obj()
{
for(auto ptr = this->child.begin(); ptr!=this->child.end(); ptr++)
{
cout<<"析构子组件"<<endl;
delete *ptr;
}
}
childList &childl()
{
return child;
}
public:
childList child;
};
class A:public Obj
{
public:
A(Obj *parent = nullptr):Obj(parent) {
if(parent != nullptr)
{
this->parent = parent;
parent->child.push_back(this);
}
cout<<"A::构造函数"<<endl;
}
~A(){
if(parent != nullptr)
{
parent->child.remove(this);
cout<<"父类对象移除自己"<<endl;
}
cout<<"A::析构函数"<<endl;
}
Obj *parent = nullptr;
};
class B:public Obj
{
public:
B(Obj *parent = nullptr):Obj(parent) {
if(parent != nullptr)
{
this->parent = parent;
parent->child.push_back(this);
}
cout<<"B::构造函数"<<endl;
}
~B(){
if(parent != nullptr)
{
parent->child.remove(this);
cout<<"父类对象移除自己"<<endl;
}
cout<<"B::析构函数"<<endl;
}
Obj *parent = nullptr;
};
int main()
{
A a1;
B * b1 = new B(&a1);
//delete b1;
cout<<"********************************"<<endl;
return 0;
}
3. 信号与槽机制
信号与槽机制,是qt能够在所有编程语言中,傲立不倒的重要机制,发生在两个组件之间,相当于两个组件的通信
3.1 信号与槽机制的概述
1> 原理
一个组件用于发射信号,与之绑定的组件收到信号后,会立刻做出相应
2> 信号:
所谓信号,就是信号函数,定义在类的signals权限下,是一个不完整的函数,只有函数声明,没有函数定义。返回值类型为void
信号函数不能当作普通函数一样被调用,只能被发射出去。
3> 槽:
所谓槽,就是槽函数,定义在类的slots权限,是一个完整的函数,既有函数声明,也有函数定义,返回值类型为void
槽函数可以当作普通函数一样被调用,但是普通函数不能当作槽函数接收信号
4> 包含信号与槽的类格式如下:
class Widget : public QWidget
{
Q_OBJECT //信号与槽的宏对象,有了该宏,信号与槽才能正常使用
public:
Widget(QWidget *parent = nullptr);
~Widget();
signals:
void my_signal(); //信号函数的定义
public slots:
void my_slot(); //自定义槽函数的声明
private:
Ui::Widget *ui;
};
5> 系统提供的组件,一般都默认自带指定的信号函数和槽函数,也可以自定义信号函数和槽函数
3.2 手动连接信号与槽
1> 使用qt4版本的连接函数:该连接函数是不友好的连接,即使函数名写错,也不会报错
[static] QMetaObject::Connection //函数返回值类型,是一个连接,是静态成员函数
QObject::connect( //函数名
const QObject *sender, //参数1:信号的发送者组件的地址
const char *signal, //要发射的信号:需要的是const char *的字符串,需要使用宏函数来将函数名转变成字符串SIGNAL()
const QObject *receiver, //信号接收者组件的地址
const char *method) //信号的接收者对应的槽函数:需要使用宏函数来转变 SLOT()
举个例子:
QLabel *label = new QLabel;
QScrollBar *scrollBar = new QScrollBar;
QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
label, SLOT(setNum(int)));
2> 使用qt5版本的连接函数
[static] QMetaObject::Connection //函数返回值类型,是一个连接,是静态成员函数
QObject::connect( //函数名
const QObject *sender, //信号发射者组件的地址
PointerToMemberFunction signal, //要发射的信号:函数指针,要求传递函数的地址
const QObject *receiver, //信号接收者组件的地址
PointerToMemberFunction method) //要执行的功能:函数指针
举个例子:
QLabel *label = new QLabel;
QLineEdit *lineEdit = new QLineEdit;
QObject::connect(lineEdit, &QLineEdit::textChanged,
label, &QLabel::setText);
3> C++11后的连接函数
[static] QMetaObject::Connection 函数返回值类型,是一个连接,是静态成员函数
QObject::connect( //函数名
const QObject *sender, //信号发送者组件的地址
PointerToMemberFunction signal, //要发送的信号:函数指针
Functor functor) //要执行的逻辑,可以时全局函数、仿函数、lambda表达式
举个例子1:全局函数作为槽函数
void someFunction();
QPushButton *button = new QPushButton;
QObject::connect(button, &QPushButton::clicked, someFunction);
举个例子2:lambda表达式作为槽函数
QByteArray page = ...;
QTcpSocket *socket = new QTcpSocket;
socket->connectToHost("qt-project.org", 80);
QObject::connect(socket, &QTcpSocket::connected, [=] () {
socket->write("GET " + page + "\r\n");
});
3.3 手动定义信号并发射
1> 需要在类的signal权限下定义信号,返回值为void,参数取决于需求而定,不需要实现函数体内容
2> 在程序的适当位置,使用关键字 emit 信号名(实参);进行发射信号
3> 当信号发射后,与该信号关联的槽函数就会自动执行
3.4 信号函数和槽函数之间的关系
1、信号函数和槽函数进行链接时,一般要求信号函数和槽函数的参数保持一致
connect(信号发送者, SIGNAL(signalFun()),信号接收者, SLOT(slotFun())); //Ok
connect(信号发送者, SIGNAL(signalFun(int)),信号接收者, SLOT(slotFun(int))); //Ok
connect(信号发送者, SIGNAL(signalFun(int, char)),信号接收者, SLOT(slotFun(int, char))); //Ok
connect(信号发送者, SIGNAL(signalFun(Qstring, int)),信号接收者, SLOT(slotFun(int, QString))); //False
connect(信号发送者, SIGNAL(signalFun(int)),信号接收者, SLOT(slotFun(QString))); //False
2、当信号函数的参数大于槽函数的参数时
connect(信号发送者, SIGNAL(signalFun(int, char)),信号接收者, SLOT(slotFun())); //Ok
connect(信号发送者, SIGNAL(signalFun(int, char)),信号接收者, SLOT(slotFun(int))); //Ok
connect(信号发送者, SIGNAL(signalFun(int, QString)),信号接收者, SLOT(slotFun(QString))); //False
3、当信号函数的参数小于槽函数的参数时
connect(信号发送者, SIGNAL(signalFun(int)),信号接收者, SLOT(slotFun(int, char))); //False
connect(信号发送者, SIGNAL(signalFun(int)),信号接收者, SLOT(slotFun(int, char=0))); //Ok 可以使用qt4版本传,但是不支持了
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//将信号函数1和槽函数1进行绑定
connect(this, &Widget::mySignal1, this, &Widget::mySlot1);
//信号函数的参数大于槽函数的参数:信号函数传来的数据槽函数可以不接
connect(this, &Widget::mySignal2, this, &Widget::mySlot1);
//将带参信号与带参槽进行连接
connect(this, &Widget::mySignal2, this, &Widget::mySlot2);
//connect(this, &Widget::mySignal2, this, &Widget::mySlot3);
//connect(this, SIGNAL(mySignal2(int)), this, SLOT(mySlot3(int, QString)));
//将带参信号与带参槽连接
connect(this, &Widget::mySignal3, this, &Widget::mySlot3);
}
Widget::~Widget()
{
delete ui;
}
//槽函数1的定义
void Widget::mySlot1()
{
qDebug() << "触发了槽函数1的相关功能";
}
//槽函数2的定义
void Widget::mySlot2(int num)
{
qDebug()<<"您触发了槽函数2 num = "<<num;
}
//槽函数3的定义
void Widget::mySlot3(int num, QString str)
{
qDebug()<<"您触发了槽函数3 num = "<<num<<" str = "<<str;
}
//按钮1对应的槽函数
void Widget::on_btn1_clicked()
{
//手动发射信号1
//emit mySignal1();
//手动发射信号2
emit mySignal2(520);
//手动发射信号3
emit mySignal3(520, "1314");
}
3.5 信号与槽连接的总结
1> 一个信号可以连接到多个槽函数中
2> 多个信号可以连接到同一个槽函数中,当连接的任意一个信号被发射出来后,槽函数就立即执行
3> 一个信号函数也可以连接到另一个信号函数上,表示当前面的信号被发射 后,后面的信号紧跟着发射出去
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//将信号函数1和槽函数1进行绑定
connect(this, &Widget::mySignal1, this, &Widget::mySlot1);
//信号函数的参数大于槽函数的参数:信号函数传来的数据槽函数可以不接
connect(this, &Widget::mySignal2, this, &Widget::mySlot1);
//将带参信号与带参槽进行连接
connect(this, &Widget::mySignal2, this, &Widget::mySlot2);
//connect(this, &Widget::mySignal2, this, &Widget::mySlot3);
//connect(this, SIGNAL(mySignal2(int)), this, SLOT(mySlot3(int, QString)));
//将带参信号与带参槽连接
connect(this, &Widget::mySignal3, this, &Widget::mySlot3);
//将一个信号绑定到另一信号上
connect(ui->btn1, &QPushButton::clicked, this, &Widget::mySignal1);
connect(ui->btn1, &QPushButton::clicked, this, &Widget::mySlot1);
}
Widget::~Widget()
{
delete ui;
}
//槽函数1的定义
void Widget::mySlot1()
{
qDebug() << "触发了槽函数1的相关功能";
}
//槽函数2的定义
void Widget::mySlot2(int num)
{
qDebug()<<"您触发了槽函数2 num = "<<num;
}
//槽函数3的定义
void Widget::mySlot3(int num, QString str)
{
qDebug()<<"您触发了槽函数3 num = "<<num<<" str = "<<str;
}
//按钮1对应的槽函数
void Widget::on_btn1_clicked()
{
//手动发射信号1
//emit mySignal1();
//手动发射信号2
//emit mySignal2(520);
//手动发射信号3
//emit mySignal3(520, "1314");
}
3.6 使用信号与槽完成两个界面跳转
1> 准备两个界面
2> 在第一个界面定义跳转的槽函数,并且在相应位置,发射该信号
3> 在第二个界面定义槽函数,接收信号后,展示界面
4> 在主函数中实例化第二个界面,并且连接两个界面的信号与槽