在使用 QtPropertyBrowser (QtPropertyBrowser 2.5) 時,字串屬性對應的編輯器預設為 QLineEdit,其 valueChanged 訊號會在每次按鍵輸入時觸發。對於需要即時預覽、資料庫同步或撤銷/重做機制的編輯器場景,這會造成嚴重的效能問題與邏輯混亂。本文記錄 Ogitor 專案的修改方案:改為編輯完成(Enter 或失焦)才觸發值變更。
QtLineEditFactory 原始碼中,直接連接 QLineEdit::textChanged 到內部槽函式,導致每個字元輸入都推送變更。
核心修改點:
QtLineEditFactoryPrivate 新增 slotEditingFinished() 槽函式createEditor() 中連接 editingFinished() 而非 textChanged()manager->setValue()class QT_QTPROPERTYBROWSER_EXPORT QtLineEditFactory
: public QtAbstractEditorFactory<QtStringPropertyManager>
{
Q_OBJECT
public:
// ... 現有介面 ...
private:
Q_PRIVATE_SLOT(d_func(), void slotEditingFinished())
// ... 其他槽 ...
};
void QtLineEditFactoryPrivate::slotEditingFinished()
{
QObject* object = q_ptr->sender();
const auto ecend = m_editorToProperty.constEnd();
for (auto it = m_editorToProperty.constBegin(); it != ecend; ++it) {
if (it.key() == object) {
QtProperty* property = it.value();
QtStringPropertyManager* manager = q_ptr->propertyManager(property);
if (!manager) return;
QString value = static_cast<QLineEdit*>(it.key())->text();
manager->setValue(property, value);
return;
}
}
}
QWidget* QtLineEditFactory::createEditor(QtStringPropertyManager* manager,
QtProperty* property,
QWidget* parent)
{
QLineEdit* editor = d_ptr->createEditor(property, parent);
QRegExp regExp = manager->regExp(property);
if (regExp.isValid()) {
editor->setValidator(new QRegExpValidator(regExp, editor));
}
editor->setText(manager->value(property));
// 關鍵修改:使用 editingFinished 取代 textChanged
connect(editor, SIGNAL(editingFinished()),
this, SLOT(slotEditingFinished()));
connect(editor, SIGNAL(destroyed(QObject*)),
this, SLOT(slotEditorDestroyed(QObject*)));
return editor;
}
| 觸發時機 | 原始 (textChanged) | 修改後 (editingFinished) |
|---|---|---|
| 輸入每個字元 | 觸發 | 不觸發 |
| 按下 Enter | 觸發 | 觸發 ✓ |
| 失去焦點 | 觸發 | 觸發 ✓ |
| Esc 取消編輯 | 觸發 (已修改) | 不觸發 ✓ |
透過將 QtLineEditFactory 的訊號連接從 textChanged 改為 editingFinished,僅需修改少量核心程式碼,即可完美解決 Qt 屬性瀏覽器字串編輯器的「逐字觸發」問題,符合大多數編輯器場景的使用直覺與效能需求。