泰州城乡建设局网站,rdm响应式网站开发,有什的自学做网站,可以在什么网站做二建题目参考#xff1a; Qt 事件(event)_w3cschool https://www.w3cschool.cn/learnroadqt/xvme1j4c.html
本地环境#xff1a; win10专业版#xff0c;64位 事件的概念
将事件抽象为一个对象#xff0c;当用户发起一个行为#xff0c;就把对应的事件加入事件队列#xff0c;对…参考 Qt 事件(event)_w3cschool https://www.w3cschool.cn/learnroadqt/xvme1j4c.html
本地环境 win10专业版64位 事件的概念
将事件抽象为一个对象当用户发起一个行为就把对应的事件加入事件队列对于系统来说每次只要处理事件队列里未处理的事件就可以了如果没用事件程序就阻塞不执行任何代码。
必要时Qt的事件也可以不进入事件队列直接处理。
与信号的区别
信号一旦发出对应的槽函数一定会被执行但是事件可以使用事件过滤器进行过滤。如果使用组件那么要关心信号槽如果自定义组件那么要关心事件。比如如果自定义一个QPushButton那么需要重写它的鼠标点击事件和键盘处理时间并在恰当的时候发出clicked()信号
如果要使用事件只要让类继承QWidget类及其子类里面定义了很多protected virtual函数然后再重写事件回调函数即可。
简单实例自定义一个Label重写鼠标移动、按压和释放事件
初始状态 在label内移动 鼠标按压 鼠标释放 代码
// eventlabel.h
#ifndef EVENTLABEL_H
#define EVENTLABEL_H#include QLabelclass QLabel;class EventLabel : public QLabel {
protected:void mouseMoveEvent(QMouseEvent *event);void mousePressEvent(QMouseEvent *event);void mouseReleaseEvent(QMouseEvent *event);
};#endif // EVENTLABEL_H// eventlabel.cpp
#include QWidget
#include QMouseEvent#include eventlabel.hvoid EventLabel::mouseMoveEvent(QMouseEvent *event) {this-setText(QString(centerh1Move: (%1, %2)/h1/center).arg(QString::number(event-x()),QString::number(event-y())));
}void EventLabel::mousePressEvent(QMouseEvent *event) {this-setText(QString(centerh1Press: (%1, %2)/h1/center).arg(QString::number(event-x()),QString::number(event-y())));
}void EventLabel::mouseReleaseEvent(QMouseEvent *event) {// 支持用c格式化字符串的方式写QStringQString msg;msg.sprintf(centerh1Release: (%d, %d)/h1/center,event-x(), event-y());this-setText(msg);
}// main.cpp
#include QApplication
#include eventlabel.hint main(int argc, char *argv[])
{QApplication a(argc, argv);EventLabel *label new EventLabel;label-setWindowTitle(DIY Label);label-resize(400, 200);// width, heightlabel-show();return a.exec();
}事件的接收与忽略
Qt的事件对象都有一个accept()和一个ignore()。对于一个事件如果子类没有处理这个事件的函数或者忽略了那么会向上传递事件给父类否则会接收事件不再传递。在事件处理函数中可以用isAccepted()查询接收状态。
不过accept()和ignore()是很少用的如果希望忽略一个事件只要调用父类的响应函数即可。如果不传给父类直接忽略可能应该执行的操作没有执行会有危险。用到它们的情况例如在窗口关闭时需要询问是否要关闭 点击Yes之后才能正常关闭。
// eventlabel.h
protected:void closeEvent(QCloseEvent *event);
private:bool continueToClose();// eventlabel.cpp
#include QMessageBox
...
void EventLabel::closeEvent(QCloseEvent *event){if(continueToClose()) {event-accept();}else {event-ignore();}
}bool EventLabel::continueToClose() {if(QMessageBox::question(this, Quit, Are you sure?,QMessageBox::Yes | QMessageBox::No,QMessageBox::No) QMessageBox::Yes){return true;}else {return false;}
}
event()函数
event()是QObject的它不是直接处理事件的而是分发给不同的事件处理器event handler。如果希望在事件分发之前做一些操作比如区分一些事件某些事件在处理之前需要做一些处理。下面的例子是当在窗口中按下tab键时做一些处理那么应该继承QWidget然后重写它的event()函数。同时如果需要自定义事件同样也要重写event()。
event()函数的返回值是bool型返回true表示被传入的事件已经被识别并且得到了处理此时QApplication会认为这个事件已经处理了然后继续处理事件队列的下一个事件返回false表示未被处理QApplication会尝试寻找这个事件的下一个处理函数。
需要注意的是前面提到的accept()和ignore()是不同事件处理器之间的沟通event()的返回值是通知QApplication的notify()函数是否处理下一个事件。
效果当按下tab键后会弹出about提示框。
// eventlabel.h
protected:bool event(QEvent *event);// eventlabel.cpp
bool EventLabel::event(QEvent *event) {if(event-type() QEvent::KeyPress) {QKeyEvent *keyEvent static_castQKeyEvent *(event);if (keyEvent-key() Qt::Key_Tab) {// 处理QMessageBox::about(this, , press Tab);return true;}}return QWidget::event(event);
}
事件过滤器
事件过滤器的作用是筛选哪些事件需要被响应就是判断哪些事件需要调用event()进行识别和分发。此时需要重写eventFilter()函数在有事件过滤器的情况下这个函数会被优先调用然后才处理事件。
这个函数的返回值也是bool返回true表示停止响应。
比如为EventLabel安装一个eventFilter希望它在面对键盘事件的时候先发出一条提示信息。 // eventlabel.h
public:EventLabel();
protected:bool eventFilter(QObject *obj, QEvent *event);// eventlabel.cpp
EventLabel::EventLabel() {// 安装事件过滤器this-installEventFilter(this);
}bool EventLabel::eventFilter(QObject *obj, QEvent *event) {if(obj this) {if(event-type() QEvent::KeyPress) {QKeyEvent *keyEvent static_castQKeyEvent *(event);//qDebug() you press: keyEvent-key();QMessageBox::about(this, , QString(%1).arg(keyEvent-key()));return true;} else {return false;}} else {// pass to parentreturn QLabel::eventFilter(obj, event);}
}
这是安装在Label上的。如果假设有个主窗口MainWindowMainWindow有个组件textEdit一个QObject对象假设不希望让textEdit处理键盘事件那么需要
在MainWindow上实现eventFilter()需要判断obj textEdit如果是的话再判断是不是KeyPress如果是的话返回true这样不会被父级的evenFilter处理执行textEdit.installEventFilter(MainWindow)表示如果有事件发送到textEdit那么先调用MainWindow-eventFilter()然后才调用textEdit.event()
注意
事件过滤器也可以安装在QApplication上这样可以过滤所有事件但是也会降低事件分发的效率。如果一个组件安装了多个过滤器那么最后一个安装的会先调用类似stack。如果在事件过滤器中delete了某个接收组件一定要将返回值设为true不然Qt仍然会分发给这个组件但实际是找不到的那么程序会崩溃事件过滤器和被安装的组件必须在同一线程否则过滤器不起作用如果安装之后两个组件到了不同的线程那么只有当二者重回到同一线程才气笑事件的调用最终都会调用QCoreApplication.notify()。因此Qt的事件处理控制权由低到高依次是重定义事件处理函数重定义event()函数为单个组件安装事件过滤器为QApplication安装事件过滤器重定义QCoreApplication.notify()
自定义事件
自定义事件需要继承QEvent同时需要提供一个QEvent::TYPE类型enum的参数作为自定义事件的类型值。Qt保留了0-999的值所以TYPE要大于999同时需要在QEvent::User和QEvent::MaxUser之间1000-65535。由于很难记住这个黍子所以使用一个函数
static int QEvent::registerEventType( int hint -1 );这个函数接受一个int如果合法直接返回如果不合法返回一个系统分配的合法值。这个函数是线程安全的不必添加另外的同步操作。
发送事件有两种方式(自定义的事件也可以)
send 事件被QCoreApplication的notify()函数直接发给receiver对象返回值是事件处理函数的返回值使用这个函数必须在栈上创建对象QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
QApplication::sendEvent(mainWindow, event);post 事件被追加到事件列表的最后等待处理。线程安全要在堆上创建对象。QApplication::postEvent(object, new MyEvent(QEvent::registerEvenType(2048)));这个对象不用手动delete是Qt自动的。postEvent()还有一个带优先级参数的版本。通过调用sendPostedEvent()可以让已提交的事件立即得到处理。
处理自定义事件也有两种方式
重写void customEvent(QEvent *event)类似重写event()直接重写eventbool CustomWidget::event(QEvent *event) {if (event-type() CustomEventType) {CustomeEvent *myEvent static_castCustomeEvent *(event);// processingreturn true;}return QWidget::event(event);
}这一块等用到了再补实例。暂时只作理解。