Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    QRadioButton group and QDataWidgetMapper

    General and Desktop
    4
    7
    4111
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J
      jmelbye last edited by

      I wanted to be able to represent an exclusive set of options as several radio buttons. I also wanted to be able to store an integer Id corresponding to which option was selected in my database, and ideally, use QDataWidgetMapper to do it. Yes, a combo box could serve here, but for this particular UI, I would prefer option buttons (in part because there are other widgets that become enabled/disabled as a result of the selected option, and they are laid out in a way that helps make the relationship apparent.)

      I came across QButtonGroup and thought that might solve my problem, but QButtonGroup is not a QWidget, which is needed by QDataWidgetMapper. I also came acroos QGroupBox which is a QWidget, but it doesn't have a property to get at the currently selected option (and why should it - a group box could have all sorts of different sets of child items.)

      I thought this would be a fairly common problem, so I wanted to present my solution so that:

      • Those of you who have tackled this problem before can chime in on the solution
      • Those of you who are looking for a solution have a starting place

      I wanted to use a widget as a starting place, and then add to the interface:

      • A method for assigning an integer Id to each option button
      • A property for getting/setting the current Id / selected option button

      The currently selected propery needs to be a property in order to work with QDataWidgetMapper. The best widget to use as a starting place seemed to be...well...QWidget!

      Here is my OptionGroup class:

      optiongroup.h
      @
      #ifndef OPTIONGROUP_H
      #define OPTIONGROUP_H

      #include <QWidget>
      #include <QMap>

      class QRadioButton;

      class OptionGroup : public QWidget
      {
      Q_OBJECT
      Q_PROPERTY(int currentSelection READ currentSelection WRITE setCurrentSelection USER true)

      public:
      explicit OptionGroup(QWidget *parent = 0);

      int currentSelection() const;
      void setCurrentSelection(int selection);
      
      void setSelectionId(QRadioButton *button, int id);
      

      signals:
      void selectionChanged(int selection);

      public slots:
      void buttonToggled(bool checked);

      private:
      int currentSelection_;
      QMap<int, QRadioButton*> buttonMap_;
      QMap<QRadioButton*, int> revButtonMap_;
      };

      #endif // OPTIONGROUP_H
      @

      optiongroup.cpp:
      @#include <QRadioButton>
      #include "optiongroup.h"

      OptionGroup::OptionGroup(QWidget *parent) :
      QWidget(parent), currentSelection_(-1)
      {
      }

      int OptionGroup::currentSelection() const
      { return currentSelection_; }

      void OptionGroup::setCurrentSelection(int selection)
      {
      // If the specified selection id is not in our button map,
      // then it is invalid, set selection to -1. Otherwise,
      // update the selection to user specified value

      auto iter = buttonMap_.find(selection);
      if (iter == buttonMap_.end() || selection < 0) {
          currentSelection_ = -1;
          for (iter = buttonMap_.begin(); iter != buttonMap_.end(); ++iter)
              iter.value()->setChecked(false);
      } else {
          iter.value()->setChecked(true);
          currentSelection_ = selection;
      }
      

      }

      void OptionGroup::setSelectionId(QRadioButton* button, int id)
      {
      // Make sure we got a valid Id (non-negative)
      // Also then listen for signals from this button
      if (id >= 0) {
      buttonMap_[id] = button;
      revButtonMap_[button] = id;
      connect(button, SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool)));
      }
      }

      void OptionGroup::buttonToggled(bool checked)
      {
      if (checked == true) {
      QRadioButton* btn = qobject_cast<QRadioButton*>(sender());
      Q_ASSERT(btn);
      currentSelection_ = revButtonMap_[btn];
      emit selectionChanged(currentSelection_);
      }
      }
      @

      Note that you'll need to call setSelectionId() to assign an Id to each QRadioButton. -1 is used to represent an invalid or unset Id, so be sure to pass something that is greater than or equal to 0.

      If you had:

      • ui->optBtnA which corresponds with Id 0
      • ui->optBtnB which corresponds with Id 1
      • ui->optBtnC which corresponds with Id 2

      And they were all children of an OptionGroup ui->optionGroup, you would do this:
      @
      ui->optionGroup.setSelectionId(ui->optBtnA, 0);
      ui->optionGroup.setSelectionId(ui->optBtnB, 1);
      ui->optionGroup.setSelectionId(ui->optBtnC, 2);

      ...
      // QDataWidgetMapper mapper;
      // int optionField; This is which field in your data model you are storing the option value in
      mapper.addMapping(ui->optionGroup, optionField);
      @

      This seems to be working well enough. Having the two maps for looking up Ids/QRadioButton* is redundant. Since the list of options is always likely to be pretty small, so I might use a QList of QPair's and just sequentially search them.

      Hit me with your critiques, and hope this helps somebody else out.

      1 Reply Last reply Reply Quote 0
      • R
        rivimey last edited by

        Looks really useful for the right situation... thanks for taking the trouble to post it :-)

        1 Reply Last reply Reply Quote 0
        • L
          lvlvlvl last edited by

          Code translated in Pyside :

          @
          from PySide.QtCore import *
          from PySide.QtGui import *

          class optionGroup(QWidget):

          def init(self, parent):
          QWidget.init (self, parent)
          self.ListeBoutons = []
          self.currentSelection_ = -1

          def litSelection (self):
          return self.currentSelection_

          def setCurrentSelection (self, selection):
          self.currentSelection_ = -1
          for elem in self.ListeBoutons:
          if elem[1] == selection:
          elem[0].setChecked(True)
          self.currentSelection_ = selection

          def setSelectionId (self, Bouton, ident):
          self.ListeBoutons.append([Bouton, ident])
          Bouton.toggled[bool].connect(self.buttonToggled)

          def buttonToggled (self, checked):
          if checked:
          Bouton = self.sender()
          for elem in self.ListeBoutons:
          if elem[0] == Bouton:
          self.currentSelection_ = elem[1]
          self.selectionChanged.emit(self.currentSelection_)

          currentSelection = Property(int, litSelection, setCurrentSelection, user = True)
          selectionChanged = Signal(int)
          @

          1 Reply Last reply Reply Quote 0
          • M
            mananbhatt last edited by

            Hi jmelbye

            can u please elaborate how to provide Id for each and every radiobutton and then store in mdoel

            1 Reply Last reply Reply Quote 0
            • M
              mananbhatt last edited by

              Hi jmelbye

              can u please elaborate how to provide Id for each and every radiobutton and then store in mdoel

              1 Reply Last reply Reply Quote 0
              • M
                mananbhatt last edited by

                and also i get this error while exec
                error: 'QMap<Key, T>::iterator::operator bool() const [with Key = int, T = QRadioButton*]' is private

                1 Reply Last reply Reply Quote 0
                • M
                  mananbhatt last edited by

                  and also i get this error while exec
                  error: 'QMap<Key, T>::iterator::operator bool() const [with Key = int, T = QRadioButton*]' is private

                  1 Reply Last reply Reply Quote 0
                  • First post
                    Last post