一、Qt消息模型
1、Qt封装了具体操作系统的消息机制
2、Qt遵循经典的GUI消息驱动事件模型
二、信号与槽
1、Qt中定义了与系统消息相关的概念
(1)、信号(Signal):由操作系统产生的消息
(2)、槽(Slot):程序中的消息处理函数
(3)、连接(Connect):将系统消息绑定到消息处理函数
2、Qt的消息处理机制(信号到槽的连接必须发生在两个Qt对象之间)
3、Qt的核心,QObject::connect函数
(1)、在Qt中。消息用字符串来描述
(2)、connect函数在消息名和处理函数之间建立联系
4、Qt中心的关键字
(1)、SIGNAL:用于指定消息名
(2)、SLOT:用于指定消息处理函数名
(3)、Q_Object:所有自定义槽的类必须在类声明的开始处加上Q_Object
(4)、slots:用于在类中声明消息处理函数
#include <QtGui/QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton b;//顶级组件
b.setText("click me to quit");
b.show();
QObject::connect(&b, SIGNAL(clicked()), &a, SLOT(quit()));//发送对象为b,消息为clicked(),接收对象为a,槽函数为quit()
return a.exec();
}
三、自定义槽
1、自定义槽的方法
(1)、只有QObject的子类才能自定义槽
(2)、定义槽的类必须在类声明的最开始处使用Q_Object
(3)、类中声明槽函数时需要用slots关键字
(4)、槽与所处理的信号在函数签名上必须一致
(5)、SIGNAL和SLOT所指定的名称中
A、可以包含参数类型
B、不能包含具体参数名
//主要是在头文件类声明那里加上了一下声明,在实现文件实现槽函数,连接了信号与槽
//QCalculatorUI.h:
#ifndef _QCALCULATORUI_H_
#define _QCALCULATORUI_H_
#include <QtGui/QApplication>
#include <QLineEdit>
#include <QPushButton>
#include <QDebug>
class QCalculatorUI : public QWidget//继承自Qwid,可知。QCalculatorUI是QObject的间接子类
{
Q_OBJECT //类声明最开始处使用Q_Object关键字
QLineEdit* m_edit;//组合关系
QPushButton* m_buttons[20];
QCalculatorUI();
bool construct();
private slots://slots关键字
void onButtonClicked();//与消息的函数签名一样,消息的clicked()没有参数,所以这里也没有
public:
static QCalculatorUI* NewInstance();
void show();
~QCalculatorUI();
};
#endif // _QCALCULATORUI_H_
//QCalculatorUI.cpp:
#include "QCalculatorUI.h"
QCalculatorUI::QCalculatorUI() : QWidget(NULL,Qt::WindowCloseButtonHint )
{
}
bool QCalculatorUI::construct()
{
bool ret = true; //注意:这里隐藏了一个巨大的bug,这里又定义了一个QLineEdit,使得后面课程访问m_edit->text()时出现异常,这里应该将QLineEdit*去掉
QLineEdit *m_edit = new QLineEdit(this);//父组件是this的原因:组合关系,同生死共存亡
const char* btnText[20] =
{
"7", "8", "9", "+", "(",
"4", "5", "6", "-", ")",
"1", "2", "3", "*", "<-",
"0", ".", "=", "/", "C"
};
if(m_edit != NULL)
{
m_edit->resize(240,30);
m_edit->move(10,10);
m_edit->setReadOnly(true);//设置文本框为只读,不输入字符串
}
else
{
ret = false;
}
for(int i=0; (i<4) && ret; i++)//(i<4) && ret表示QLineEdit没有生成,这里也 没必要运行了
{
for(int j=0; (j<5) && ret; j++)
{
m_buttons[i*5 + j] = new QPushButton(this);
if(m_buttons[i*5 + j])
{
m_buttons[i*5 + j] ->resize(40,40);//[i*5 + j]是转换为一维来算
m_buttons[i*5 + j]->move(10 + (10 + 40)*j, 50 + (10 + 40)*i);//横坐标移五个,纵坐标移四个
m_buttons[i*5 + j]->setText(btnText[i*5 + j]);
connect(m_buttons[i*5 + j], SIGNAL(clicked()), this, SLOT(onButtonClicked()));//将信号映射到当前对象的onButtonclick()
}
else
{
ret = false;
}
}
}
return ret;
}
QCalculatorUI* QCalculatorUI::NewInstance()
{
QCalculatorUI* ret = new QCalculatorUI();
if(!(ret && ret->construct()))
{
delete ret;
ret = NULL;
}
return ret;
}
void QCalculatorUI::show()
{
QWidget::show();
setFixedSize(width(), height());//要放在show()后,否则是先固定再显示
}
void QCalculatorUI::onButtonClicked()
{
QPushButton* btn = (QPushButton*)sender();//返回一个指向发送信号的对象的指针
qDebug() << "onButtonClick";
qDebug() << btn->text();
}
QCalculatorUI::~QCalculatorUI()
{
}
//main.cpp
#include <QtGui/QApplication>
#include "QCalculatorUI.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QCalculatorUI* cal = QCalculatorUI::NewInstance();
int ret =-1;
if(cal != NULL)
{
cal->show();
ret = a.exec();
delete cal;//记得删除父对象
}
return ret;
}
2、小贴士:解决经典问题QObject::connect: NO such slot
(1)、检查类是否继承于QObject
(2)、检查类声明的开始处是否添加Q_Object
(3)、检查是否使用slots关键字进行槽声明
(4)、检查槽的名称是否拼写错误
(5)、重新执行qmake
四、小结
(1)、信号与槽是Qt中的核心机制
(2)、不同的Qt对象可以通过信号与槽进行通信
(3)、只有QObject的子类才能自定义信号与槽
(4)、使用信号与槽的类必须在类声明的最开始处使用Q_Object
(5)、信号与处理函数在函数签名上必须一致(如都没有参数)