QT事件详解

14 篇文章 0 订阅

QT事件详解


1.事件处理介绍

​ Qt 程序需要在main()函数创建一个QCoreApplication对象,然后调用它的exec()函数。这个函数就是开始 Qt 的事件循环。在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent。在事件对象创建完毕后,Qt 将这个事件对象传递给QObjectevent()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler)。

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QMouseEvent>
class EventLabel : public QLabel
{
protected:
        void mouseMoveEvent(QMouseEvent *event);     //声明明三个事件函数
        void mousePressEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
};

void EventLabel::mouseMoveEvent(QMouseEvent *event)    //鼠标移动事件函数,显示出鼠标的坐标
{
    this->setText(QString("<center><h1>Move: (%1, %2)</h1></center>")
                          .arg(QString::number(event->x()), QString::number(event->y())));
}

void EventLabel::mousePressEvent(QMouseEvent *event)          //按下时,获得鼠标坐标
{
        this->setText(QString("<center><h1>Press: (%1, %2)</h1></center>")
                       .arg(QString::number(event->x()), QString::number(event->y())));
}

void EventLabel::mouseReleaseEvent(QMouseEvent *event)   //松开鼠标时,获取鼠标的坐标
{
        QString msg;
        msg.sprintf("<center><h1>Release: (%d, %d)</h1></center>",
                                event->x(), event->y());
        this->setText(msg);
}
//上述需要点击鼠标移动才能出发mouseMoveEvent时间,可以设置为什么要点击鼠标之后才能在mouseMoveEvent()函数中显示鼠标坐标值?这是因为QWidget中有一个mouseTracking属性,该属性用于设置是否追踪鼠标。只有鼠标被追踪时,mouseMoveEvent()才会发出。如果mouseTracking是 false(默认即是),组件在至少一次鼠标点击之后,才能够被追踪,也就是能够发出mouseMoveEvent()事件。如果mouseTracking为 true,则mouseMoveEvent()直接可以被发出
int main(int argc, char *argv[])
{
        QApplication app(argc, argv);
        EventLabel *label = new EventLabel;
        label->setWindowTitle("MouseEvent Demo");
        label->resize(300, 200);
    	label->setMouseTracking(true);
        label->show();
        return app.exec();
}

1.知识点:

//样例QString.arg函数
this->setText(QString("<center><h1>Press: (%1, %2)</h1></center>")
              .arg(QString::number(event->x()), QString::number(event->y())));
//使用的是QString("[%1, %2]").arg(x, y);    
//使用 x 替换 %1,y 替换 %2,因此,这个语句生成的QString为 [x, y]。
//样例 static_cast<type-id>(expression)
//解释:static_cast是一个c++运算符,功能是把一个表达式转换为某种类型,但没有运行时类型检查来保证转换的安全性。  
int i;
float f = 166.97;
i = static_cast<int>(f);   //i值为166

2.下面继承分析

class CustomButton : public QPushButton
{
    Q_OBJECT
public:
    CustomButton(QWidget *parent) : QPushButton(parent)
    {
    }
protected:
    void mousePressEvent(QMouseEvent *event)
    {
        qDebug() << "CustomButton";
    }
};

class CustomButtonEx : public CustomButton
{
    Q_OBJECT
public:
    CustomButtonEx(QWidget *parent) : CustomButton(parent)
    {
    }
protected:
    void mousePressEvent(QMouseEvent *event)
    {
        qDebug() << "CustomButtonEx";
    }
};

class CustomWidget : public QWidget
{
    Q_OBJECT
public:
    CustomWidget(QWidget *parent) : QWidget(parent)
    {
    }
protected:
    void mousePressEvent(QMouseEvent *event)
    {
        qDebug() << "CustomWidget";
    }
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0) : QMainWindow(parent)
    {
        CustomWidget *widget = new CustomWidget(this);
        CustomButton *cbex = new CustomButton(widget);
        cbex->setText(tr("CustomButton"));
        CustomButtonEx *cb = new CustomButtonEx(widget);
        cb->setText(tr("CustomButtonEx"));
        QVBoxLayout *widgetLayout = new QVBoxLayout(widget);
        widgetLayout->addWidget(cbex);
        widgetLayout->addWidget(cb);
        this->setCentralWidget(widget);
    }
protected:
    void mousePressEvent(QMouseEvent *event)
    {
        qDebug() << "MainWindow";
    }
};

当CustButton继承QPushButton;而CustButtonEx继承CustButton;同时都在MainWidow中作为控件显示。仅仅作为单机各个控件,都是仅仅打印自己重写的mousePressEvent()事件;如果想要让孩子同时可以执行父亲相同的事件,需要重新添加父亲的事件 CustButton::mousePressEvent(ent); 添加到孩子执行的事件函数中;

其次,还有另一中方案,就是使用 accept()ignore() 函数,其中 ent->accept() 是默认状态,不做处理,仅仅执行自己重写部分。 ignore() 说明我们想让事件继续传播,所以就传递给父类组件,同时启动父类的事件。

事件的传播是在组件层次上面的,而不是依靠类继承机制。

2.事件过滤器

准确地说事件过滤器就是在父类窗口上,查询子类控件的事件的类型进而处理的一种方式

介绍:

这个函数返回一个 bool 类型,如果你想将参数 event 过滤出来,比如,不想让它继续转发,就返回 true,否则返回 false。事件过滤器的调用时间是目标对象(也就是参数里面的watched对象)接收到事件对象之前。也就是说,如果你在事件过滤器中停止了某个事件,那么,watched对象以及以后所有的事件过滤器根本不会知道这么一个事件。

class MainWindow : public QMainWindow 
{
public:
	MainWindow();
protected:
	bool eventFilter(QObject *obj, QEvent *event);
private:
	QTextEdit *textEdit;
}


MainWindow :: MainWindow()
{
    textEdit = new QTextEdit;
    setCentraWidget(textEdit);
    //installEventFilter 是由需要过滤的实例化对象调用的,以父类为基础
    textEdit->installEventFilter(this);
}

bool MainWindow :: eventFilter(QObject *obj, QEvent *event)
{
    if(obj == textEdit)
    {
        if(event->type() == QEvent::KeyPress)
        {
            QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        	qDebug("Ate key press");
            return true;	
            //也就是过滤掉textEdit的KeyPress事件
        }
        else
        {
            return false;
        }
    }
    else
    {
        //pass the event on to the parent class
        return QMainWindow::eventFilter(obj, event);
    }
}

eventFilter()函数相当于创建了过滤器,然后我们需要安装这个过滤器。安装过滤器需要调用QObject::installEventFilter()`函数

//用于安装过滤器函数
void QObject::installEventFilter(QObject *filterObj);
//用于移除过滤器
void QObject::removeEventFilter(QObject *filterObj);

如果我们向一个对象安装多个事件处理器,只能调用多次 installEventFilter() 函数,如果一个对象存在多个事件过滤器,那么最后一个安装的第一个执行,也就是后进先执行的顺序。

注意:

注意,如果你在事件过滤器中 delete 了某个接收组件,务必将函数返回值设为 true。否则,Qt 还是会将事件分发给这个接收组件,从而导致程序崩溃

事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效

3.自定义事件举例

自定义事件处理流程

首先,继承QEvent;

其次,定义事件类型,通过registerEventType()函数进行自动创建一个全局唯一的事件类型;

再其次,使用sendEvent()[同步处理] 和 postEvent()函数[异步处理] 发送事件;

最后,重写QObject::event()方法处理自定义事件

但是,自定义事件用在何处?具体什么用处?还不得而知

参考网址:自定义事件

参考网址:自定义事件-程序已实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值