Search code examples
qtubuntublock

Qt can not respond key Press event immediately


Environment: Ubuntu, Qt Creator

In my Qt app, I found that sometimes Qt doesn't respond to my key press event immediately, but if I wait a while, it eventually responds.

I think something is blocking the UI.

As I know, if a Qt's component (QWidget etc.) is being destroyed, the Qt UI will be blocked. I have checked my code, there is no component being destroyed at the time I'm pressing the up/down key. I really want to know is there any other things can block Qt UI.

{
    ...
    connect(webViewWidget, SIGNAL(loadfinished()), this, SLOT(addItem()));
    ...
}

void addItem()
{
    delete webViewWidget; // will this delete block UI?
    mListWidget = new ScrollWidget();
    mScrollArea = new ScrollArea(this);
    for(int i=0; i<Datalen; i++)
    {
        mListWidget->addSubItem(itemWidget);
    }
}

void keyPressEvent(QKeyEvent *event)
{
    switch(event->key)
    {
    case UP_KEY:
        scroll up;
        break;
    case DOWN_KEY:
        scroll down;
        break;
    default:
        break;
    }
}

Solution

    • Destruction of objects is usually not a concern, unless you are doing a lot of work in the destructor. Destroying a webview may take long. You probably should not be destroying it like you do. Instrument that delete (see code below) and see how long it takes.

    • Your own code may be calling APIs that block. Are you calling any third party libraries? Are you calling any wait... methods in Qt's own API?

      If you're unsure, you can instrument every slot and every reimplemented virtual method like xxxEvent(...). You'd need to instrument only slots and reimplemented QObject/QWidget methods, not every method in your code.

    • You may be producing an event storm, perhaps by posting lots of events in a loop, or by sending a lot of signals that are hooked up to slots connected via a Qt::QueuedConnection. Make sure you're not calling repaint() from within paintEvent() for example.

    The instrumentation example below uses RAII and is very easy to apply. Alternatively, you can use a profiler.

    #include <QElapsedTimer>
    #define INSTRUMENT() Instrument instr__ument(__FUNCTION__)
    #define INSTRUMENTLIM(lim) Instrument instr__ument(__FUNCTION__, (lim))
    
    class Instrument {
       QElapsedTimer timer;
       int limit;
       const char * function;
    public:
       Instrument(const char * name, int timeLimitMs = 20) : 
          function(name), limit(timeLimitMs) { timer.start(); }
       ~Instrument() {
          if (timer.elapsed() > limit) {
             qDebug("%s was slow, took %d ms", function, timer.elapsed());
          }
       }
    }
    
    void slot(...)
    {
       INSTRUMENT();
       ...
    
    }
    
    void addItem()
    {
        INSTRUMENT();
        delete webViewWidget; // will this delete block UI?
        mListWidget = new ScrollWidget();
        mScrollArea = new ScrollArea(this);
        for(int i=0; i<Datalen; i++)
        {
            mListWidget->addSubItem(itemWidget);
        }
    }