fix(framework): ensure that widgets are recreated and reparented after the owning view is closed
This commit is contained in:
parent
06c0a4ad6f
commit
db0477b80b
@ -20,36 +20,38 @@ concept isQWidget = std::is_base_of<QWidget, T>::value;
|
|||||||
*/
|
*/
|
||||||
template <isQWidget T> class TUWidgetLayoutViewBase : public TULayoutView {
|
template <isQWidget T> class TUWidgetLayoutViewBase : public TULayoutView {
|
||||||
public:
|
public:
|
||||||
TUWidgetLayoutViewBase() { m_widget = nullptr; };
|
TUWidgetLayoutViewBase() {
|
||||||
TUWidgetLayoutViewBase(T *widget) { m_widget = widget; };
|
m_widget = nullptr;
|
||||||
virtual ~TUWidgetLayoutViewBase() {
|
m_parentConnected = nullptr;
|
||||||
};
|
};
|
||||||
|
TUWidgetLayoutViewBase(T *widget) {
|
||||||
|
m_widget = widget;
|
||||||
|
m_parentConnected = nullptr;
|
||||||
|
};
|
||||||
|
virtual ~TUWidgetLayoutViewBase() {};
|
||||||
virtual void triggerMenuChanged() override {}
|
virtual void triggerMenuChanged() override {}
|
||||||
QWidget *widget() override {
|
QWidget *widget() override {
|
||||||
return reinterpret_cast<QWidget *>(static_cast<TULayoutView *>(this));
|
return reinterpret_cast<QWidget *>(static_cast<TULayoutView *>(this));
|
||||||
}
|
}
|
||||||
const QWidget *getWidget() const override {
|
const QWidget *getWidget() const override {
|
||||||
|
const_cast<TUWidgetLayoutViewBase *>(this)->ensureWidget();
|
||||||
|
const_cast<TUWidgetLayoutViewBase *>(this)->connectToParentIfNeeded();
|
||||||
return m_widget;
|
return m_widget;
|
||||||
}
|
}
|
||||||
QWidget *getWidget() override {
|
QWidget *getWidget() override {
|
||||||
ensureWidget();
|
ensureWidget();
|
||||||
|
connectToParentIfNeeded();
|
||||||
return m_widget;
|
return m_widget;
|
||||||
}
|
}
|
||||||
|
// Note: initiate() is NOT called by Toon Boom! The actual parenting
|
||||||
|
// is done externally via getWidget() + setParent(). We keep this for
|
||||||
|
// API compatibility but the real work is done in connectToParentIfNeeded().
|
||||||
TULayoutView *initiate(QWidget *parent) override {
|
TULayoutView *initiate(QWidget *parent) override {
|
||||||
ensureWidget();
|
ensureWidget();
|
||||||
if (parent && m_widget) {
|
if (parent && m_widget) {
|
||||||
m_widget->setParent(parent);
|
m_widget->setParent(parent);
|
||||||
|
connectToParent(parent);
|
||||||
}
|
}
|
||||||
QObject::connect(
|
|
||||||
parent, &QObject::destroyed, m_widget,
|
|
||||||
[this]() {
|
|
||||||
if (m_widget) {
|
|
||||||
m_widget->setParent(nullptr); // Prevent Qt from deleting us
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Qt::DirectConnection); // DirectConnection ensures this runs BEFORE
|
|
||||||
// deletion
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +60,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
QPointer<T> m_widget;
|
QPointer<T> m_widget;
|
||||||
|
QWidget *m_parentConnected; // Track which parent we've connected to
|
||||||
void ensureWidget() {
|
void ensureWidget() {
|
||||||
if (!m_widget) {
|
if (!m_widget) {
|
||||||
m_widget = createWidget();
|
m_widget = createWidget();
|
||||||
@ -65,9 +68,34 @@ protected:
|
|||||||
m_widget->setAttribute(Qt::WA_QuitOnClose, false);
|
m_widget->setAttribute(Qt::WA_QuitOnClose, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void isTULayoutView() override {}
|
// Connect to the widget's current parent to unparent before deletion
|
||||||
void disconnectView() override {
|
// This prevents cross-DLL heap corruption when Qt tries to delete our widget
|
||||||
|
void connectToParentIfNeeded() {
|
||||||
|
if (!m_widget)
|
||||||
|
return;
|
||||||
|
QWidget *parent = m_widget->parentWidget();
|
||||||
|
if (parent && parent != m_parentConnected) {
|
||||||
|
connectToParent(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void connectToParent(QWidget *parent) {
|
||||||
|
if (!parent || !m_widget)
|
||||||
|
return;
|
||||||
|
m_parentConnected = parent;
|
||||||
|
QObject::connect(
|
||||||
|
parent, &QObject::destroyed, m_widget.data(),
|
||||||
|
[this]() {
|
||||||
|
std::cout << "[parent destroyed] Unparenting widget to prevent "
|
||||||
|
"cross-DLL heap deletion"
|
||||||
|
<< std::endl;
|
||||||
|
if (m_widget) {
|
||||||
|
m_widget->setParent(nullptr);
|
||||||
|
}
|
||||||
|
m_parentConnected = nullptr;
|
||||||
|
onParentDisconnect();
|
||||||
|
},
|
||||||
|
Qt::DirectConnection);
|
||||||
}
|
}
|
||||||
virtual T *createWidget() = 0;
|
virtual T *createWidget() = 0;
|
||||||
};
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user