Qt Windows同一线程中槽函数未返回,后续又陆续进入了该槽函数,求大神解惑这是不是Qt的BUG

qiushot 2020-04-22 03:12:08
该程序在QtCreator5.3.0中运行
main.cpp文件
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

mainwindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
signals:
public slots:
void OnAct(bool);
};
#endif // MAINWINDOW_H


mainwindow.cpp文件
#include "mainwindow.h"
#include <QToolBar>
#include <QThread>
#include <QAction>
#include <QDebug>
#include <QDesktopServices>
#include <QUrl>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QToolBar *tb = new QToolBar();
this->addToolBar(tb);
QAction* act = tb->addAction("help");

connect(act,SIGNAL(triggered(bool)) ,this,SLOT(OnAct(bool)));
}
void MainWindow::OnAct(bool)
{
qDebug()<<"currentThreadId:"<<QThread::currentThreadId();

QString url ("E:/abc.txt");

bool bOk = QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode));


qDebug()<<"end";
}

快速连续点击help工具按钮,运行结果如下

正常执行流程应该是
currentThreadId: 0x303c
end
currentThreadId: 0x303c
end

我测试的结果是由于 QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode));函数引起,必须能正确打开文件,函数错误不会产生该现象,请教各路大神为什么同一个线程中槽函数return之前为什么又可以进入该曹函数。
...全文
588 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
sn314 2020-04-25
  • 打赏
  • 举报
回复
谢谢分享。。。
mideum 2020-04-24
  • 打赏
  • 举报
回复
引用 8 楼 dinjay 的回复:
可以编译源码,debug看一下openUrl里面怎么实现的。

这用不着编译源码,找到qwindowsservices.cpp就行
实际就是调用ShellExecute
dinjay 2020-04-24
  • 打赏
  • 举报
回复

bool QDesktopServices::openUrl(const QUrl &url)
{
QOpenUrlHandlerRegistry *registry = handlerRegistry();
QMutexLocker locker(®istry->mutex);
static bool insideOpenUrlHandler = false;

if (!insideOpenUrlHandler) {
QOpenUrlHandlerRegistry::HandlerHash::ConstIterator handler = registry->handlers.constFind(url.scheme());
if (handler != registry->handlers.constEnd()) {
insideOpenUrlHandler = true;
bool result = QMetaObject::invokeMethod(handler->receiver, handler->name.constData(), Qt::DirectConnection, Q_ARG(QUrl, url));
insideOpenUrlHandler = false;
return result; // ### support bool slot return type
}
}
if (!url.isValid())
return false;

QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
if (!platformIntegration)
return false;

QPlatformServices *platformServices = platformIntegration->services();
if (!platformServices) {
qWarning("%s: The platform plugin does not support services.", Q_FUNC_INFO);
return false;
}
return url.scheme() == QLatin1String("file") ?
platformServices->openDocument(url) : platformServices->openUrl(url);
}
dinjay 2020-04-24
  • 打赏
  • 举报
回复
可以编译源码,debug看一下openUrl里面怎么实现的。
qiushot 2020-04-24
  • 打赏
  • 举报
回复
问题应该找到,ShellExecute单步汇编执行时,会造成Windows的DispatchMessage异常了,该异常应该被windows自己封装的函数处理掉了,因此程序还是可以继续正常运行,继续下次的DispatchMessage了。
qiushot 2020-04-24
  • 打赏
  • 举报
回复
今天在MFC里测试了下,也存在这个问题,所以和QT没什么关系。
由于没有ShellExecute的源码,我的理解是ShellExecute的执行中断了鼠标或键盘消息的响应,造成了这样的现象。

继续等待3天 ,欢迎大神的其他想法,3天后结帖。
qiushot 2020-04-23
  • 打赏
  • 举报
回复
顶顶顶顶顶顶顶下
qiushot 2020-04-22
  • 打赏
  • 举报
回复
引用 4 楼 dinjay 的回复:
你connect了triggered,只是说点击后会触发你绑定的OnAct函数,并不代表这个click toobal上help按钮的动作是阻塞的,再加上这个openUrl是一个非阻塞函数,所以会出现你这个情况。
如果你只是希望每一次点击help都等slot函数处理完才能继续点击下一次help,那你可以这样写:

void MainWindow::OnAct(bool)
{
QAction* act = (QAction*)sender();
act->setEnabled(false);//置灰按钮
qDebug()<<"currentThreadId:"<<QThread::currentThreadId();

QString url ("E:/abc.txt");

bool bOk = QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode));


qDebug()<<"end";
act->setEnabled(true);//放开按钮点击
}




并不是说问题不好解决,换一种方法打开就文件就可以避免这个情况,例如将openUrl函数替换成WinExec就不会存在这个问题,WinExec应该同样是个非阻塞函数。
按钮消息的触发是消息队列触发的,肯定是在同一线程里顺序执行的,执行完上一个的消息后才能从消息队列取出下个鼠标消息处理。不可能是交叉执行的。另外openUrl是否阻塞不影响同一个线程的代码顺序执行。

现在的问题是怎么理解在调用了openUrl后同一线程的代码没有顺序执行的问题。我的感觉的是openUrl执行时中断了线程任务,优先执了其他线程任务,等openUrl返回后,在回到中断点继续执行。
donwmufromdying 2020-04-22
  • 打赏
  • 举报
回复
楼上这个是一个解决方案
dinjay 2020-04-22
  • 打赏
  • 举报
回复
你connect了triggered,只是说点击后会触发你绑定的OnAct函数,并不代表这个click toobal上help按钮的动作是阻塞的,再加上这个openUrl是一个非阻塞函数,所以会出现你这个情况。
如果你只是希望每一次点击help都等slot函数处理完才能继续点击下一次help,那你可以这样写:

void MainWindow::OnAct(bool)
{
QAction* act = (QAction*)sender();
act->setEnabled(false);//置灰按钮
qDebug()<<"currentThreadId:"<<QThread::currentThreadId();

QString url ("E:/abc.txt");

bool bOk = QDesktopServices::openUrl(QUrl(url, QUrl::StrictMode));


qDebug()<<"end";
act->setEnabled(true);//放开按钮点击
}

qiushot 2020-04-22
  • 打赏
  • 举报
回复 1
引用 1 楼 dinjay 的回复:
connect最后加上参数,Qt::QueuedConnection



大神们最好验证下再回答,你说的参数我都验证过,没什么用,同步的都可以执行,更不要说队列执行了
dinjay 2020-04-22
  • 打赏
  • 举报
回复
connect最后加上参数,Qt::QueuedConnection

16,213

社区成员

发帖
与我相关
我的任务
社区描述
Qt 是一个跨平台应用程序框架。通过使用 Qt,您可以一次性开发应用程序和用户界面,然后将其部署到多个桌面和嵌入式操作系统,而无需重复编写源代码。
社区管理员
  • Qt
  • 亭台六七座
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