使用QtWidgets跨作用域访问对象致Toon Boom Harmony崩溃求助
解决Toon Boom Harmony管线工具的线程崩溃与作用域问题
1. 修复「QThread: destroyed while thread is still running」崩溃
问题核心是窗口关闭时,自定义Widget实例被销毁,但关联的异步线程(比如UiLoader后台线程、project.findAsset的异步任务)仍在运行,导致线程被强制终止触发崩溃。
解决步骤:
- 重写Widget的
closeEvent方法,主动清理线程:SaveLoadWidget.prototype.closeEvent = function(event) { // 终止并等待异步线程完成 if (this.assetSearchThread) { this.assetSearchThread.quit(); this.assetSearchThread.wait(); this.assetSearchThread = null; } // 解除所有信号槽关联,避免悬空引用 QtCore.QObject.disconnect(this); // 调用父类的关闭事件逻辑 WidgetBase.prototype.closeEvent.call(this, event); }; - 如果
project.findAsset是异步执行,给它添加取消接口,在窗口关闭时调用,确保线程能正常退出。
2. 解决「QDir未定义」TypeError
调试模式下Qt模块的自动导入机制失效,导致QDir无法被脚本识别。
解决方法:
- 在脚本开头显式声明QDir:
var QDir = QtCore.QDir; - 如果是UiLoader加载的UI里用到QDir,在加载前把QDir注入UI上下文:
var uiLoader = new UiLoader(this); uiLoader.context().setContextProperty("QDir", QtCore.QDir); var uiWidget = uiLoader.load("saveLoadWidget.ui");
3. 修复MessageLog访问引发的崩溃
信号回调的作用域未持有MessageLog的有效引用,导致对象被提前回收,触发崩溃。
解决方法:
- 把MessageLog挂载到Widget实例上,确保回调能通过
this访问:function SaveLoadWidget(parent) { WidgetBase.call(this, parent); // 持久化MessageLog到实例作用域 this.msgLog = MessageLog; // 绑定信号时用bind确保this指向正确 this.searchInput.returnPressed.connect(function() { this.msgLog.logInfo("开始查找资源"); project.findAsset(...); }.bind(this)); } - 或者直接通过全局作用域访问:
this.searchInput.returnPressed.connect(function() { global.MessageLog.logInfo("开始查找资源"); project.findAsset(...); });
通用的对象作用域注入方法
要把对象添加到其他对象的作用域,常用这几种方式:
- 实例属性挂载:把需要的对象(比如MessageLog、QDir)作为自定义Widget的属性,这样所有实例方法和回调都能通过
this访问。 - UiLoader上下文注入:用
setContextProperty把对象注入UI加载器的上下文,让UI里的控件回调能直接调用这些对象。 - 函数作用域绑定:用
Function.bind()把回调的this固定到目标实例,避免作用域漂移。
内容的提问来源于stack exchange,提问作者Nikita
相关产品推荐
相关产品推荐

