QtPropertyBrowser and value changed signals
Asked Answered
F

3

7

I'm using the Qt Property Browser library as a record editor. When the user has completed their edits of any given field, by removing focus from the edit item or pressing the enter key, I want to be informed of that so that I can take the change, process it, and send it off to the REAL item that's being changed.

Unfortunately I seem to only be able to find the propertyChanged and valueChanged signals and they get triggered every time any amount of text is added or removed, not just when the user is triggering a finish.

Without being able to get this notification I don't see how this can be a usable component. It doesn't even revert when the user hits [ESC], which I certainly need to be able to implement! Surely I must be wrong about there being absolutely NO signal that does what I need, but I sure can't find it.

Anyone know?


Upon examining the source code, the people who made the line editor factory made the unfortunate decision to connect with textEdited rather than editingFinished. It would be a relatively simple matter to change except that the quite methodically made it impossible to extend this editor factory that has an extensible interface!

ALL I would need to do is override the createEditor function, disconnect the bad connection, connect a better connection with a call in between to get the string out of the line edit control. But NO!!! We're not going to let you do that! We're going to put all of the accounting stuff in a private class you can't access or call and those parts that we are going to let you call are going to be tightly coupled to the fact that they're being called by the edit control, NOT by anything else. ERGO, we've quite effectively made life as frustratingly impossible as we could possibly imagine. Aren't we brilliant?


I've found out more. The standard Qt approach for these kinds of objects uses delegates to control the behavior I'm trying to get. The Qt property library overrides this behavior and does something else that is NOT what I'm trying to accomplish. Inside of the QAbstractItemDelegate interface is a setModelData function that is called by the view it's attached to when the user commits their edits; it is not called when they destroy the editor without committing.

The next trick is going to be learning the Qt Model/View architecture and patching the library to do it the right way. This may even amount to no more than simply removing the overriding stubs that destroy the behavior I'm trying to get. It might also be that forgoing the use of this system in place of simply using the QtTreeView might be a better choice though it would be nice to be able to retain the ability to switch out between the different kinds of browser.

Foist answered 17/12, 2010 at 0:32 Comment(1)
5 years later and I got same feel as you. I've done a lot of hacks to make property grid at least a bit like as .NET's one.Attica
F
4

So, here's the half-ass fix I came up with:

I added a "commitItem(QModelIndex)" function to the private thing in the TreePropertyBrowser. Then I call that from the delegate when the setModelData() function is called.

This then finds the property, calls a new function I added to the AbstractBrowser to fetch the factory for a property and then tells the factory to "commitProperty(QtProperty*)".

This function is an empty virtual at the base and in the LineEditFactory I override it to apply the property change, which generates the valueChanged() signal.

With these changes in place the user is able to back out of the edit by hitting the ESC key and I get notified iff they commit the property change by hitting RETURN, focus changing, etc...

Only works for the tree version at the moment. Probably won't bother trying to make the rest work. In fact I'm probably going to throw this library away and just use the QTreeView myself. IT behaves the way I want, this thing had to be uber-hacked to get the behavior BACK.

Oh yeah, you also have to remove the connection to the textChanged() signal in the LineEditFactory's createEditor().

Foist answered 18/12, 2010 at 0:34 Comment(0)
D
1

I ran into this same problem awhile ago. We needed to know when editing was finished for any of the QVariant editors. The trick is that the framework creates and deletes its widgets as you start and stop editing. So, buried in the EditorFactory classes, I connected to QObject::destroyed signal very every single QWidget type it creates, and bubbled up a new propertyEditFinished signal that the main app can catch.

QtPropertyBrowser is definitely crazy, but it's also a pain to reimplement the whole thing.

Desperate answered 15/6, 2011 at 17:23 Comment(2)
Actually, I found it wasn't a whole lot of work to re implement and I have something that makes a bit more sense. The property browser (the part I wanted anyway) is nothing more than a basic tree view.Foist
Yeah you're right. That's the thing about engineering. What should be done or what's easiest always comes back to what you really need to do. :) It's a good thing we're lazy! Glad you got it working.Desperate
A
1

