Qt入门---窗口坐标系,信号和槽

目录

窗口坐标系

信号(Signal)和槽(Slot)的机制

自定义的信号和槽

信号和槽函数的重载问题

信号连接信号


窗口坐标系

Qt窗口坐标体系:窗口左上角为原点(0,0) 向右x增加 向下y增加

信号(Signal)和槽(Slot)的机制

        信号:代表特定情况下被发射的事件 比如鼠标点击的clicked()信号 可在帮助中查找相关的信号 若在该类中未发现Signals 可以向上寻找其父类的信号

        槽:对信号响应的函数,当对应信号发射时,槽函数会自动执行

        特点:松散耦合 通过信号与槽机制实现的对象间通信方式具有低耦合度 信号的发送方和接收方彼此并无关联 仅通过connect函数来连接实现信号响应

信号与槽函数的连接方式 

        引入connect函数,其参数依次为信号的发送者 发送的信号 信号的接收者 处理的槽函数

样例:实现点击按钮关闭窗口

//mybtn代表信号发送方 发送的信号要用函数地址 格式为& + 信号发送方的类 + :: + 对应的信号
//this代表myWidget 信号的接收方 处理的槽函数同理也要用函数地址 格式与信号一致
connect(mybtn, &mypushbutton::clicked, this, &myWidget::close);

自定义的信号和槽

需求:创造老师类和学生类 下课后 老师饿 学生请客吃饭

1.添加新文件 老师类和学生类 由于这两个类并不属于窗口类 所以base class 中选择QObject 方便释放 原因可参考对象树机制

2.声明信号

//自定义信号写到signals下面
//返回值必须为void型 信号只需在.h文件中声明 无需实现
//可以有参数,可以重载
signals:
    void hungry();

3.创建槽函数

//.h文件
class Student : public QObject
{
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);
    
//槽函数的声明 早期Qt版本声明要写到public slots: 高版本(5.4以后)可以写到public 或者 全局
//返回值也必须为void 需要声明与实现
//可以有参数 可以进行重载
    void treat();
    
signals:

};
//.cpp文件 注意作用域一定要标明
void Student::treat()
{
    qDebug() << "请客吃饭";
}

4.创建对象 构造链接

创建对象也需要先在.h文件中声明

//QWidget.h 添加对应头文件
#include <QWidget>
#include "teacher.h"
#include "student.h"

//在class下声明对象 设为私有
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    Teacher * zhy;
    Student * st;
};
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

//zhy 和 st 属于Widget下的对象 可以用. 或 ->调用
    this->zhy = new Teacher(this);

    this->st = new Student(this);

    connect(zhy, &Teacher::hungry, st, &Student::treat);
}

5.创造信号触发函数

//Widget.h
private:
    Ui::Widget *ui;
    Teacher * zhy;
    Student * st;

//代表下课后老师开始饿 信号触发函数
    void ClassIsOver();
};
//Widget.cpp

void Widget::ClassIsOver()
{

//emit 专门用来发射信号
    emit zhy->hungry();
}

//构造函数的涉及代码 注意顺序 要先用connect建立连接 再发送信号
connect(zhy, &Teacher::hungry, st, &Student::treat);
ClassIsOver();

信号和槽函数的重载问题

以信号hungry和槽函数treat的重载为例

信号hungry重载

//teacher.h
signals:
    void hungry();

    void hungry(QString foodname);

槽函数treat重载

//student.h
public:
    explicit Student(QObject *parent = nullptr);

    void treat();

    void treat(QString foodname);

//student.cpp
void Student::treat(QString foodname)
{
    qDebug() << "请客吃饭,吃" << foodname;
}

connect连接

//Widget.cpp
//当信号和槽函数出现重载时 不能单纯地直接调用函数地址&Teacher::hungry, &Student::treat
//会出现二义性 编译过程不知道要调用无参函数还是带参函数 需要引入函数指针指向具体的函数
//函数指针的格式 该函数返回值类型(函数作用域:: * 指针名称)(该函数形参类型, , , )
//若要指向的函数非全局函数 而是成员函数 则需要在指针名称前加上函数作用域 否则不需要
//等号右边代表要指向的函数 该成员函数由于存在多个 需要等式左边第二个(形参类型)来指向特定的一个
void (Teacher:: * teachersignal)(QString) = &Teacher::hungry;
void (Student:: * studentslot)(QString) = &Student::treat;
connect(zhy, teachersignal, st, studentslot);
ClassIsOver();


