zoukankan      html  css  js  c++  java
  • 局部QEventLoop帮助QWidget不消失(也就是有一个局部事件循环始终在运行,导致程序被卡住那里,但仍可以接受事件。说白了就是有一个while语句死活不肯退出,直到收到退出信号)

    熟悉的陌生人

    Qt 是事件驱动的,所以当你用Qt的时候,几乎时时刻刻和 QEventLoop 打交道、,只是你可能没有意识到:

    • QCoreApplicaton::exec()
    • QApplication::exec()
    • QDialog::exec()
    • QThread::exec()
    • QDrag::exec()
    • QMenu::exec()
    • ...

    在前面列出的这些常见函数的背后,都有各自的QEventLoop,可能是我们很少有机会想到自己显式使用QEventLoop的缘故吧,对这个类似乎总是有些陌生。

      如何让 Qt 程序的 Sleep   和  QDialog 模态对话框与事件循环   两个短文中,我们可以看到 QEventLoop 的使用。那么?如何自己使用 QEventLoop 的,又有什么用呢?

    QEventLoop

    Manual 中说的很简洁

    At any time, you can create a QEventLoop object and call exec() on it to start a local event loop. From within the event loop, calling exit() will force exec() to return.

    在任何时候,你都可以创建一个QEventLoop的对象,然后调用它的exec() 来开始一个局部的事件循环。

    看Manual容易让人头大,那么,看例子吧:

    让主线程等待100ms?

    直接sleep一下行么,显然,如果你的用户不介意你的程序界面不响应用户操作,没问题!可是如果介意呢?

    此时,开启一个局部的事件循环,让其执行100ms后自己退出,似乎很不错。写来看看:

    QEventLoop eventloop;
    QTimer::singleShot(100, &eventloop, SLOT(quit()));
    eventloop.exec();
    • 创建事件循环
    • 启动定时器,让其100ms后触发事件循环的quit()槽
    • 启动事件循环

    注:让主线程等待有其他方法,此处略过。

    窗口一闪而过?

    不少人遇到过这个问题:在一个槽函数内创建了一个窗口对象,却没有看到窗口弹出来,或者看到窗口一闪而过。比如:

    void XXXX::slot1()
    {
        QDialog dlg;
        dlg.show()
    }

    当然,大家都知道原因:因为到了后面的大括号处,dlg因为出作用域,会被析构掉。解决方法很简单,增大w的生存时间即可。比如:

    • 将 dlg 作为类的成员,而不是函数的局部变量
    • 将 dlg 前面添加 static,作为静态成员
    • 将 dlg 用 new 分配到 heap 中
    • ...

    能否用 QEventLoop 来解决呢?答案是,可以

     

    void XXXX::slot1()
    {
        QDialog dlg;
        dlg.show()
        QEventLoop loop;
        connect(&dlg, SIGNAL(finished(int)), &loop, SLOT(quit()));
        loop.exec(QEventLoop::ExcludeUserInputEvents);
    }

    恩至此,问题解决。其实,这也是 QDialog::exec() 内部所做的事情,只不过此处不是模态对话框而已。

    http://blog.csdn.net/dbzhang800/article/details/6300519

    Qt源代码:

    int QEventLoop::exec(ProcessEventsFlags flags)
    {
        Q_D(QEventLoop);
        //we need to protect from race condition with QThread::exit
        QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);
        if (d->threadData->quitNow)
            return -1;
    
        if (d->inExec) {
            qWarning("QEventLoop::exec: instance %p has already called exec()", this);
            return -1;
        }
    
        struct LoopReference {
            QEventLoopPrivate *d;
            QMutexLocker &locker;
    
            bool exceptionCaught;
            LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
            {
                d->inExec = true;
                d->exit.storeRelease(false);
                ++d->threadData->loopLevel;
                d->threadData->eventLoops.push(d->q_func());
                locker.unlock();
            }
    
            ~LoopReference()
            {
                if (exceptionCaught) {
                    qWarning("Qt has caught an exception thrown from an event handler. Throwing
    "
                             "exceptions from an event handler is not supported in Qt.
    "
                             "You must not let any exception whatsoever propagate through Qt code.
    "
                             "If that is not possible, in Qt 5 you must at least reimplement
    "
                             "QCoreApplication::notify() and catch all exceptions there.
    ");
                }
                locker.relock();
                QEventLoop *eventLoop = d->threadData->eventLoops.pop();
                Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
                Q_UNUSED(eventLoop); // --release warning
                d->inExec = false;
                --d->threadData->loopLevel;
            }
        };
        LoopReference ref(d, locker);
    
        // remove posted quit events when entering a new event loop
        QCoreApplication *app = QCoreApplication::instance();
        if (app && app->thread() == thread())
            QCoreApplication::removePostedEvents(app, QEvent::Quit);
    
        while (!d->exit.loadAcquire())
            processEvents(flags | WaitForMoreEvents | EventLoopExec);
    
        ref.exceptionCaught = false;
        return d->returnCode.load();
    }
    
    void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
    {
        Q_D(QEventLoop);
        if (!d->threadData->eventDispatcher.load())
            return;
    
        QElapsedTimer start;
        start.start();
        while (processEvents(flags & ~WaitForMoreEvents)) {
            if (start.elapsed() > maxTime)
                break;
        }
    }
    
    bool QEventLoop::processEvents(ProcessEventsFlags flags)
    {
        Q_D(QEventLoop);
        if (!d->threadData->eventDispatcher.load())
            return false;
        return d->threadData->eventDispatcher.load()->processEvents(flags);
    }
  • 相关阅读:
    读javascript高级程序设计08-引用类型之Global、Math、String
    读javascript高级程序设计07-引用类型、Object、Array
    读javascript高级程序设计06-面向对象之继承
    读javascript高级程序设计05-面向对象之创建对象
    读javascript高级程序设计04-canvas
    读javascript高级程序设计03-函数表达式、闭包、私有变量
    读javascript高级程序设计02-变量作用域
    C#将Word转换成PDF方法总结(基于Office和WPS两种方案)
    【转】 C#中Finally的一个不太常见的用法
    一看就懂的ReactJs入门教程-精华版
  • 原文地址:https://www.cnblogs.com/findumars/p/7836665.html
Copyright © 2011-2022 走看看