Q3ListView 是不是无法从 Qt 后备存储中注销或代码错误?
Posted
技术标签:
【中文标题】Q3ListView 是不是无法从 Qt 后备存储中注销或代码错误?【英文标题】:Does Q3ListView fail to unregister from Qt backing store or the code is wrong?Q3ListView 是否无法从 Qt 后备存储中注销或代码错误? 【发布时间】:2015-10-03 13:42:35 【问题描述】:我有以下用例(实际上没有意义,因为它是从一个真实的工作示例中最小化的,但我认为它在技术上仍然是正确的):
class Dialog : public QDialog
public:
Dialog(QWidget* parent)
: QDialog(parent)
new Q3ListView(this); // this will crash
// new QWidget(this); // this won't crash
;
取决于添加到Dialog
中的内容,当删除Dialog
实例时程序是否会崩溃(如sn-p 中的cmets 所示),但仅在修改了主窗口的标志时。这是MainWindow
类的代码,它使用Dialog
:
class MainWindow : public QMainWindow
public:
// the fact that the widget (dialog) below
// has no chance to show seems irrelevant.
// In the real scenario I have, the widget is shown on
// the screen and is closed by the user.
// I've just put the whole sequence of pieces of code
// that result from signal/slot calls, that in turn
// result from a point&click scenario in our application
// into the following function for brevity.
void go()
auto dialog = new Dialog(this);
dialog->show();
dialog->close();
disableAlwaysOnTop();
delete dialog; // or dialog->deleteLater();
void disableAlwaysOnTop()
setAttribute(Qt::WA_Resized, true);
Qt::WindowFlags flags = windowFlags();
setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint));
setVisible(true);
;
以及main
的实现:
int main(int argc, char** argv)
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
mainWindow.go();
return app.exec();
所有行似乎对于重现崩溃都是必不可少的。
这是 Qt 中的错误,还是我做错了什么?
允许手动删除小部件的子级,并且它们应自动从其父级注销,如下面手册中的引用所示。在我的真实案例中,该小部件被删除以从 GUI 中消失,并且它适用于其他小部件组合。如上面的评论所示,将delete dialog;
更改为dialog->deleteLater();
没有帮助。
似乎在从 Qt 的后备存储中删除 Q3ListView
实例时出现问题,这是堆栈跟踪:
QtGuid4.dll!QWidgetBackingStore::staticContents(QWidget * parent, const QRect & insideClipRect) 第 499 行 C++
QtGuid4.dll!QWidgetBackingStore::sync() 第 1200 行 C++
QtGuid4.dll!QWidgetPrivate::syncBackingStore() 第 1896 行 C++
QtGuid4.dll!QWidget::event(QEvent * event) 第 8694 行 C++
QtGuid4.dll!QMainWindow::event(QEvent * event) 第 1479 行 C++
QtGuid4.dll!QApplicationPrivate::notify_helper(QObject * receiver, QEvent * e) Line 4565 C++
QtGuid4.dll!QApplication::notify(QObject * receiver, QEvent * e) Line 4530 C++
QtCored4.dll!QCoreApplication::notifyInternal(QObject * receiver, QEvent * event) Line 955 C++
QtCored4.dll!QCoreApplication::sendEvent(QObject * receiver, QEvent * event) Line 231 C++
QtCored4.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver, int event_type, QThreadData * data) Line 1579 C++
QtCored4.dll!qt_internal_proc(HWND__ * hwnd, unsigned int message, unsigned __int64 wp, __int64 lp) 第 498 行 C++
[外部代码]
QtCored4.dll!QEventDispatcherWin32::processEvents(QFlags flags) 第 823 行 C++
QtGuid4.dll!QGuiEventDispatcherWin32::processEvents(QFlags flags) 第 1216 行 C++
QtCored4.dll!QEventLoop::processEvents(QFlags flags) 第 150 行 C++
QtCored4.dll!QEventLoop::exec(QFlags flags) 第 204 行 C++
QtCored4.dll!QCoreApplication::exec() 第 1227 行 C++
QtGuid4.dll!QApplication::exec() 第 3824 行 C++
qt_bug.exe!main(int argc, char * * argv) 第 60 行 C++
还有一段 Qt 的代码试图在堆栈跟踪中指示的行中使用指向已删除对象的指针:
for (int i = 0; i < count; ++i)
QWidget *w = staticWidgets.at(i);
QWidgetPrivate *wd = w->d_func();
if (!wd->isOpaque || !wd->extra || wd->extra->staticContentsSize.isEmpty() // ****
|| !w->isVisible() || (parent && !parent->isAncestorOf(w)))
continue;
(wd
指向标有注释的行处已删除的对象)。
免责声明: 我知道存在更优雅的解决方案,但这是遗留代码,根据Qt's manual:
您也可以自己删除子对象,它们会将自己从父对象中删除。
此代码有效。
我们在 Windows 7(MSVC 2010 SP1,CL 16)、Windows 8(MSVC 2013 U4,CL 18)和 Fedora 20(GCC 4.8.3)上重现了该问题。
【问题讨论】:
看起来像一个真正的 Qt 错误。这是一个极端情况:在事件循环有机会运行之前,您似乎不应该删除实例化和显示的小部件。我不认为它特定于Q3ListView
。我敢打赌,如果您将delete dialog
更改为dialog->deleteLater()
,它不会崩溃。也许如果您在delete
之前插入qApp->processEvents()
,它也不会崩溃。请让我们知道它在哪个平台上,因为它也很重要。我可能会尝试复制它。
TL;DR:您的代码没有错,但我怀疑 Qt 代码库中是否有很多测试可以确保在事件循环耗尽之前可以删除显示的小部件。我敢打赌这样的恶作剧也会在 Qt 5 中崩溃。
@KubaOber 感谢您的意见。我忘了提到我已经尝试过dialog->deleteLater()
,不幸的是它没有帮助。我们在 Windows 7、Windows 8 和 Arch Linux 上重现了崩溃。我会更新问题。
如果您(或其他人)能够设法重现该问题,那就太好了,所以我确信这不是我们环境中的问题(但是,3 台不同的机器和操作系统会降低这种可能性: ) ),并可能发布错误报告。
@KubaOber 另外,我忘了提 - 小部件没有机会显示的事实似乎无关紧要。在我的真实场景中,小部件显示在屏幕上并由用户关闭。为简洁起见,我刚刚将信号/槽调用产生的整个代码片段序列(反过来又产生于我们应用程序中的点击场景)放入一个函数 (go
)。
【参考方案1】:
我已经提交了bug report。由于它涉及旧版本的库,因此不希望它被修复。
无论如何,我们都将陆续删除 Qt3Support,因此建议大家 ;)
【讨论】:
以上是关于Q3ListView 是不是无法从 Qt 后备存储中注销或代码错误?的主要内容,如果未能解决你的问题,请参考以下文章