【问题标题】:How to keep Qt Widgets responsive to keyboard and mouse while handling Windows Events?如何在处理 Windows 事件时保持 Qt 小部件对键盘和鼠标的响应?
【发布时间】:2013-06-12 22:30:42
【问题描述】:

我的应用程序有一个 QLineEdit 和一个 QPushButton 不能正确响应键盘和鼠标的输入(QLineEdit 没有接收到键盘输入,QLineEditQPushButton 都没有接收到鼠标输入)当我的应用处理这些 Windows 事件时:

bool MainWindow::winEvent(MSG *msg, long *result)
{
    HWND hWnd = msg->hwnd;
    UINT message = msg->message;
    WPARAM wParam = msg->wParam;
    LPARAM lParam = msg->lParam;

    bool retval = true;
    LRESULT lRet = 0;

    switch(message)
    {
    case WM_PAINT:
    {
        HDC hDC = GetWindowDC(hWnd);
        PaintCustomCaption(hWnd, hDC); //Method responsible to draw the image at the non client area
        DeleteDC(hDC);
        break;
    }
    case WM_NCHITTEST:
    {
        lRet = HitTestNCA(hWnd, lParam); //Method responsible to deal with the window resizing and moving
        DwmDefWindowProc(hWnd, message, wParam, lParam, &lRet);
        break;
    }
    case WM_NCCALCSIZE:
    {
        break;
    }
    default:
    {
        retval = false;
        DwmDefWindowProc(hWnd, message, wParam, lParam, &lRet);
        break;
    }
    }

    *result = lRet;
    if(retval) return true;

    return QWidget::winEvent(msg, result);
}

如果我删除此类代码,我的 Qt 小部件可以正常工作,但我需要这些代码,因为我的应用正在窗口的非客户区绘制图像。

是否可以处理上面列出的 Windows 事件以保持我的 Qt 小部件对键盘和鼠标的响应?

【问题讨论】:

  • 我会尝试的第一件事是删除WM_NCHITTEST(可能还有default: case),看看是否有任何改变。我怀疑由于某种原因,您的事件可能会因为在到达您的控件之前到达非客户区而被丢弃。顺便说一句,为什么您的default: 案例调用DwmDefWindowProc
  • 通过删除所有switch,我的控件再次变得响应,但问题是:我需要在非客户区绘制图像。
  • 我并不是指所有这些——我只是指WM_NCHITTEST 的情况。稍后你会担心它是否能满足你的需要——这只是为了弄清楚你的控件为什么会冻结。如果在删除这个特定的case 后它们会解冻,你就会知道你的WM_NCHITTEST 响应是问题的根源。
  • @j_kubik 这是我的结果:通过删除WM_NCHITTEST:控件保持无响应。通过删除WM_NCCALCSIZE 也:控件保持无响应。通过从switch 中删除WM_NCHITTESTWM_NCCALCSIZEWM_PAINT:控件完全负责,但没有图像绘制。

标签: c++ qt qlineedit qpushbutton


【解决方案1】:

您可以尝试在处理这些窗口事件时定期调用QCoreApplication::processEvents()

【讨论】:

    【解决方案2】:

    您需要分析该代码并加快其速度,以免阻塞事件循环,或者您需要在单独的线程中运行该代码。

    对于分析,我建议查看 valgrind、callgrind 和 kcachegrind。

    至于线程,大多数 Qt 应用程序默认是单线程的,所以如果你不尽快将处理返回到事件循环,UI 事件将在事件循环中阻塞,直到你返回才得到处理处理到事件循环。

    在 Qt 中创建新线程非常容易。请参阅 QThread 上的 Qt 文档中的此示例:

    void MyObject::putWorkerInAThread()
    {
        Worker *worker = new Worker;
        QThread *workerThread = new QThread(this);
    
        connect(workerThread, &QThread::started, worker, &Worker::doWork);
        connect(workerThread, &QThread::finished, worker, &Worker::deleteLater);
        worker->moveToThread(workerThread);
    
        // Starts an event loop, and emits workerThread->started()
        workerThread->start();
    }
    

    【讨论】:

    • Windows 事件不是异步的?
    • 如果您将clicked 信号连接到您自己代码中的某些内容,则clicked 信号可能会异步触发,但它所连接的代码在控制权返回之前不会执行事件循环。
    • 绘制窗口的非客户区域不太可能产生这样的问题 - 您自己处理的事件更有可能以某种方式连接到不活动的小部件。
    • +1 通过正确的方式创建线程,但这不能解决我的问题,我不能接受这个答案是正确的。
    猜你喜欢
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多