带参的信号、lamda表达式及坐标系统
一、带参的信号
1. 自定义信号(这个信号不像标准信号是一个宏,而是一个自定义信号函数,注意是信号函数不是信号处理函数,信号处理函数是槽函数)
- 信号必须由signals关键字声明
- 信号没有返回值但是可以有参数
- 信号就是函数的声明无需实现
- 使用的时候需要加emit + 信号函数的方式
- 信号可以重载
2. Qt5重载带参信号的使用
**我们上面说过,自定义信号就是自定义一个信号函数,只有声明没有实现**,所以也可以按照函数指针的方式进行区分,不过和函数指针的区别是它要加上信号所在类名::信号函数
那么看下面这种情况:
signals:
void Mysignal();
void Mysignal(int,QString);
void dealsub();
void dealsold(int,QString);
connect(&w,&SubWidget::Mysignal,this,&MainWidget::dealsub);
connect(&w,&SubWidget::Mysignal,this,&MainWidget::dealsold);
void MainWidget::dealsold(int num,QString arg)
{
qDebug()<<num<<" "<<arg.toUtf8().data();
}
void MainWidget::dealsub()
{
w.hide();
this->show();
}
我们重载了Mysignal()信号
,在进行connect关联槽函数时编译就会出错,因为编译器无法区分SubWidget::Mysignal
信号是带参数的还是不带参数的,所以应进行区分。
方法:所在类名::信号函数一起构成函数指针
void (SubWidget::*sub)() = &SubWidget::Mysignal;
connect(&w,sub,this,&MainWidget::dealsub);
void (SubWidget::*subsignal)(int,QString) = &SubWidget::Mysignal;
connect(&w,subsignal,this,&MainWidget::dealsold);
3.QT中的输出
qDebug
:函数
#include <QDebug>//头文件
qDebug(const char *message, ...)
-
注意第一个q是小写
-
注意还有一个()
- 自动换行
- 和cout用法基本一样
qDebug()<<num<<" "<<arg.toUtf8().data();
4. QString转char*
//字节数组
QByteArray QString::toUtf8() const
//C字符串
char *QByteArray::data()
例
:
//arg.toUtf8() -> 字节数组
//arg.toUtf8().data()->C字符串
qDebug()<<num<<" "<<arg.toUtf8().data();
5. Qt4信号连接
- Qt4槽函数必须有slots声明
-
SIGNAL和SLOT宏
是将函数名字转换为字符串 - 采用Qt5的函数指针的方式使用会参与类型安全检查,而Qt4宏的方式不参与安全检查,只有到运行时才报错
signals:
void Mysignal();
void Mysignal(int,QString);
public slots:
void dealsub();
void dealsold(int,QString);
connect(&w,SIGNAL(Mysignal()),this,SLOT(dealsub()));
connect(&w,SIGNAL(Mysignal(int,QString)),this,SLOT(dealsold(int,QString)));
void MainWidget::dealsold(int num,QString arg)
{
qDebug()<<num<<" "<<arg.toUtf8().data();
}
void MainWidget::dealsub()
{
w.hide();
this->show();
}
使用Qt4宏的方式也可以实现区分重载信号,方便使用,但是一定要注意Qt4宏的方式的缺陷,所以一般采用Qt5的方式,虽然麻烦但是安全
二、lamda表达式
C++11新增加加了lamda表达式,所以也可以用lamda表达式配合Qt信号一起使用!
使用的方式:在项目文件(.pro)中加入CONFIG += c++11
QPushButton* b4 = new QPushButton(this);
b4->setText("i am lambda");
b4->move(1,200);
//this可写可不写
connect(b4,&QPushButton::clicked,[](bool check)
{
qDebug()<<"i am lambda";
qDebug()<<check;
});
- 注意lambda的捕获列表既可以以值方式捕获,也可以以引用的方式进行捕获,但是
在信号这里最好用值的方式进行捕获
假设上面的代码以引用的方式捕获b4,然后在函数体内对b4进行修改
QPushButton* b4 = new QPushButton(this);
b4->setText("i am lambda");
b4->move(1,200);
//this可写可不写
connect(b4,&QPushButton::clicked,[&b4](bool check)
{
qDebug()<<"i am lambda";
qDebug()<<check;
b4->move(2,200);
});
程序就会 出错,因为connect正在使用b4,而函数体内的b4刚好是引用方式捕获的,也就是一个别名,内部正在修改,两者就会矛盾,就会导致程序崩溃
!
-
注意信号的发出者
:
b1.setParent(this);
b1.setText("close");
b1.move(10,10);
connect(&b1,&QPushButton::pressed,this,&MainWidget::close);
上面这个代码的功能是当按下b1按钮时,主窗口关闭,你们可能认为信号是b1按钮发送的,其实不是,信号是信号拥有者发送的
,而当按下b1按钮时只是触发了槽函数,由槽函数来进行发送信号
三、坐标系统
1. move函数
移动按钮是使用move函数,而移动窗口也是使用move函数,因为move函数是继承与QWidgets,而QWidgets基本上是所有控件的基类,所以窗口也可以用move移动
2.坐标系统
- 对于主窗口来说:坐标系统是相对于屏幕而言,移动的起点是相对于屏幕的左上角, x:往右递增,y往下增长
- 对于子窗口来说:坐标系统就是相对于主窗口而言的,移动的起点是主窗口的空白区域,不包括边框
#include "mywidget.h"
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
move(100,100);
QPushButton* b1 = new QPushButton(this);
b1->setText("i am move b1");
b1->move(99,99);
b1->resize(140,140);
QPushButton* b2 = new QPushButton(b1);
b2->setText("i am move b2");
b2->move(0,0);
b2->resize(30,30);
}
MyWidget::~MyWidget()
{
}