010_初探 Qt 中的消息处理

Posted luosir520

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了010_初探 Qt 中的消息处理相关的知识,希望对你有一定的参考价值。

在现代的 GUI 应用程序开发当中,主要分为两步:1.编写用户界面;2.处理用户操作后而产生的消息(编写消息处理函数来处理用户事件而产生的系统消息)

一、 Qt 消息模型

1. Qt 封装了具体操作系统的消息机制(Qt是现代的应用程序跨平台的开发框架)
2. Qt 遵循经典的 GUI 消息驱动事件模型

技术图片
GUI应用程序是针对我们用户的,用户就会对GUI程序中的一些组件,比如:按钮,对话框等等做一些操作,当用户做了这些操作之后,首先知道这个用户事件的是操作系统,操作系统就会将用户的操作的翻译成应用程序消息,并且把这个消息发送给对应的应用程序。应用程序收到这个消息之后就会调用事先编写好的消息处理函数
如果我们不关心中间的细节,简单的看开始和结束,就是用户做了一个操作,我们应用程序的某个函数就会被调用。

二、 思考

1. Qt 中如何表示用户消息?

答:用字符串来描述消息

2. Qt 中如何映射用户消息到消息处理函数?

答:使用connet函数

三、 信号与槽

1、 Qt 中定义了与系统消息相关的概念

---信号(Signal)
  • 由操作系统产生的消息
---槽(Slot)
  • 程序中的消息处理函数
---连接(Connect)
  • 将系统消息绑定到消息处理函数

2、 Qt 中的消息处理机制

技术图片
信号到槽的连接必须放生在两个 Qt 类对象之间!

3、 Qt 的核心-QObject::connet函数

技术图片

4、 Qt中的"新"关键字

Qt 是基于C++的,Qt 又扩展了C++,在Qt里面引进了几个核心的关键字

- SIGNAL
  • 用于指定消息名
- SLOT
  • 用于指定消息处理函数名
- Q_OBJECT
  • 所有自定义槽的类必须在类声明的开始处加上 Q_OBJECT
- slots
  • 用于在类中声明消息处理函数

四、 编程实验(初探信号与槽)---工程名:10-1.pro

技术图片
分析connet函数:连接信号与槽,将b这个按钮对象的click消息,这个click消息时一个预定义的消息,在Qt内库里面就已经定义好了,当按钮对象被点击了之后就会发送这个消息,现在我们通过connet函数将这个消息映射到a这个对象的quit成员函数上。那么映射之后click消息发生的时候quit函数就会被调用。
技术图片

五、 自定义槽

  • 只有 QObject的子类才能自定义槽
  • 定义槽的类必须在声明的最开始处使用 Q_OBJECT
  • 类中声明槽时需要使用 slots 关键字
  • 槽与所处理的信号在函数签名上必须一致。函数签名就是把函数名字去掉以后剩下的东西(参数、调用方式等)
  • SIGNAL 和 SLOT本质上就是用来指定消息的名字和消息处理函数的名字。那么在指定的名字当中,只能包含参数类型,不能包含具体的参数名

六、 编程实验(为计算器实例添加消息处理函数)

第一步:我们自己实现的Refactoring这个间接继承自QObject
第二步:在类的声明最开始处使用Q_OBJECT
第三步:声明槽(消息处理函数)时使用slots关键字,且槽与信号在函数签名上必须一致
技术图片
技术图片
第四步:connet连接,将二十个按钮连接到同一个消息处理函数
技术图片
测试输出
技术图片

问:我们将二十个按钮映射到了同一个消息处理函数上,那应当如何区分是哪一个按钮被点击了呢?

答:之所以我们消息处理函数有那么一丁点的特别,特别之处在于我们可以在消息处理函数内部调用sender这样的函数
技术图片

程序源码

Refactoring_Calculator.h文件

#ifndef REFACTORING_CALCULATOR_H
#define REFACTORING_CALCULATOR_H

