Custom Widget with QDataWidgetMapper in AutoSubmit Mode.



  • Hello,

    I'm having a problem with getting a custom widget to properly update a model when the widget's value is changed (after losing focus).
    The widget is mapped to a model using QDataWidgetMapper in AutoSubmit mode.

    The widget's value is read properly from the model and written properly when the mapper's submit() method is called, however the value is not updated to the model when the widget's NOTIFY signal is fired.

    Interestingly, if I derive the widget directly from QComboBox and use the same property it works fine.

    This example is a simplified widget that exhibits the problem; In practice, the custom widgets I want to use are more complex.

    #include <QComboBox>
    
    class TestCustomWidget : public QWidget
    {
      Q_OBJECT
      Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged USER true)
    public:
      explicit TestCustomWidget(QWidget* parent=0);
    
      int id() const;
    
    public Q_SLOTS:
      void setId(const int &);
    
    Q_SIGNALS:
      void idChanged(int);
    
    protected slots:
      void onSelectionChanged(const int &);
    
    protected:
      QComboBox *m_comboBox;
      int m_id;
    };
    
    TestCustomWidget::TestCustomWidget(QWidget* parent)
      : QWidget(parent),
        m_comboBox(new QComboBox(this)),
        m_id(0)
    {
      QVBoxLayout *layout = new QVBoxLayout;
      layout->setContentsMargins(0, 0, 0, 0);
      layout->addWidget(m_comboBox);
      layout->addStretch();
      setLayout(layout);
      
      m_comboBox->addItems ( (QStringList() << "A" << "B" << "C" << "D" ) );
    
      connect(m_comboBox, SIGNAL(currentIndexChanged(int)), this ,SLOT(onSelectionChanged(int)) );
    }
    
    
    int TestCustomWidget::id() const
    {
      return m_id;
    }
      
    void TestCustomWidget::setId(const int &id)
    {
      if ( id != m_id ) {
        m_id = id;
        m_comboBox->setCurrentIndex(id/10);
        emit idChanged(m_id);
      }
    }
    
    
    void TestCustomWidget::onSelectionChanged(const int &index)
    {
      setId(index * 10);
    }
    

    In my form, the widget is mapped using the custom property, but the model's setData() method is not called when the widget value is changed after it loses focus.

    ....
      m_TestCustomWidget = new TestCustomWidget (this);
      m_mapper( new QDataWidgetMapper(this) );
      m_mapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
    
      m_mapper->addMapping(m_TestCustomWidget, 0, "id");
    ...
    
    Has anyone else ever experienced this behavior?

  • Lifetime Qt Champion

    Hi,

    An educated guess, you should check the focus in/focus out events.



  • Hi, thanks very much for your reply. I believe you are pointing me in the right direction.

    The custom widget doesn't appear to receive focus events, even after I added

    setFocusPolicy(Qt::StrongFocus);
    

    This makes sense seeing that the custom widget is only acting as a container for the ComboBox. So I guess my question is how can I get the container widget to propagate the ComboBox's focus events?

    Thanks,
    Mike


  • Lifetime Qt Champion



  • I installed an event filter on the combobox:

      m_comboBox->installEventFilter(this);
    

    And reimped eventFilter:

    bool TestCustomWidget::eventFilter(QObject *object, QEvent *event)
    {
      if (object == m_comboBox) {
        if ( event->type() == QEvent::FocusOut ) {
          QFocusEvent *e = static_cast<QFocusEvent *>(event);
          focusOutEvent( e );
          return true;
        }
        else if ( event->type() == QEvent::FocusIn ) {
          QFocusEvent *e = static_cast<QFocusEvent *>(event);
          focusInEvent( e );
          return true;
        }
      }
      return QWidget::eventFilter(object, event);
    }
    

    But this still doesn't fire whatever mechanism is behind the mapper to commit the data to the model.


  • Lifetime Qt Champion

    I was rather thinking of mimicking what's done by QComboBox. AFAICS you are only intercepting all the events and rather execute the one from your own widget which doesn't do anything special.



  • Sorry, but I don't understand what you are suggesting.


  • Lifetime Qt Champion

    I'm suggesting to take a look at the implementation of QComboBox to see what the focus related methods are doing and then adapt that to your widget.

    Basically, your event filter is just eating the focus events from your QComboBox.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.