This question is probably no longer relevant in Qt 5 that has incorporated QtPropertyBrowser and friends. I implemented an editingFinished signal for the QtLineEditorFactory along the lines of Thadeaux's approach, and then decided I didn't need/want to do it that way! Perhaps to assuage the feeling of wasting my time I enclose a code diff of my solution in case someone might find it useful.

    Index: src/qteditorfactory.cpp
    ===================================================================
    --- src/qteditorfactory.cpp (revision 737)
    +++ src/qteditorfactory.cpp (working copy)
    @@ -1076,7 +1076,6 @@
     }


    -
     /*!
         \class QtLineEditFactory

    @@ -1094,7 +1093,6 @@
     {
         d_ptr = new QtLineEditFactoryPrivate();
         d_ptr->q_ptr = this;
    -
     }

     /*!
    @@ -1121,6 +1119,10 @@
                 this, SLOT(slotEchoModeChanged(QtProperty *, int)));
         connect(manager, SIGNAL(readOnlyChanged(QtProperty*, bool)),
             this, SLOT(slotReadOnlyChanged(QtProperty *, bool)));
    +
    +   // c.s. Added 4/12/2017
    +   connect(this, SIGNAL(propertyEditingFinished(QtProperty*, const QString&)),
    +       manager, SIGNAL(propertyEditingFinished(QtProperty*, const QString&)));
     }

     /*!
    @@ -1131,7 +1133,6 @@
     QWidget *QtLineEditFactory::createEditor(QtStringPropertyManager *manager,
             QtProperty *property, QWidget *parent)
     {
    -
         QLineEdit *editor = d_ptr->createEditor(property, parent);
         editor->setEchoMode((EchoMode)manager->echoMode(property));
         editor->setReadOnly(manager->isReadOnly(property));
    @@ -1146,9 +1147,49 @@
                     this, SLOT(slotSetValue(const QString &)));
         connect(editor, SIGNAL(destroyed(QObject *)),
                     this, SLOT(slotEditorDestroyed(QObject *)));
    -    return editor;
    +   
    +   // c.s. Added 4/12/2017
    +   connect(editor, SIGNAL(editingFinished()), SLOT(handleEditingFinished()));
    +    return editor; 
     }

    +
    +
    +// c.s. Added 4/12/2017
    +void QtLineEditFactory::handleEditingFinished()
    +{
    +   auto keys = d_ptr->m_editorToProperty.keys();
    +   QLineEdit *le = qobject_cast<QLineEdit*>(sender());
    +   if (!le)
    +       return;
    +
    +   disconnect(le, SIGNAL(editingFinished()), this, SLOT(handleEditingFinished()));
    +
    +   QtProperty *property = 0;
    +
    +   const QMap<QLineEdit *, QtProperty *>::ConstIterator ecend =
    +       d_ptr->m_editorToProperty.constEnd();
    +    for (QMap<QLineEdit *, QtProperty *>::ConstIterator itEditor =
    +            d_ptr->m_editorToProperty.constBegin(); itEditor != ecend; ++itEditor)
    +   {
    +        if (itEditor.key() == le)
    +       {
    +           property = itEditor.value();
    +           if (!property)
    +               return;
    +           
    +            QtStringPropertyManager *manager = propertyManager(property);
    +
    +           if (!manager)
    +               return;
    +
    +           QString s = manager->value(property);
    +           manager->setValue(property, s); // make sure it has the last value
    +           emit propertyEditingFinished(property, s);
    +       }
    +   }
    +}
    +
     /*!
         \internal

    @@ -1165,6 +1206,9 @@
         disconnect(manager, SIGNAL(readOnlyChanged(QtProperty*, bool)),
             this, SLOT(slotReadOnlyChanged(QtProperty *, bool)));

    +   // c.s. Added 4/12/2017
    +   disconnect(this, SIGNAL(propertyEditingFinished(QtProperty*, const QString&)),
    +       manager, SIGNAL(propertyEditingFinished(QtProperty*, const QString&)));
     }

     // QtDateEditFactory
    Index: src/qteditorfactory.h
    ===================================================================
    --- src/qteditorfactory.h   (revision 737)
    +++ src/qteditorfactory.h   (working copy)
    @@ -183,6 +183,14 @@
         QWidget *createEditor(QtStringPropertyManager *manager, QtProperty *property,
                     QWidget *parent);
         void disconnectPropertyManager(QtStringPropertyManager *manager);
    +   
    +// c.s. Added 4/12/2017
    +Q_SIGNALS:
    +   void propertyEditingFinished(QtProperty*,  const QString&); // signal editing done in line_editor is finished
    +
    +protected slots:
    +   void handleEditingFinished(); // similar to QLineEdit
    +
     private:
         QtLineEditFactoryPrivate *d_ptr;
         Q_DECLARE_PRIVATE(QtLineEditFactory)
    Index: src/qtpropertymanager.h
    ===================================================================
    --- src/qtpropertymanager.h (revision 737)
    +++ src/qtpropertymanager.h (working copy)
    @@ -200,6 +200,9 @@
         void echoModeChanged(QtProperty *property, const int);
         void readOnlyChanged(QtProperty *property, bool);

    +   // c.s. Added 4/12/2017
    +   void propertyEditingFinished(QtProperty *, const QString &val);
    +
     protected:
         QString valueText(const QtProperty *property) const;
         QString displayText(const QtProperty *property) const;
Alston answered 18/4, 2017 at 1:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.