PDA

View Full Version : QRadioButton and QDataWidgetMapper



SimonSchmeisser
19th June 2009, 21:58
Hi,

i have a model, were each item has among others a boolean option. The logical approach of using QDataWidgetMapper works quite well for all the other fields (mapped to LineEdits, ComboBoxes, etc.). But I have no success mapping this boolean option to two QRadioButtons.

Here is what I do:
- Groupbox with two RadioButtons and autoExcluse == true
- QDataWidgetMapper maps the Variable to the QRadioButton for "true"

Here is what I expect:
- model->setData ( "true" ) when this QRadioButton is selected
- model->setData ( "false") when the other QRadioButton is selected

Here is what I get:
- model->setData ("true") when the unmapped QRadioButton is checked (which should be false)
- nothing happens, when the mapped QRadioButton is checked

I used connect(radioButton, SIGNAL(toggled(bool)), mapper, SLOT(submit())), but that works only sometimes and looks like a hack.

Any Ideas? Should I subclass QItemDelegate and look at the events? if so, which? and then do what? ;) Or rather QRadioButton, so that it behaves?

Thanks a lot for your help
Simon

caduel
21st June 2009, 10:28
for a bool property where only one option is checked, you can
* use a QCheckBox
* use 2 exclusive radiobuttons and just ignore the second for the QDataWidgetMapper;
the first one for a relevant purposes will behave like a checkbox and contain the correct bool state all by itself, too.

If you want to map the possible values of an enum, things are different though. then you need to consider all the radiobuttons. in this case i'd suggest to create a wrapper parent widget with a (custom) property value() that contains the desired enum value and map the parent with that property in the QDataWidgetMapper.

HTH

SimonSchmeisser
20th November 2009, 07:41
Hi Caduel,

thanks for your help and sorry for replying so late ...

So here are my observations, as a reference for myself and anyone searching an answer:

*QCheckBox:
Might work, but I didn't try. Generally speaking QDataWidgetMapper needs a Focus event or something similiar to notice the changed data.

*QRadioButton:
The problem with your Idea is that one cannot "uncheck" an exclusive QRadionButton, because Qt apparently doesn't know which RadioButton to check in exchange (doesn't really make sense for just two Buttons ...).

So here is what I did:

1. Create a Class ButtonGroup: public QWidget


class ButtonGroup : public QWidget {
Q_OBJECT
public:
ButtonGroup(QWidget *parent = 0);
virtual ~ButtonGroup();

Q_PROPERTY(int checkedId READ getCheckedId WRITE checkId USER true)
int getCheckedId();
void checkId(int id);

void addButton(QAbstractButton *button, int id);

signals:
void buttonClicked();

private:
QButtonGroup *m_buttonGroup;
QVBoxLayout *m_layout;
};

- contains a QButtonGroup and some layouting
- give it a user property and return QButtonGroup::checkedId there
- use QButtonGroup::button(int id) to get an Button and then check it with button->setChecked(true);

2. Map this with the QDataWidgetMapper

3. in your delegate add a slot like this:


void Delegate::commitMyData() {
QWidget *obj = qobject_cast<QWidget*>(sender());
emit commitData(obj);
emit closeEditor(obj);

qDebug() << "commitMyData";
}


4. connect QButtonGroup::buttonClicked signal to your delegate::commitMyData

5. thats it

future improvements:

would be cool to have ButtonGroup use SendEvent or something, so that I can just map it using QDataWidgetMapper and be done.

Hope that helps someone.

Bye

pilpi
24th June 2015, 15:28
I had trouble understanding this so I posted about it on stackoverflow. (http://stackoverflow.com/questions/31021852/connecting-radio-buttons-to-qsqltablemodel-via-qdatawidgetmapper-in-qt)

The piece I was missing is how the delegate needs to be connected to the mapper.

I have created a sample project that works at http://scanrobot.fi/wp-content/uploads/2015/06/qradiobutton-qsqltablemodel.zip

Here is the essence of what I needed to understand in practice:


QDataWidgetMapper* mapper = new QDataWidgetMapper(this);
mapper->setModel(model);
mapper->toLast();

QRadioButton *b1=new QRadioButton("a",this);
QRadioButton *b2=new QRadioButton("b",this);

RadioButtonDelegate *delegate=new RadioButtonDelegate(this);
ButtonGroup *group=new ButtonGroup(this);
mapper->addMapping(group,model->fieldIndex("radio"));

// set the delegate as the item delegate of mapper
mapper->setItemDelegate(delegate);
// connect value change in group to delegate so it can send appropriate signals
connect(group,SIGNAL(buttonClicked(int)),delegate, SLOT(commitMyData()));

group->addButton(b1,1);
group->addButton(b2,0);

Source for buttongroup.cpp:


#include "buttongroup.h"

ButtonGroup::ButtonGroup(QWidget *parent) :
QWidget(parent)
{
m_buttonGroup=new QButtonGroup(this);
connect(m_buttonGroup,SIGNAL(buttonClicked(int)),t his,SIGNAL(buttonClicked(int)));

}

int ButtonGroup::getCheckedId()
{
int id=m_buttonGroup->id(m_buttonGroup->checkedButton());
return id;
}

void ButtonGroup::checkId(int id)
{
m_buttonGroup->button(id)->setChecked(true);
}

void ButtonGroup::addButton(QAbstractButton *button, int id)
{
m_buttonGroup->addButton(button,id);
}

buttongroup.h (nothing very new here compared to the original url):


#ifndef BUTTONGROUP_H
#define BUTTONGROUP_H

#include <QWidget>
#include <QButtonGroup>
#include <QVBoxLayout>
#include <QAbstractButton>
#include <QRadioButton>

class ButtonGroup : public QWidget
{
Q_OBJECT
public:
explicit ButtonGroup(QWidget *parent = 0);

Q_PROPERTY(int checkedId READ getCheckedId WRITE checkId USER true)
int getCheckedId();
void checkId(int id);

void addButton(QAbstractButton *button, int id);

signals:
void buttonClicked(int);

private:
QButtonGroup *m_buttonGroup;
QVBoxLayout *m_layout;


};

#endif // BUTTONGROUP_H

radiobuttondelegate.h (nothing very new here either):


#ifndef RADIOBUTTONDELEGATE_H
#define RADIOBUTTONDELEGATE_H

#include <QItemDelegate>

class RadioButtonDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit RadioButtonDelegate(QObject *parent = 0);

signals:

public slots:

void commitMyData();
};

#endif // RADIOBUTTONDELEGATE_H

radiobuttondelegate.cpp (or here):


#include "radiobuttondelegate.h"
#include <QDebug>
RadioButtonDelegate::RadioButtonDelegate(QObject *parent) :
QItemDelegate(parent)
{
}
void RadioButtonDelegate::commitMyData() {
QWidget *obj = qobject_cast<QWidget*>(sender());
emit commitData(obj);
emit closeEditor(obj);

qDebug() << "commitMyData";
}