在同一线程即处理界面的UI,又要处理加载对话框的paint事件,去显示正在加载,发现加载对话框显示不出来

本文探讨了使用QTreeWidget实现实时目录树加载时的优化技巧。在主线程中,通过在for循环内调用QCoreApplication::processEvents(),有效地避免了UI阻塞,实现了平滑的加载体验。文章深入解析了事件处理机制,并提供了具体代码示例。

在用QTreeWidget实现目录树时,点击目录,逐级展开需要一个加载对话框,表明正在加载数据,此时主线程一直在for循环里添加下一级目录的子节点,导致没有工作线程去执行加载对话框的paintEvent的绘制,就没有加载效果出现。

如下程序代码:

在for循环里,添加        QCoreApplication::processEvents();//添加处理事件

每添加一次节点,就调 QCoreApplication::processEvents();去处理其他需要响应的事件,就如单核CPU,多线程正在使用时,每个线程只使用一段CPU的时间片,时间一到就会被切出去,而这里是通过事件消息循环,去处理其他事件的消息

void CLocalDirTreeWgt::UpdateLeftTree(QTreeWidgetItem *item)
{
    m_bLeftChange = true;
    Qt::CheckState cs = item->checkState(0);
    Qt::CheckState checkstate;

    FILE_NODE iteminfo = item->data(0, FILE_TYPE).value<FILE_NODE>();
    m_path = iteminfo.qFilePath;

    /*添加path路径文件*/
    QDir dir(m_path);          //遍历各级子目录
    if (ShowHiddenFolderAndFile() && ShowHiddenProtectedOSSystemFile())
    {
        dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); //先过滤目录和文件
    }
    else if (ShowHiddenFolderAndFile())
    {
        dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden); //先过滤目录和文件
    }
    else if (ShowHiddenProtectedOSSystemFile())
    {
        dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::System); //先过滤目录和文件
    }
    else
    {
        dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); //先过滤目录和文件
    }

    dir.setSorting(QDir::DirsFirst);//优先显示目录
    QFileInfoList folder_list = dir.entryInfoList();   //获取当前所有目录


    FILE_NODE info;

    for (int i = 0; i != folder_list.size(); i++)         //自动递归添加各目录到上一级目录
    {
        QCoreApplication::processEvents();//添加处理事件

        QFileInfo folderinfo = folder_list.at(i);

        if (folderinfo.isDir() && !folderinfo.isSymLink())
        {
            QString namepath = folder_list.at(i).absoluteFilePath();    //获取路径

            QString name = folderinfo.fileName();      //获取目录名

            if (ChildWidgetItemIsCombinedTree(item, namepath))
            {
                continue;
            }

            info.bFolder = true;
            info.qFilePath = namepath;
            QVariant var;
            var.setValue(info);
            QTreeWidgetItem* childDirItem = new QTreeWidgetItem(QStringList() << name);

            QIcon icon = GetFolderFileIcon(namepath);
            childDirItem->setIcon(0, icon);
            childDirItem->setText(0, name);
            childDirItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
            childDirItem->setData(0, FILE_TYPE, var);

            if (cs == Qt::PartiallyChecked)
            {
                //checkstate = GetCheckStateFormLeftTree(namepath);
                //获取当前项item是否绑定了节点数据
                SELECT_TREE_NODE *selectItemNode = item->data(0, NODE_PTR).value<SELECT_TREE_NODE*>();
                if (NULL != selectItemNode)
                {
                    checkstate = GetWidgetItemState(selectItemNode, childDirItem);
                }

                childDirItem->setCheckState(0, checkstate);
            }
            else
            {
                childDirItem->setCheckState(0, cs);
            }

            item->addChild(childDirItem);              //将当前目录添加成path的子项    

            QString qstrpath = info.qFilePath;
            qstrpath.replace("/", "\\");
            bool bHaveSubDir = isHaveSubDir(qstrpath);
            if (bHaveSubDir)
            {
                QTreeWidgetItem * childChildItem = new QTreeWidgetItem;
                childChildItem->setText(0, FAKER_ITEM_TEXT);
                childDirItem->addChild(childChildItem);
            }
        }
        else
        {
            INT64 filesize = folderinfo.size();
            QString name2 = folderinfo.fileName();

            if (ChildWidgetItemIsCombinedTree(item, folderinfo.absoluteFilePath()))
            {
                continue;
            }

            info.bFolder = false;
            info.qFilePath = folderinfo.absoluteFilePath();
            QVariant var;
            var.setValue(info);

            QString filePath = folderinfo.filePath();
            filePath.replace("/", "\\");
            QIcon icon = GetFolderFileIcon(filePath);
            QTreeWidgetItem *fileWgtItem = new QTreeWidgetItem();
            fileWgtItem->setCheckState(0, Qt::Unchecked); //初始状态没有被选中
            fileWgtItem->setIcon(0, icon);
            fileWgtItem->setText(0, name2);
            fileWgtItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);   //设置树形控件子项的属性
            fileWgtItem->setData(0, FILE_TYPE, var);
            if (cs == Qt::PartiallyChecked)
            {
                //获取当前项item是否绑定了节点数据
                SELECT_TREE_NODE *selectItemNode = item->data(0, NODE_PTR).value<SELECT_TREE_NODE*>();
                if (NULL != selectItemNode)
                {
                    checkstate = GetWidgetItemState(selectItemNode, fileWgtItem);
                }

                fileWgtItem->setCheckState(0, checkstate);
            }
            else
            {
                fileWgtItem->setCheckState(0, cs);
            }
            item->addChild(fileWgtItem);
            fileWgtItem->setHidden(true);
        }
    }    

}

