PDA

View Full Version : QCheckBox as item of QComboBox



Grinchman
23rd June 2011, 04:44
Hello.
I bumped into a problem of adding an item QCheckBox into QComboBox. What I`ve found is the code for creating ItemDelegate for QComboBox, but it makes all of items in QComboBox as QCheckBox. My task is to add just one check box into the list of common combobox`s items...
Here is a code I found:

class CheckBoxList: public QComboBox
{
Q_OBJECT;

public:
CheckBoxList(QWidget *widget = 0);
virtual ~CheckBoxList();
virtual void paintEvent(QPaintEvent *);
void SetDisplayText(QString text);
QString GetDisplayText() const;

private:
QString m_DisplayText;
};


class CheckBoxListDelegate : public QItemDelegate
{
public:
CheckBoxListDelegate(QObject *parent)
: QItemDelegate(parent)
{
;
}

void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
//Get item data
bool value = index.data(Qt::UserRole).toBool();
QString text = index.data(Qt::DisplayRole).toString();

// fill style options with item data
const QStyle *style = QApplication::style();
QStyleOptionButton opt;
opt.state |= value ? QStyle::State_On : QStyle::State_Off;
opt.state |= QStyle::State_Enabled;
opt.text = text;
opt.rect = option.rect;

// draw item data as CheckBox
style->drawControl(QStyle::CE_CheckBox,&opt,painter);
}

QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem & option ,
const QModelIndex & index ) const
{
// create check box as our editor
QCheckBox *editor = new QCheckBox(parent);
return editor;
}

void setEditorData(QWidget *editor,
const QModelIndex &index) const
{
//set editor data
QCheckBox *myEditor = static_cast<QCheckBox*>(editor);
myEditor->setText(index.data(Qt::DisplayRole).toString());
myEditor->setChecked(index.data(Qt::UserRole).toBool());
}

void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
//get the value from the editor (CheckBox)
QCheckBox *myEditor = static_cast<QCheckBox*>(editor);
bool value = myEditor->isChecked();

//set model data
QMap<int,QVariant> data;
data.insert(Qt::DisplayRole,myEditor->text());
data.insert(Qt::UserRole,value);
model->setItemData(index,data);
}
};



CheckBoxList::CheckBoxList(QWidget *widget )
:QComboBox(widget),m_DisplayText("")
{
// set delegate items view
view()->setItemDelegate(new CheckBoxListDelegate(this));

// Enable editing on items view
view()->setEditTriggers(QAbstractItemView::CurrentChanged) ;
}


CheckBoxList::~CheckBoxList()
{
;
}


void CheckBoxList::paintEvent(QPaintEvent *)
{
QStylePainter painter(this);
painter.setPen(palette().color(QPalette::Text));

// draw the combobox frame, focusrect and selected etc.
QStyleOptionComboBox opt;
initStyleOption(&opt);

// if no display text been set , use "..." as default
if(m_DisplayText.isNull())
opt.currentText = "...";
else
opt.currentText = m_DisplayText;
painter.drawComplexControl(QStyle::CC_ComboBox, opt);

// draw the icon and text
painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
}


void CheckBoxList::SetDisplayText(QString text)
{
m_DisplayText = text;
}

QString CheckBoxList::GetDisplayText() const
{
return m_DisplayText;
}

Is anyone have thoughts how to improve this code to get possibility for adding into QComboBox 2 types of items: QCheckBox and common QComboBox items?
Or there is some other ways to achieve such behaviour?

Santosh Reddy
23rd June 2011, 05:16
Should be simple if you use QModelIndex to track items

For example if you want only item at index 3 to be QCheckBox, and rest to be standard QComboBox items, then you need to modify this way



QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem & option ,
const QModelIndex & index ) const
{
if(index.row() == 2) // Check for row 3 //Add this
{
// create check box as our editor
QCheckBox *editor = new QCheckBox(parent);
return editor;
}
return 0; //Add this, for default
}

Grinchman
23rd June 2011, 06:27
Thanks! It works! But next questions is how to check that index.row() is the last row in combo box?

Santosh Reddy
23rd June 2011, 06:41
if(index.row() == index.model()->rowCount() - 1)
//then last row

Grinchman
23rd June 2011, 06:54
Sorry for my inattention in reading documentation. I`ve did it already the same way )
Let this topic be opened. Coz I just studying that part of Qt (QModelIndex, QItemDelegate ant etc.) and I`m sure that new questions would appear.

The next thing I would try to do is to get (and set too) data from(to) checkbox.

Grinchman
23rd June 2011, 10:56
I`ve done it.
I just added ne set/get functions:

class CheckBoxList: public QComboBox
{
Q_OBJECT;

public:
CheckBoxList(QWidget *widget = 0);
virtual ~CheckBoxList();
bool GetAutoCalcValue();
void SetAutoCalcValue(bool checked);
};

And the implentation:

bool CheckBoxList::GetAutoCalcValue()
{
QModelIndex index = model()->index(model()->rowCount() - 1, 0);
return index.data(Qt::UserRole).toBool();
}

void CheckBoxList::SetAutoCalcValue(bool checked)
{
QModelIndex index = model()->index(model()->rowCount() - 1, 0);

QString text = index.data(Qt::DisplayRole).toString();

QMap<int,QVariant> data;
data.insert(Qt::DisplayRole,text);
data.insert(Qt::UserRole,checked);
model()->setItemData(index,data);
}

wysota
23rd June 2011, 14:44
Wouldn't it be easier to just use a model with the combobox and return the ItemIsUserCheckable flag for the items you want checkable?