From b0b5345e158d5ed56565146b2b5d3ff94543f663 Mon Sep 17 00:00:00 2001 From: ispyisail Date: Mon, 10 Aug 2026 20:29:44 +1200 Subject: [PATCH] Commit font/color edits immediately instead of waiting for an unrelated click plc-user on PR #693: the crash is fixed, but the color/font field and the on-diagram text no longer update until you leave the properties list and click in the diagram -- previously it updated as soon as you clicked OK. That's a side effect of the crash fix itself. The old, crashing code returned a *live* QColorDialog as the item view's editor; clicking its OK button called accept()/hide() on it, and hiding the active editor happens to trip the base delegate's own focus-lost commit path -- so the value applied immediately, racily, as a side effect of the same mechanism that crashed on Enter. The fix (commit 4bd9b6b21) replaced that with running the dialog synchronously inside createEditor() and returning an inert placeholder with the result stashed in a property. Correct for the crash, but it also removed that accidental commit trigger: the placeholder never had focus to lose, so nothing tells the view to read the value back until some unrelated interaction (clicking away) incidentally triggers it. Fix: explicitly emit commitData()/closeEditor() for the resolved editor, deferred via QTimer::singleShot(0, ...) since the view only registers createEditor()'s return value as "the active editor" after createEditor() itself returns -- emitting synchronously, before returning, would target a widget the view doesn't know about yet. Applied to both font and color, since both share the exact same "resolve synchronously in createEditor(), return an inert placeholder" shape and thus the exact same gap; font just hadn't been reported. Verified with the same standalone harness from the crash fix (real QTreeView + DynamicTextItemDelegate + QAbstractItemView::edit()), this time deliberately *not* sending the synthetic Enter keypress the crash-fix verification needed: clicks the dialog's real OK button, lets the event loop run, and confirms the picked color lands in the model on its own. Also reconfirmed the crash fix itself still holds (clean exit, no synthetic-Enter needed either way now) and did a full Release build (504/504) with no new warnings. --- sources/ui/dynamicelementtextmodel.cpp | 12 ++++++++++++ sources/ui/dynamicelementtextmodel.h | 15 +++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/sources/ui/dynamicelementtextmodel.cpp b/sources/ui/dynamicelementtextmodel.cpp index e210ffba5..6ad12570a 100644 --- a/sources/ui/dynamicelementtextmodel.cpp +++ b/sources/ui/dynamicelementtextmodel.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include static int src_txt_row = 0; @@ -1595,6 +1596,15 @@ DynamicTextItemDelegate::DynamicTextItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {} +void DynamicTextItemDelegate::commitAndCloseDeferred(QWidget *editor) const +{ + auto *self = const_cast(this); + QTimer::singleShot(0, self, [self, editor]() { + emit self->commitData(editor); + emit self->closeEditor(editor); + }); +} + QWidget *DynamicTextItemDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, @@ -1682,6 +1692,7 @@ QWidget *DynamicTextItemDelegate::createEditor( w->setProperty("ok", ok); } w->setObjectName("font_dialog"); + commitAndCloseDeferred(w); return w; } case DynamicElementTextModel::color: @@ -1716,6 +1727,7 @@ QWidget *DynamicTextItemDelegate::createEditor( w->setProperty("ok", true); } w->setObjectName("color_dialog"); + commitAndCloseDeferred(w); return w; } case DynamicElementTextModel::pos: diff --git a/sources/ui/dynamicelementtextmodel.h b/sources/ui/dynamicelementtextmodel.h index 67b42e23e..013d9318b 100644 --- a/sources/ui/dynamicelementtextmodel.h +++ b/sources/ui/dynamicelementtextmodel.h @@ -155,6 +155,21 @@ class DynamicTextItemDelegate : public QStyledItemDelegate private: QStringList availableInfo(DynamicElementTextItem *deti) const; + /** + @brief commitAndCloseDeferred + Schedule commitData()/closeEditor() for @a editor on the next + event loop iteration. For editors resolved synchronously inside + createEditor() (font/color, both run their picker dialog before + returning) there is no user interaction left to drive the base + QStyledItemDelegate::eventFilter()'s usual Enter/focus-out commit + path, so without this the value sits picked-but-uncommitted + until something unrelated (e.g. clicking elsewhere) happens to + trigger it. Deferred rather than called immediately: the view + only registers the widget createEditor() returns as "the active + editor" *after* createEditor() itself returns, so emitting here + would target an editor the view doesn't know about yet. + */ + void commitAndCloseDeferred(QWidget *editor) const; }; #endif // DYNAMICELEMENTTEXTMODEL_H