2012-06-05 25 views
0

环境:Ubuntu的,Qt Creator的Qt可以不响应按键事件立即

在我的Qt应用程序,我发现有时Qt不给我按键事件立即作出反应,但如果我等待一段时间,它最终回应。

我觉得有些东西阻塞了用户界面。我知道,如果Qt的组件(QWidget等)被破坏,Qt UI将被阻止。我检查了我的代码,当按下上/下键时,没有组件被销毁。 我真的很想知道有没有其他东西可以阻止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; 
    } 
} 
+0

展示一个简单的示例代码,你是如何准确地看到这一点。 – rubenvb

+0

我不知道哪个代码导致了这一点,我只是想知道阻止UI的哪个位置。据我所知,被毁坏的QWidget会导致这种情况。那还有别的吗?谢谢。 – user1437008

+0

@rubenvb你介意我伪装成伪码吗? – user1437008

回答

0
  • 对象的破坏通常不是一个问题,除非你在析构函数中做了很多工作。销毁webview可能需要很长时间。你可能不应该像你那样摧毁它。删除的工具(见下面的代码)并查看需要多长时间。

  • 您自己的代码可能正在调用阻塞的API。你打电话给任何第三方图书馆吗?你在调用Qt自己的API中的任何wait...方法吗?

    如果你不确定,就可以检测每条插槽重新实现的虚方法xxxEvent(...)。您需要仪器只有插槽和重新实现QObject/QWidget方法,而不是代码中的每个方法。

  • 您可能正在制作一个事件风暴,可能是通过在一个循环中发布大量事件,或者通过发送大量连接到通过Qt::QueuedConnection连接的插槽的信号。例如,确保你没有从paintEvent()内拨打repaint()

下面的仪表示例使用RAII,并且很容易应用。或者,您可以使用分析器。

#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); 
    } 
} 
+0

感谢您的回复。我有点疑惑,你说:确保你没有从paintEvent()中调用repaint()。在我的应用程序代码中,我发现我在painEvent()中重绘了scrollare,这是否会导致UI块?如果是这样,当webViewWidget发出信号时,我应该怎样重绘滚动条:loadfinished()? – user1437008

+0

我的意思是你不应该调用'repaint()'方法。一个'paintEvent()'只能做一些事情:更新对象的内部状态,自己做绘画,如果你想让你继承的BaseClass完成一些绘画,则调用'BaseClass :: paintEvent()'。永远不要从'paintEvent()'调用'repaint()'。 –

1

一般来说,处理这些被按下的键放到应用程序的事件队列之前的所有其他事件之前,将不会处理您的按键事件。

因此,它可能是任何种类的事件还没有完成处理。也许你可以找出是否有任何事件,例如通过使用QApplication::hasPendingEvents或从QApplication继承并在添加或完全处理事件时添加调试输出。

+0

感谢您的回复。我已经使用QApplication :: hasPendingEvents来检查,实际上有事件挂起,但我仍然需要检查它是什么事件。我会继续调查。 – user1437008