//事件处理函数

void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)
{
    QThreadData *data = QThreadData::current();
    if (!data->hasEventDispatcher())
        return;
    data->eventDispatcher.load()->processEvents(flags);
}

bool QWindowsGuiEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
{
    const QEventLoop::ProcessEventsFlags oldFlags = m_flags;  //将原来的事件标记保留
    m_flags = flags;                  //存放新的事件标记
    const bool rc = QEventDispatcherWin32::processEvents(flags);  //处理新的事件标记
    m_flags = oldFlags;         //处理完后返回原来的事件标记
    return rc;
}

 

bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
{
    Q_D(QEventDispatcherWin32);

    if (!d->internalHwnd) {
        createInternalHwnd();
        wakeUp(); // trigger a call to sendPostedEvents()
    }

    d->interrupt = false;
    emit awake();

    bool canWait;
    bool retVal = false;
    bool seenWM_QT_SENDPOSTEDEVENTS = false;
    bool needWM_QT_SENDPOSTEDEVENTS = false;
    do {
        DWORD waitRet = 0;
        HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
        QVarLengthArray<MSG> processedTimers;
        while (!d->interrupt) {
            DWORD nCount = d->winEventNotifierList.count();
            Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);

            MSG msg;
            bool haveMessage;

            if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
                // process queued user input events
                haveMessage = true;
                msg = d->queuedUserInputEvents.takeFirst();
            } else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
                // process queued socket events
                haveMessage = true;
                msg = d->queuedSocketEvents.takeFirst();
            } else {
                haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);
                if (haveMessage) {
                    if ((flags & QEventLoop::ExcludeUserInputEvents)
                        && ((msg.message >= WM_KEYFIRST
                             && msg.message <= WM_KEYLAST)
                            || (msg.message >= WM_MOUSEFIRST
                                && msg.message <= WM_MOUSELAST)
                            || msg.message == WM_MOUSEWHEEL
                            || msg.message == WM_MOUSEHWHEEL
                            || msg.message == WM_TOUCH
#ifndef QT_NO_GESTURES
                            || msg.message == WM_GESTURE
                            || msg.message == WM_GESTURENOTIFY
#endif
                            || msg.message == WM_CLOSE)) {
                        // queue user input events for later processing
                        d->queuedUserInputEvents.append(msg);
                        continue;
                    }
                    if ((flags & QEventLoop::ExcludeSocketNotifiers)
                        && (msg.message == WM_QT_SOCKETNOTIFIER && msg.hwnd == d->internalHwnd)) {
                        // queue socket events for later processing
                        d->queuedSocketEvents.append(msg);
                        continue;
                    }
                }
            }
            if (!haveMessage) {
                // no message - check for signalled objects
                for (int i=0; i<(int)nCount; i++)
                    pHandles[i] = d->winEventNotifierList.at(i)->handle();
                waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE);
                if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) {
                    // a new message has arrived, process it
                    continue;
                }
            }
            if (haveMessage) {
                // WinCE doesn't support hooks at all, so we have to call this by hand :(
                if (!d->getMessageHook)
                    (void) qt_GetMessageHook(0, PM_REMOVE, (LPARAM) &msg);

                if (d->internalHwnd == msg.hwnd && msg.message == WM_QT_SENDPOSTEDEVENTS) {
                    if (seenWM_QT_SENDPOSTEDEVENTS) {
                        // when calling processEvents() "manually", we only want to send posted
                        // events once
                        needWM_QT_SENDPOSTEDEVENTS = true;
                        continue;
                    }
                    seenWM_QT_SENDPOSTEDEVENTS = true;
                } else if (msg.message == WM_TIMER) {
                    // avoid live-lock by keeping track of the timers we've already sent
                    bool found = false;
                    for (int i = 0; !found && i < processedTimers.count(); ++i) {
                        const MSG processed = processedTimers.constData()[i];
                        found = (processed.wParam == msg.wParam && processed.hwnd == msg.hwnd && processed.lParam == msg.lParam);
                    }
                    if (found)
                        continue;
                    processedTimers.append(msg);
                } else if (msg.message == WM_QUIT) {
                    if (QCoreApplication::instance())
                        QCoreApplication::instance()->quit();
                    return false;
                }

               //在这里过滤事件,翻译,派发消息,去响应其他事件

                if (!filterNativeEvent(QByteArrayLiteral("windows_generic_MSG"), &msg, 0)) {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            } else if (waitRet - WAIT_OBJECT_0 < nCount) {
                d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
            } else {
                // nothing todo so break
                break;
            }
            retVal = true;
        }

        // still nothing - wait for message or signalled objects
        canWait = (!retVal
                   && !d->interrupt
                   && (flags & QEventLoop::WaitForMoreEvents));
        if (canWait) {
            DWORD nCount = d->winEventNotifierList.count();
            Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
            for (int i=0; i<(int)nCount; i++)
                pHandles[i] = d->winEventNotifierList.at(i)->handle();

            emit aboutToBlock();
            waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
            emit awake();
            if (waitRet - WAIT_OBJECT_0 < nCount) {
                d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
                retVal = true;
            }
        }
    } while (canWait);

    if (!seenWM_QT_SENDPOSTEDEVENTS && (flags & QEventLoop::EventLoopExec) == 0) {
        // when called "manually", always send posted events
        sendPostedEvents();
    }

    if (needWM_QT_SENDPOSTEDEVENTS)
        PostMessage(d->internalHwnd, WM_QT_SENDPOSTEDEVENTS, 0, 0);

    return retVal;
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值