void Widget::ClassIsOver()
{
    emit zhy->hungry("北京烤鸭");
}

输出结果

 可以看到输出的是 请客吃饭,吃“北京烤鸭”

这里介绍下QString 它是Qt编程中常用的类 QString存储字符串采用Unicode码 编码方式采用UTF-16进行编码(一个汉字占两个字节)

qDebug() 函数输出 QString 时,根据需要会自动添加引号来区分字符串的起始和结束位置。

qDebug() << "请客吃饭,吃" << foodname;

在这个代码中,"请客吃饭,吃" 是一个常量字符串,而 foodname 是一个 QString 对象。当它们一起被输出时,qDebug() 函数会将 foodname 的内容用双引号括起来,以标识字符串的边界

若要去掉这个双引号 可以采用以下方法

//将QString型转化为char* 
//char* 字符型指针 用来指向一个字符数组 被视为以空字符'\0'结尾
//qDebug在输出char*时仍然将其视为C风格字符串,并且不会添加双引号来表示字符串的边界
//qDebug在输出char*类型的指针时会进行特殊处理,不会直接输出指针的地址,而是根据该指针指向的内存地址来输出字符串的内容
qDebug() << "请客吃饭,吃" << foodname.toUtf8().data();

信号连接信号

需求:在窗口中提供一个按钮 点击后下课 老师饿 学生请吃饭

方法一:采用信号与槽函数的连接

QPushButton * btn = new QPushButton("下课", this);

connect(btn, &QPushButton::clicked, this, &Widget::ClassIsOver);

方法二:采用信号与信号的连接

//将按钮的点击信号与老师的饿了信号做连接 当下课按钮被点击时 饿了信号就会被发送
//同时饿了信号还与学生的请客槽函数连接 从而触发请客
//注意 这里指向的老师饿了信号和学生的请客槽函数都是无参的 详情见下面拓展
QPushButton * btn = new QPushButton("下课", this);

void (Teacher:: * Teachersignal)() = &Teacher::hungry;

void (Student:: * Studentslot)() = &Student::treat;

connect(zhy, Teachersignal, st, Studentslot);

connect(btn, &QPushButton::clicked, zhy, Teachersignal);

断开信号

//将要断开的连接()内的各个参数直接复制到disconnect()内即可
disconnect(btn, &QPushButton::clicked, zhy, Teachersignal);

拓展

1.信号可以和信号连接

2.一个信号可以连接多个槽函数

3.多个信号可以连接同一个槽函数

4.信号和槽函数的参数类型必须一一对应

5.信号的参数个数可以多于槽函数的参数个数 槽函数可以选择不接受多余的参数 但槽函数所需要的参数类型信号参数中必须存在且顺序一致

举例:信号参数 bool 槽函数 void 槽函数不会接受信号的参数 bool型相当于无效传递 

           信号参数 bool 槽函数 int 会报错 因为最基本的槽函数所需要的参数类型没有被满足

           信号参数 bool int 槽函数 bool 可行

           信号参数 int bool 槽函数 bool int 不可行 顺序必须一致

6.Qt4版本及以前的信号和槽的连接方式

优点:简洁直观

缺点:由于该连接方式的底层实现是将信号和槽函数转变为字符串去查找 并没有进行信号与槽函数参数之间的比较 因此可能会出现5中参数不符的情况 但它依然会通过编译 当你进行相关操作时会提示报错信息

//底层实现 "hungry()" "treat()"
connect(zhy, SIGNAL(hungry()), st, SLOT(treat()));

特别注意:在本机QT版本中信号和槽函数均要明确声明,否则会判定为信号或槽函数不存在

signals:
    void hungry();

    void hungry(QString foodname);

public slots:
    void treat();

    void treat(QString);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值