截取QEvent并且优先处理

QEvent事件

案例:全局快捷键处理

一、 前言

        在一个复杂的大型QT项目中,会存在很多QAction,并为之设置快捷键,若要自定义和QAction相同的快捷键、或者全局的快捷键(类似于Ctrl+A、Ctrl+S之类),就可能被冲突掉

 

二、快捷键响应过程

1)、去官网下载相应版本的PDB文件,链接https://download.qt.io/online/qtsdkrepository/windows_x86/desktop/,   找到相应的版本号qt5_597/ (代表Qt 5.9.7)  

2、导入PDB后,随便在界面上按一个键,在QApplication中会看到如下堆栈消息

(1)、在QT开启了事件循环(QEventLoop),当我们按键就会发送sendPostedEvents  (注意此函数也可以手动调用)

(2)、QT会把所有的事件解析一次,解析成相应的类型,不同的消息,调用不同的process函数

(3)、注意按键事件,会优先处理一次handleShortcutEvent

(4)、在handleShortcutEvent中,先传递ShortcutOverride事件(这个事件会比Shortcut事件优先相应)

 

三、实现

1、重新一个Application :public  QApplication,  处理QEvent::ShortcutOverride

bool Application::notify(QObject *obj, QEvent *event)
{
	if (event->type() == QEvent::ShortcutOverride)
	{
		
		QKeyEvent *keyEvent = (QKeyEvent *)event;
		if (qApp->modalWindow() == nullptr)
		{
			QObject *receiver = QWidget::keyboardGrabber();
			if (!receiver)
			{
				receiver = qApp->focusObject();
			}
            // 注:编辑框按键是不需要响应快捷键的
			QLineEdit *lineEdit = qobject_cast<QLineEdit *>(receiver);
			if (lineEdit == nullptr)
			{
				// 处理快捷键事件
				if (event->isAccepted())
				{
					return true;
				}
			}
		}

	}
	return Application::notify(obj, event);
}

2·、为什么不在QMainWindow里面重载event(QEvent *event) 再截取QEvent::ShortcutOverride事件

     Qt信号机制,在Notify中分发,然后在QObject处理,然后一层一层的向上分发

     1)、无法避免在分发过程中被截断 (一般不会)

      2)、部分窗口不存在parent的话,传递不到QMainWindow(例如:悬浮状态的QDockwidget)

 

四、优化    

1、在使用过程中,非模态弹窗、QWindow也响应快捷键(其实不应该响应)

2、在notify中打断点,对于不同的对象,观察obj会出现4种情况

      A:QObject:是一个QWidgetWindow, m_wiget是QMainWindw (在QMainWindow按键)

      B:QObject:是一个QWidgetWindow, m_wiget是QDialog(弹框)

      C:  QObject:   是一个QWidgetWindow, m_wiget是QDockWidget(悬浮状态的QDock,停靠状态响应A)

      D:  QObject:   是一个QWindow, 没有m_wiget (在QWindow中按键)

3、如果能吧QObject转化成QWidgetWindow,并判断获取到m_widget就能解决,我们自定义面板是否能响应快捷键了

4、qwidgetwindow_p.h 是一个受保护的类,但是QT还是支持引用的,博主的做法是,直接拷贝过来引用(QT dll里面支持,只要不修改源码,就不影响使用)

注:这边吧响应的头文件引用方法修改了

4、只处理QDockWidget、和QMainWindow的按键事件--可以根据自己自定义修改

bool Application::notify(QObject *obj, QEvent *event)
{
	if (event->type() == QEvent::ShortcutOverride)
	{
		// 只处理Dock, MainWindow
		QWidgetWindow *window = dynamic_cast<QWidgetWindow *>(obj);
		if (!window)
		{
            // 这里再次进入消息循环,不能return
			return QApplication::notify(obj, event);
		}


		QDockWidget *dockWidget = dynamic_cast<QDockWidget*>(window->widget());
		if (!dockWidget)
		{
			QMainWindow *pWindow = dynamic_cast<QMainWindow*>(window->widget());
			if (!pWindow)
			{
                // 这里再次进入消息循环,不能return
				return QApplication::notify(obj, event);
			}
		}

		QKeyEvent *keyEvent = (QKeyEvent *)event;
		if (qApp->modalWindow() == nullptr)
		{
			QObject *receiver = QWidget::keyboardGrabber();
			if (!receiver)
			{
				receiver = qApp->focusObject();
			}
            // 注:编辑框按键是不需要响应快捷键的
			QLineEdit *lineEdit = qobject_cast<QLineEdit *>(receiver);
			if (lineEdit == nullptr)
			{
				// 处理快捷键事件
				if (event->isAccepted())
				{
					return true;
				}
			}
		}

	}
	return Application::notify(obj, event);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值