目录
一、QWidget类(重点)
二、子组件(掌握)
三、样式表(熟悉)
一、什么是信号槽?
二、信号槽的连接方式
2.1 自带信号→自带槽
2.2 自带信号→自定义槽
2.3 自定义信号
三、传参方式
3.1 成员变量
3.2 静态局部变量
3.3 信号槽传参
四、对应关系
4.1 一对多
4.2 多对一
一、QWidget类(重点)
QWidget类是Qt中所有可视化组件和窗口的基类,其内部规定了很多成员,这些成员都会继承给其派生类。
常用成员,所有属性的Access functions对应的都是封装后的接口,即getter和setter:
- width : const int
宽度
- height : const int
高度
宽高无法直接设定,可以通过resize函数一起改变。
- x : const int
x轴坐标,x轴的正方向向右
- y : const int
y轴坐标,y轴的正方向向下,原点在左上。
坐标无法直接设定,可以通过move函数一起改变,任何组件和窗口的定位点是左上角。位置是相对的,取决于当前组件或窗口属于什么。
- void QWidget::show() [slot]
展示
- void setGeometry(int x, int y, int w, int h)
同时设置坐标与宽高。
二、子组件(掌握)
窗口中要有其它的子组件,不然只是空内容的窗口。
使用QPushButton类作为子组件,QPushButton表示一个按钮,构造函数如下
QPushButton(const QString & text, QWidget * parent = 0)
参数一:显示文本,QString是Qt中的字符串类。
参数二:父窗口或父组件
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
// 引入头文件
#include <QPushButton>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton *btn;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
// 改变宽高(不包含标题栏)
resize(200,200);
// 移动位置
move(200,200);
// 创建按钮对象
// this指的是主函数中的Dialog w对象
// this结合多态进行参数传递
btn = new QPushButton("你好",this);
btn->resize(50,50);
// 相对坐标
btn->move(50,50);
// 展示
btn->show();
}
Dialog::~Dialog()
{
// C++:有new就有delete
delete btn;
}
三、样式表(熟悉)
默认的组件样式比较普通,可以通过设置样式表来自定义组件样式。
void setStyleSheet(const QString & styleSheet)
参数为QSS语法的样式,QSS语法类似于CSS。
配色网站:在线颜色选择器 | RGB颜色查询对照表
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
// 引入头文件
#include <QPushButton>
// 预设样式
#define QPushButton_STYTLE (QString("\
/*按钮普通态*/\
QPushButton\
{\
font-family:Microsoft Yahei;\
/*字体大小为20点*/\
font-size:20pt;\
/*字体颜色为白色*/\
color:white;\
/*背景颜色*/\
background-color:rgb(188, 238, 104);\
/*边框圆角半径为8像素*/\
border-radius:8px;\
}\
/*按钮悬停态*/\
QPushButton:hover\
{\
/*背景颜色*/\
background-color:rgb(100 , 137 , 255);\
}\
/*按钮按下态*/\
QPushButton:pressed\
{\
/*背景颜色*/\
background-color:rgb(14 , 135 , 10);\
/*左内边距为3像素,让按下时字向右移动3像素*/\
padding-left:3px;\
/*上内边距为3像素,让按下时字向下移动3像素*/\
padding-top:3px;\
/*字体颜色为白色*/\
color:black;\
}"))
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton *btn;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
// 同时设置x,y,宽,高
setGeometry(200,200,200,200);
btn = new QPushButton("你好",this);
btn->setGeometry(50,50,100,100);
// 给按钮设置样式表
// btn->setStyleSheet("background-color:green;color:red");
btn->setStyleSheet(QPushButton_STYTLE);
// 展示
btn->show();
}
Dialog::~Dialog()
{
// C++:有new就有delete
delete btn;
}
Tip:
在Qt程序运行过程中,如果出现
表示当前程序已经运行,需要先关闭已经运行的程序,再重新运行。
一、什么是信号槽?
之前写的代码,只能看,不能交互。使用信号槽可以让用户与图形用户界面进行人机交互,信号槽是Qt特有的一种组件对象之间的通信机制。
信号函数是一种特殊的函数,槽函数也是一种特殊的函数。
使用信号槽进行组件对象之间的通信有两个前提条件:
1. 通信的对象必须是中QObject派生出来的,QObject类是所有Qt类型的基类。
2. 类中要有Q_OBJECT宏。
信号槽的使用主要通过下面的连接函数:
参数1:发射者,即触发动作的、作为条件的组件对象,通常是名词(对象名称)。
参数2:信号函数的名称,使用SIGNAL()包裹,信号函数是作为条件的动作本身,通常是 动词(函数名称)。信号函数一定属于发射者。
参数3:接收者,作为执行结果动作的对象,通常是名词(对象名称)。
参数4:槽函数的名称,使用SLOT()包裹,作为结果执行的具体动作,通常是动词(函数 名称)。槽函数是一种特殊的成员函数。槽函数一定属于接收者。
整个信号槽的连接,可以总结为:
receiver绑定了sender的signal信号,一旦sender发出signal信号,receiver就执行method函数。
信号槽的断开连接方式有两种:
- 当发射者或接收者对象销毁时,信号槽连接自动断开
- 调用disconnect函数手动断开信号槽连接,参数与connect函数一样。
二、信号槽的连接方式
为了方便渐进式的学习,信号槽连接依次讲解以下几种方式:
- 自带信号→自带槽
- 自带信号→自定义槽
- 自定义信号→槽函数(自带或自定义皆可)
2.1 自带信号→自带槽
这是最简单的一种连接方式,因为信号函数与槽函数都是Qt内置的函数,程序员只需要找到对应的关系调用connect函数连接即可。
【例子】点击按钮,关闭窗口。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(300,300);
btn = new QPushButton("关闭",this);
btn->move(150,150);
// 连接信号槽
// 参数1:发射者,按钮
// 参数2:信号函数,clicked()
// 参数3:接收者,窗口
// 参数4:槽函数,close()
connect(btn,SIGNAL(clicked()),this,SLOT(close()));
}
Dialog::~Dialog()
{
delete btn;
}
2.2 自带信号→自定义槽
即使Qt内置的函数再多,也总有触及不到的需求,对于一些没有内置的槽函数,就需要程序员手动去编写了。
【例子】点击按钮,窗口向右下方移动 10*根2 个像素,并输出移动后的窗口坐标。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
#include <QDebug>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn;
// 1. 声明槽函数
private slots:
void mySlot();
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(300,300);
btn = new QPushButton("向右下",this);
btn->move(140,140);
// 连接信号槽
// 点击按钮,执行自定义槽函数
connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}
// 2. 定义槽函数
/**
* 窗口向右下方移动14.1个像素,并输出移动后的窗口坐标。
*/
void Dialog::mySlot()
{
// 获取窗口的当前坐标
int x = this->x();
int y = this->y();
// 移动窗口
move(x+10,y+10);
// 打印新坐标
qDebug() << x+10 << "*" << y+10;
}
Dialog::~Dialog()
{
delete btn;
}
2.3 自定义信号
这种方式主要用在后面一些特定的时机,现在只是为了讲解强行使用。
信号函数具有以下特点:
- 信号函数只有声明,没有定义
- 信号函数无需调用,只需发射
- 信号函数的参数使用哑元
- 信号函数无权限
【例子】点击按钮,关闭窗口。
这一次把上面的动作分解为:
点击按钮,调用自定义槽函数,在自定义槽函数中发射自定义信号;
自定义信号触发关闭窗口的动作。
与之前的对比如下:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn;
// 声明自定义槽函数
private slots:
void mySlot();
// 声明自定义信号
signals:
void mySignal();
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(200,200);
btn = new QPushButton("关闭",this);
btn->move(80,80);
// 连接信号槽
connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
connect(this,SIGNAL(mySignal()),this,SLOT(close()));
}
void Dialog::mySlot()
{
// 发射自定义信号
emit mySignal();
}
Dialog::~Dialog()
{
delete btn;
}
三、传参方式
【例子】有一个按钮,按钮上显示按钮点击的次数。
需要用到整型转字符串函数
QString number(int n, int base = 10) [static]
参数1:要转换的数字
参数2:进制
返回值:转换后的字符串
3.1 成员变量
代码与3.2合并。
3.2 静态局部变量
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
int count1 = 0; // 按钮1的点击次数
QPushButton* btn1;
QPushButton* btn2;
private slots:
// 两个按钮点击的槽函数
void btn1ClickedSlot();
void btn2ClickedSlot();
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(300,300);
btn1 = new QPushButton("0",this);
btn1->move(150,150);
btn2 = new QPushButton("0",this);
btn2->move(150,180);
// 连接信号槽
connect(btn1,SIGNAL(clicked()),this,SLOT(btn1ClickedSlot()));
connect(btn2,SIGNAL(clicked()),this,SLOT(btn2ClickedSlot()));
}
void Dialog::btn1ClickedSlot()
{
count1++; // 计数+1
// 把整型转换为字符串
QString text = QString::number(count1);
// 设置到按钮上
btn1->setText(text);
}
void Dialog::btn2ClickedSlot()
{
static int count2 = 0;
count2++;
QString text = QString::number(count2);
btn2->setText(text);
}
Dialog::~Dialog()
{
delete btn1;
delete btn2;
}
3.3 信号槽传参
为了讲解信号槽传参,强行在上面的例子中使用。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn;
int count = 0;
private slots:
void btnClickedSlot();
// 带参数的槽函数,来接收信号发送的参数
void mySlot(int);
signals:
// 带参数的信号函数
void mySignal(int);
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(300,300);
btn = new QPushButton("0",this);
btn->move(50,50);
connect(btn,SIGNAL(clicked()),this,SLOT(btnClickedSlot()));
connect(this,SIGNAL(mySignal(int)),this,SLOT(mySlot(int)));
}
void Dialog::btnClickedSlot()
{
count++;
// 发射带参数的自定义信号
emit mySignal(count);
}
/**
* @brief Dialog::mySlot
* @param count 信号发射过来的
*/
void Dialog::mySlot(int count)
{
QString text = QString::number(count);
btn->setText(text);
}
Dialog::~Dialog()
{
delete btn;
}
信号槽传参需要注意:
1. 理论上可以传递任意多个参数,但通常传递1-2个参数。
2. 信号的参数个数必须大于等于槽的参数个数。
3. 参数的类型需要一一匹配。
四、对应关系
4.1 一对多
同一个信号可以同时链接到多个槽。
一对多的情况也可以优化为下面的代码:
4.2 多对一
多个信号也可以同时连接到同一个槽。
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QPushButton>
#include <QDebug>
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
~Dialog();
private:
QPushButton* btn1;
QPushButton* btn2;
private slots:
void mySlot1();
void mySlot2();
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
resize(200,200);
btn1 = new QPushButton("按钮1",this);
btn2 = new QPushButton("按钮2",this);
btn1->move(50,50);
btn2->move(50,80);
// 一对多
// connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot1()));
// connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot2()));
// 多对一
connect(btn1,SIGNAL(clicked()),this,SLOT(mySlot1()));
connect(btn2,SIGNAL(clicked()),this,SLOT(mySlot1()));
}
void Dialog::mySlot1()
{
qDebug() << "槽函数1";
}
void Dialog::mySlot2()
{
qDebug() << "槽函数2";
}
Dialog::~Dialog()
{
delete btn1;
delete btn2;
}