QRadioButton group and QDataWidgetMapper
-
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 valueauto 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.
-
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_ = -1def 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_ = selectiondef 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)
@ -
Hi jmelbye
can u please elaborate how to provide Id for each and every radiobutton and then store in mdoel
-
Hi jmelbye
can u please elaborate how to provide Id for each and every radiobutton and then store in mdoel
-
and also i get this error while exec
error: 'QMap<Key, T>::iterator::operator bool() const [with Key = int, T = QRadioButton*]' is private -
and also i get this error while exec
error: 'QMap<Key, T>::iterator::operator bool() const [with Key = int, T = QRadioButton*]' is private