相关文章推荐
坏坏的茴香  ·  Graphics2D.setComposit ...·  7 月前    · 
逆袭的核桃  ·  极简 Node.js 入门 - 4.1 ...·  10 月前    · 
从容的投影仪  ·  Azure Synapse RESTAPI ...·  1 年前    · 
腹黑的跑步机  ·  使用kubectl ...·  1 年前    · 

​ 写截图时,当源码在 IDE 中,通过编译和运行后,右下加出现一个 托盘图标 ,表示程序在运行中,此时通过快捷键 F6 可顺利召唤出 截图窗口 (无标题栏 + 最大化 + 置顶)。

操作如下: 此时鼠标故意不点击此 截图窗口 托盘图标 ,仅移动,可以看到实时显示其中光标的绝对坐标的变化。 此时按下快捷键 Esc 截图窗口 并不会消失。甚是奇怪??? 但倘若是通过右键点击托盘菜单,召唤的 截图窗口 ,按下 Esc 则有关闭响应。后续再快捷键召唤 截图窗口 Esc 则总是正常的。

​ 一开始是认为程序缺少焦点导致,尝试 【QT】新弹窗默认无焦点 中两种设置焦点方法,均无效。

索性写了一个 TestHotKey 来验证这个全局热键功能,原因为何?

托盘相关代码如下

// -------------------- tray.h --------------------
class Tray : public QObject
    Q_OBJECT
public:
    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 学习,附学习由浅入深的目录。

  1. Qt绘图:Keyboard Focus in Widgets 给予启发,灵光乍现
  2. Qt界面focus焦点设置的一些体会 虽然不是原因不同,其中参考文章却有关于焦点理解的价值
  3. QT 激活窗口 未尝试,若是本文未解决,可以试试这种方法
QApplication::postEvent(target, event)则是将事件event放入目标target的事件队列中,并立即返回,在目标及其父级窗口的事件循环下一次轮询时会取出该事件进行处理。这个过程类似于一个异步调用。但也需要注意的是,由于QApplication::postEvent()是基于事件循环的机制进行处理的,所以它并不是实时的,可能会存在一定的延迟。 该实例程序使用Qt进行,windows的键盘后台监听,即使Qt桌面程序失去焦点在后台运行,也会捕捉到按键事件 这个程序使用windows的钩子(hook)实现的,Qt官方有相关的实现 关于编译,我用的是Qt5.9.7 MinGW32位,我还用了Qt 5.6.3MinGW32位,也变过去了, 更换编译环境时候可能会报错,这些问题请百度 我遇到过声明的函数提示已经声明了,我就声明了一次,办发, 把声明去了,就去可以正常便过去了 还有使用windows系统库的时候可能会链接不上,在*.pro文件里面添加windows系统库就好了 列如: LIBS += -Lc:/xx/xx -lUser32 不要想着别人的代码拿过来就能跑起来,先解决编译问题,这也是在不断地积累 qt编程之捕获按键响应按键响应一般是有获取到焦点,因此下面首先介绍一个属性,QWidget以及界面中的每个控件都有focusPolicy属性,用于更改获取焦点的方式,具体如下:Qt::TabFocus      //通过Tab键获得焦点Qt::ClickFocus     //通过单击获得焦点Qt::StrongFocus  //通过以上两种方式(即Tab键或单击)均可获得焦点Qt::No... QT界面无响应解决办法汇总无响应情况示例解决方案显卡问题方法1(笔记本适用,台式PC可能不行)方法2(适用不存在上述方法的首选图形处理器选项的台式PC)显卡驱动原因其他软件进程的干涉(如HOOK)其他可能的解决办法合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如... 3.Qt按键事件——QKeyEvent QKeyEvent是一个描述Qt键盘事件的类。当有按键按下或者松开的时候,按键事件key event将会发送消息给QWidget。Key Event包... Qtcreator,发现代码编辑极其不方便,基本的快捷键Ctrl+C, Ctrl+V,全选Ctrl+A,以及代码对齐Ctrl+I都用不了,并且,在QT Creater-&gt;Tools-&gt;Options... 里找到environment-&gt;Keyboard,重设置了,也不行。        在网上找帖子阅读,也找到方法,突然在别人的只言片语当中,找到灵感,在Keyboard选项... 所有的窗口都只有一个是激活的,只有激活的窗口才能获取鼠标和键盘事件,QT中的widget默认是无法接受鼠标输入事件的,如果希望捕捉键盘事件,则需要调用grabKeyboard(),如果需要捕捉当前的鼠标事件,同样的道理,grabMouseEvent(),那么当前发送的鼠标和键盘事件就会让该widget接收到。