简 述: 全局热键召唤的新窗口后,?不点击此程序的托盘图标和相关窗口(但是可以移动,开启光标跟踪),只点击键盘按键却无响应。但?点击过后,却可以响应⌨按键了。解决此怪异问题。
[TOC]
本文初发于 “偕臧的小站“,同步转载于此。
? win10 21H2
? Qt 5.12.11
背景
写截图时,当源码在 IDE 中,通过编译和运行后,右下加出现一个托盘图标
,表示程序在运行中,此时通过快捷键 F6
可顺利召唤出截图窗口
(无标题栏 + 最大化 + 置顶)。
操作如下: 此时鼠标故意不点击此截图窗口
和托盘图标
,仅移动,可以看到实时显示其中光标的绝对坐标的变化。此时按下快捷键 Esc
,截图窗口
并不会消失。甚是奇怪??? 但倘若是通过右键点击托盘菜单,召唤的 截图窗口
,按下 Esc
则有关闭响应。后续再快捷键召唤 截图窗口
和 Esc
则总是正常的。
分析
一开始是认为程序缺少焦点导致,尝试 【QT】新弹窗默认无焦点 中两种设置焦点方法,均无效。
索性写了一个 TestHotKey 来验证这个全局热键功能,原因为何?
托盘相关代码如下
// -------------------- tray.h --------------------class Tray : public QObject{ Q_OBJECTpublic: explicit Tray(QObject *parent = nullptr);public slots: void onScreenShot();private: QAction* m_screenShot; QAction* m_quit; QMenu* m_menuTary; QSystemTrayIcon* m_sysTary; QHotkey* m_hkScrnShot; // 热键};// -------------------- tray.cpp --------------------Tray::Tray(QObject *parent) : QObject(parent) , m_screenShot(nullptr) , m_quit(nullptr) , m_menuTary(nullptr) , m_sysTary(nullptr) , m_hkScrnShot(new QHotkey(QKeySequence("f2"), true, qApp)){ m_screenShot = new QAction(tr("ScreenShot"), this); m_quit = new QAction(tr("Quit"), this); m_menuTary = new QMenu(); m_menuTary->addAction(m_screenShot); m_menuTary->addSeparator(); m_menuTary->addAction(m_quit); m_sysTary = new QSystemTrayIcon(this); m_sysTary->setIcon(QIcon(":/resources/PicShot_32.svg")); m_sysTary->setToolTip(tr("PicShot Test")); m_sysTary->setContextMenu(m_menuTary); m_sysTary->setVisible(true); // 快捷键响应 connect(m_hkScrnShot, &QHotkey::activated, this, &Tray::onScreenShot); // 右键菜单触发 connect(m_screenShot, &QAction::triggered, this, &Tray::onScreenShot); connect(m_quit, &QAction::triggered, []() {qApp->quit();});}void Tray::onScreenShot(){ auto& ins = Widget::instance(); ins.show();}
截图窗口代码如下:
// -------------------- tray.cpp --------------------Widget::Widget(QWidget *parent) : QWidget(parent){ setFocusPolicy(Qt::StrongFocus); QDesktopWidget *desktop = QApplication::desktop(); // 获取桌面的窗体对象 const QRect geom = desktop->geometry(); // 多屏的矩形取并集 setWindowFlags(Qt::FramelessWindowHint /*| Qt::WindowStaysOnTopHint */| windowFlags()); // 去掉标题栏 + 置顶// setAttribute(Qt::WA_ShowWithoutActivating,true);// setFocusPolicy(Qt::StrongFocus);// setFixedSize(QSize(geom.size().width() / 4, geom.size().height())); setFixedSize(QSize(512, geom.size().height())); setMouseTracking(true);}void Widget::keyPressEvent(QKeyEvent *event){ if (event->key() == Qt::Key_Escape) { qDebug() << "Key_Escape"; hide(); } else if (event->key() == Qt::Key_A) { qDebug() << "Key_A"; }}void Widget::paintEvent(QPaintEvent *event){ QPainter pa(this); pa.drawText(100, 200, QString("m_pos(%1, %2)").arg(m_pos.x()).arg(m_pos.y()));}
突破点在 Widget::keyPressEvent()
,想知道到底对应状态是否会响应键盘按键,确认此便可以找到原因。
根因解决
此次思路感觉有点欧亨利式:
知乎此篇 —> tab 切换窗口 —> 联想到 激活窗口 —> google key: focus 变成 窗口激活, —> 去掉置顶后尝试(去掉干扰因素) —> ok
使用全局热键召唤出来的截图窗口,此时不属于激活窗口。 解决方法,再 show() 后,将此窗口设置为激活窗口即可。
void Tray::onScreenShot() { auto& ins = Widget::instance(); ins.show(); // 解决方案: show() 之后,设置为激活窗口即可 if(!ins.isActiveWindow()) ins.activateWindow();}
系列地址
QtExamples 『TestHotKey』
欢迎 star
⭐ 和 fork
?这个系列的 C++ / QT / DTK
学习,附学习由浅入深的目录。
参考
- Qt绘图:Keyboard Focus in Widgets 给予启发,灵光乍现
- Qt界面focus焦点设置的一些体会 虽然不是原因不同,其中参考文章却有关于焦点理解的价值
- QT 激活窗口 未尝试,若是本文未解决,可以试试这种方法
本文转自: https://ifmet.cn/posts/44eabb4d/
本站仅做收录,版权归原作者所有。