#include <QWidget>
#include <QLineEdit>
#include <QPushButton>


class Refactoring_Calculator : public QWidget
{
    Q_OBJECT
private:
    QLineEdit* m_edit;
    QPushButton* button_array[20];
    Refactoring_Calculator();
    bool construct();
private slots:
    void OnButtonClicked();

public:
    static Refactoring_Calculator* NewInstance();
    void show();
    ~Refactoring_Calculator();
};

#endif // REFACTORING_CALCULATOR_H

Refactoring_Calculator.cpp文件

#include "Refactoring_Calculator.h"
#include <QDebug>

Refactoring_Calculator::Refactoring_Calculator() : QWidget(NULL, Qt::WindowCloseButtonHint)
{
}

 bool Refactoring_Calculator::construct()
{
     bool ret = true;
     const char* button_name[20] =
     {
         "7", "8", "9", "+", "(",
         "4", "5", "6", "-", ")",
         "1", "2", "3", "*", "<-",
         "0", ".", "=", "/", "C",
     };
     m_edit = new QLineEdit(this);
     if( m_edit != NULL )
     {
         m_edit->move(10, 10);
         m_edit->resize(240, 30);
         m_edit->setReadOnly(true);
     }
     else
     {
         ret = false;
     }

     for(int i=0; i<4; i++)
     {
         for(int j=0; j<5; j++)
         {
             button_array[j + 5*i] = new QPushButton(this);
             if( button_array[j + 5*i] != NULL )
             {
                 button_array[j + 5*i]->resize(40, 40);
                 button_array[j + 5*i]->move(10 + 50*j, 50 + 50*i);
                 button_array[j + 5*i]->setText(button_name[j + 5*i]);

                 connect(button_array[j + 5*i], SIGNAL(clicked()), this, SLOT(OnButtonClicked()));
             }
             else
             {
                 ret = false;
             }
         }
     }
     return ret;
}

 Refactoring_Calculator* Refactoring_Calculator::NewInstance()
{
     Refactoring_Calculator* ret = new Refactoring_Calculator();
     if( !(ret && ret->construct()) )
     {
         delete ret;
         ret = NULL;
     }
     return ret;
}

 void Refactoring_Calculator::show()
{
     QWidget::show();
     setFixedSize(width(), height());
}

void Refactoring_Calculator::OnButtonClicked()
{
    QPushButton* btn = (QPushButton*)sender();
    qDebug() << "OnButtonClicked()";
    qDebug() << btn->text();
}

Refactoring_Calculator::~Refactoring_Calculator()
{
    if( m_edit != NULL )
    {
        delete m_edit;
    }
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<5; j++)
        {
            if( button_array[j + i*5] != NULL )
            {
                delete button_array[j + 5*i];
            }
        }
    }
}

main.cpp文件

#include <QtGui/QApplication>
#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include "Refactoring_Calculator.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Refactoring_Calculator* cal = Refactoring_Calculator::NewInstance();
    int ret = -1;
    if( cal != NULL )
    {
        cal->show();
        ret = a.exec();
        delete cal;
    }

    return ret;
}

七、 小贴士

技术图片

八、 小结

  • 信号与槽是 Qt 中的核心机制,不同的 Qt 对象可以通过信号和槽进行通信
  • 只有 QObject 的子类才能自定义信号和槽,并且使用信号和槽的类必须在声明的最开始处使用 Q_OBJECT
  • 信号与消息处理函数在函数签名上必须一致

以上是关于010_初探 Qt 中的消息处理的主要内容,如果未能解决你的问题,请参考以下文章

初探Qt中的消息处理

第十课初探Qt的消息处理

2.QT-窗口组件(QWidget),QT坐标系统,初探消息处理(信号与槽)

2.QT-窗口组件(QWidget),QT坐标系统,初探消息处理(信号与槽)

第0-0课 - 引言

论如何设计一款端对端加密通讯软件