目录
一、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;
}
 
     















![〖产品思维训练白宝书 - 产品思维认知篇⑤〗- 学习 [产品思维] 需要做哪些准备?](https://img-blog.csdnimg.cn/e764f067fc174078a5a7f8d571f0d679.png#pic_center)

