Qt delegate not calling createEditor() - qt

I have ComboBox filled with CheckBoxes when the ComboBox is opened the first item's delegate createEditor is not called but when you move to second item it is called and delegate is properly created. After this when you move back to first item then delegate is working. The problem is only with selecting first item for first time. If you have got only one item in comboBox this item is unselectable.
This is my delegate's code:
#include "checkboxlistdelegate.h"
CheckBoxListDelegate::CheckBoxListDelegate(QObject *parent)
: QItemDelegate(parent) {
}
void CheckBoxListDelegate::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;
opt.palette = QPalette(Qt::white);
// draw item data as CheckBox
style->drawControl(QStyle::CE_CheckBox,&opt,painter);
}
QWidget* CheckBoxListDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem& option,
const QModelIndex & index ) const {
QCheckBox *editor = new QCheckBox(parent);
editor->setStyleSheet("QCheckBox {background-color: #aaaaaa; color: white;}");
return editor;
}
void CheckBoxListDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const {
QCheckBox *myEditor = static_cast<QCheckBox*>(editor);
myEditor->setText(index.data(Qt::DisplayRole).toString());
myEditor->setChecked(index.data(Qt::UserRole).toBool());
}
void CheckBoxListDelegate::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);
emit indexChanged(index);
}
void CheckBoxListDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const {
Q_UNUSED(index);
editor->setGeometry(option.rect);
}
And this is code of my QComboBox subclass:
CheckBoxList::CheckBoxList(QWidget *widget)
: QComboBox(widget),title(""),selection() {
// set delegate items view
view()->setItemDelegate(new CheckBoxListDelegate(this));
view()->setStyleSheet("QAbstractItemView {background-color:white;}");
// Enable editing on items view
view()->setEditTriggers(QAbstractItemView::AllEditTriggers);
connect(view()->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
this, SLOT(onItemClicked(QModelIndex)));
}
void CheckBoxList::paintEvent(QPaintEvent *) {
QStylePainter painter(this);
painter.setPen(palette().color(QPalette::Text));
QStyleOptionComboBox opt;
initStyleOption(&opt);
opt.currentText = title;
painter.drawComplexControl(QStyle::CC_ComboBox, opt);
painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
}
void CheckBoxList::setDisplayText(QString text) {
title = text;
}
QString CheckBoxList::getDisplayText() const {
return title;
}
bool CheckBoxList::isChecked(const QModelIndex& index) const {
return view()->model()->itemData(index).value(Qt::UserRole).toBool();
}
Thank you.

Related

How to display QSpinBox in QTableView when it is not in the edit mode

I was able to add the QSpinBox widget in a QTreeView using QStyledItemDelegate.
QWidget *NoteDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() == 2)
{
QSpinBox *spinBox = new QSpinBox(parent);
spinBox->setRange(0, 9999);
return spinBox;
}
return QStyledItemDelegate::createEditor(parent, option, index);
}
void NoteDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
if (index.column() == 2)
{
int value = index.model()->data(index, Qt::EditRole).toInt();
auto spinBox = static_cast<QSpinBox *>(editor);
spinBox->setValue(value);
return;
}
QStyledItemDelegate::setEditorData(editor, index);
}
void NoteDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if (index.column() == 2)
{
auto spinBox = static_cast<QSpinBox *>(editor);
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
return;
}
QStyledItemDelegate::setModelData(editor, model, index);
}
But, QSpinBox is showing up only when it is in the edit mode. How can I display this QSpinBox all the time even when it is in the display mode?
I suspect that QAbstractItemView::openPersistentEditor may be what you are looking for.

QStyledItemDelegate: how to make checkbox button to change its state on click

I have a delegate MyDelegate which is used for QListWidget. The delegate is derived from QStyledItemDelegate. One of the goals of MyDelegate is to place a checkbox button on each row of ListWidget. It is done within the paint() event of MyDelegate:
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter, option, index);
// ... drawing other delegate elements
QStyleOptionButton checkbox;
// setting up checkbox's size and position
// now draw the checkbox
QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkbox, painter);
}
At first I thought the checkbox would automatically change its state on click, since I specified QStyle::CE_CheckBox. But it is not the case. Looks like I have to specify the checkbox visual behavior manually.
Data-wise, When user clicks on that checkbox, certain signal is emitted and the scene data is changed. I perform this action in editorEvent():
bool MyDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
if (event->type() == QEvent::MouseButtonRelease) {
if (/* within checkbox area */)
emit this->clickedCheckbox(index);
}
}
The backend part works. However, I cannot figure out how to make the checkbox button to change its visual state from checked to unchecked, and backwards.
I realized that I can change the checkbox state manually by doing something like this from paint():
checkbox.state = someCondition? (QStyle::State_Enabled | QStyle::State_On) :
(QStyle::State_Enabled | QStyle::State_Off) ;
QStyle::State_On/Off does the trick of manual checkbox state change.
But I do not know how to set up that someCondition and where I should set it up. I tried to introduce it as a private bool variable which would be set in editorEvent() when the checkbox area gets a click, however, it does not produce the desired behavior: it sets all the other checkboxes of ListWidget to the same visual state. So, it behaved like some global condition for all the checkboxes.
I feel like, to accomplish my task, I have to re-implement the button and make it to change the checkbox state on click. But I'm lost on this way and not sure how to approach the problem. From the QStyleOptionButton API I do not see a clicked() or any other method I could use.
So, the question is: how do I make checkbox to behave like a checkbox, visually? If I need to re-implement a checkbox, then what class do I inherit?
You can set some value that describes your checkbox state in MyDelegate::editorEvent and then use it to paint a proper checkbox:
const int CHECK_ROLE = Qt::UserRole + 1;
bool MyDelegate::editorEvent(QEvent *event,
QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index)
{
if (event->type() == QEvent::MouseButtonRelease)
{
bool value = index.data(CHECK_ROLE).toBool();
// invert checkbox state
model->setData(index, !value, CHECK_ROLE);
return true;
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
void MyDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QStyleOptionButton cbOpt;
cbOpt.rect = option.rect;
bool isChecked = index.data(CHECK_ROLE).toBool();
if (isChecked)
{
cbOpt.state |= QStyle::State_On;
}
else
{
cbOpt.state |= QStyle::State_Off;
}
QApplication::style()->drawControl(QStyle::CE_CheckBox, &cbOpt, painter);
}
I added the following:
data(Qt:CheckStateRole) is toggled.
enable/disable the item.
center the box in the cell.
only toggle checkmark with left mouse button, and when checkmark is clicked (not the entire cell).
Here's the code:
// -------------------------------- //
class GFQtCheckboxItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
const int CHECK_ROLE = Qt::CheckStateRole;
// dont't let the default QStyledItemDelegate create the true/false combobox
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE
{
(void)parent;
(void)option;
(void)index;
return nullptr;
}
QRect GetCheckboxRect(const QStyleOptionViewItem &option)const
{
QStyleOptionButton opt_button;
opt_button.QStyleOption::operator=(option);
QRect sz = QApplication::style()->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt_button);
QRect r = option.rect;
// center 'sz' within 'r'
int dx = (r.width() - sz.width())/2;
int dy = (r.height()- sz.height())/2;
r.setTopLeft(r.topLeft() + QPoint(dx,dy));
r.setWidth(sz.width());
r.setHeight(sz.height());
return r;
}
// click event
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
if (event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent* pME = static_cast<QMouseEvent*>(event);
if(pME->button() == Qt::LeftButton)
{
QRect ro = GetCheckboxRect(option);
QPoint pte = pME->pos();
if(ro.contains(pte) )
{
bool value = index.data( CHECK_ROLE).toBool();
// invert checkbox state
model->setData(index, !value, CHECK_ROLE);
return true;
}
}
}
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionButton cbOpt;
cbOpt.rect = GetCheckboxRect(option);
bool isChecked = index.data(CHECK_ROLE ).toBool();
if (isChecked)
{
cbOpt.state |= QStyle::State_On;
}
else
{
cbOpt.state |= QStyle::State_Off;
}
QVariant enabled = index.data(Qt::ItemIsEnabled);
if(enabled.isNull() || enabled.toBool() )
{
cbOpt.state |= QStyle::State_Enabled;
}
QApplication::style()->drawControl(QStyle::CE_CheckBox, &cbOpt, painter);
}
};
And for completeness, here's how to apply it:
m_p_QTableView->setItemDelegateForColumn(iTableColumnIndex, new GFQtCheckboxItemDelegate() );
...
bool yesno ...;
pGrid->setData(index, yesno, Qt::CheckStateRole);
qtqcheckboxqtableview
This is much easier if you change the QListWidget to a QListModel and a QListView.
Qt::ItemFlags ListModel::flags(const QModelIndex &index) const
{
return QAbstractListModel::flags(index) | Qt::ItemIsUserCheckable;
}
QVariant ListModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::EditRole) {
return m_checkStateForRow[index.row()];
}
}
bool ListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == Qt::CheckStateRole) {
m_checkStateForRow[index.row()] = value.toInt();
emit dataChanged(index, index, {role});
return true;
}
return false;
}

checkbox and itemdelegate in a tableview

I'm doing an implementation of a CheckBox that inherits from QitemDelegate, to put it into a QTableView.
the problem is that I get when inserted flush left and I need it centered.
As I understand the method that is responsible for the Paint. I have it written as follows:
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
bool checkValue;
QStyleOptionButton BtnStyle;
BtnStyle.state = QStyle::State_Enabled;
if(index.model()->data(index, Qt::DisplayRole).toBool() == true)
{
BtnStyle.state |= QStyle::State_On;
checkValue = true;
}else{
BtnStyle.state |= QStyle::State_Off;
checkValue = false;
}
BtnStyle.direction = QApplication::layoutDirection();
BtnStyle.rect = option.rect;
QApplication::style()->drawControl(QStyle::CE_CheckBox,&BtnStyle,painter );
QApplication::style()->drawControl(QStyle::CE_CheckBox,&BtnStyle,painter );
}
what is missing to appear centered?
so I have the delegated:
.h
class BooleanWidget : public QWidget
{
Q_OBJECT
QCheckBox * checkBox;
public:
BooleanWidget(QWidget * parent = 0)
{
checkBox = new QCheckBox(this);
QHBoxLayout * layout = new QHBoxLayout(this);
layout->addWidget(checkBox,0, Qt::AlignCenter);
}
bool isChecked(){return checkBox->isChecked();}
void setChecked(bool value){checkBox->setChecked(value);}
};
class CheckBoxDelegate : public QItemDelegate
{
Q_OBJECT
private:
BooleanWidget *checkbox;
public:
CheckBoxDelegate(QObject *parent);
~CheckBoxDelegate();
void setEditorData( QWidget *editor,const QModelIndex &index )const;
void setModelData( QWidget *editor,QAbstractItemModel *model,const QModelIndex &index )const;
QWidget *createEditor( QWidget *parent,const QStyleOptionViewItem &/* option */,const QModelIndex &/* index */ )const;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
public slots:
void changed( bool );
};
.cpp
void CheckBoxDelegate::changed( bool value )
{
BooleanWidget *checkbox = static_cast<BooleanWidget*>( sender() );
emit commitData( checkbox );
emit closeEditor( checkbox );
}
QWidget *CheckBoxDelegate::createEditor( QWidget *parent,const QStyleOptionViewItem &/* option */,const QModelIndex &/* index */ ) const
{
BooleanWidget *editor = new BooleanWidget( parent );
connect( editor, SIGNAL( toggled ( bool ) ), this, SLOT( changed( bool ) ) );
return editor;
}
void CheckBoxDelegate::setEditorData( QWidget *editor,const QModelIndex &index ) const
{
int value = index.model()->data(index, Qt::DisplayRole).toInt();
BooleanWidget *checkbox = static_cast<BooleanWidget*>(editor);
if(value == 1)
{
checkbox->setChecked(true);
}
else
{
checkbox->setChecked(false);
}
}
void CheckBoxDelegate::setModelData( QWidget *editor,QAbstractItemModel *model,const QModelIndex &index ) const
{
BooleanWidget *checkBox = qobject_cast<BooleanWidget*>( editor );
Qt::CheckState value;
if(checkBox->isChecked())
value = Qt::Checked;
else
value = Qt::Unchecked;
model->setData( index, value, Qt::DisplayRole);
}
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
drawFocus(painter, option, option.rect);
}
If you are extending the QItemDelegate class, it has a drawCheck() function, what will draw you a nince, centered checkbox. You can use it in the paint() function.
Edit:
Here is an example, assuming you have a class called BooleanEditor, what inherits from QItemDelegate:
void BooleanEditor::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
drawFocus(painter, option, option.rect);
}
For keeping the checkbox centered when entering the edit mode, you can do something like this:
class BooleanWidget : public QWidget
{
Q_OBJECT
QCheckBox * checkBox;
public:
BooleanWidget(QWidget * parent = 0)
{
checkBox = new QCheckBox(this);
QHBoxLayout * layout = new QHBoxLayout(this);
layout->addWidget(checkBox,0, Qt::AlignCenter);
}
bool isChecked(){return checkBox->isChecked();}
void setChecked(bool value){checkBox->setChecked(value);}
};
And in your ItemDelegates createEditor() method return an instance of this BooleanWidget class. In your setModelData() and setEditorData() you can now cast your input widget to this BooleanWidget:
BooleanWidget * widget = qobject_cast<BooleanWidget*>(editor);
and then use the is/setChecked method.
I solve this problem with the following item delegate:
booleanitemdelegate.h
#ifndef BOOLEANITEMDELEGATE_H
#define BOOLEANITEMDELEGATE_H
#include <QItemDelegate>
class BooleanItemDelegate : public QItemDelegate
{
public:
BooleanItemDelegate(QObject *parent);
public:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;public:
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
};
#endif // BOOLEANITEMDELEGATE_H
booleanitemdelegate.cpp
#include "booleanitemdelegate.h"
BooleanItemDelegate::BooleanItemDelegate(QObject *parent):
QItemDelegate(parent)
{
}
void BooleanItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
drawCheck(painter, option, option.rect, index.data().toBool() ? Qt::Checked : Qt::Unchecked);
drawFocus(painter, option, option.rect);
}
bool BooleanItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
if(event->type() == QEvent::MouseButtonRelease){
model->setData(index, !model->data(index).toBool());
event->accept();
}
return QItemDelegate::editorEvent(event, model, option, index);
}
I hope, I can help.
that's what I did to center-allign the editor control:
QWidget *checkBoxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
QCheckBox *editor = new QCheckBox(parent);
editor->setTristate(allowTriState); //my class' variable
// this does the trick :)
editor->setStyleSheet("QCheckBox {margin-left: 43%; margin-right: 57%;}");
// this should do it better
// editor->setStyleSheet("QCheckBox {margin-left: auto; margin-right: auto;}");
// but in my case the checkbox is slightly to the left of original
return editor;
}
solved the problem as follows:
believes that inherits from the itemDelegate QStyledItemDelegate and reimplemented methods "paint" and "editorEvent".
In the method "editorEvent" emit a signal that indicates which row was selected.
Here is the code
class ItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
signals:
void clickSignal(int);
public:
ItemDelegate(QObject *parent = 0)
: QStyledItemDelegate(parent)
{
}
void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
QStyleOptionViewItemV4 viewItemOption(option);
if (index.column() == 0) {
const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
QRect newRect = QStyle::alignedRect(option.direction, Qt::AlignCenter,
QSize(option.decorationSize.width() + 5,option.decorationSize.height()),
QRect(option.rect.x() + textMargin, option.rect.y(),
option.rect.width() - (2 * textMargin), option.rect.height()));
viewItemOption.rect = newRect;
}
QStyledItemDelegate::paint(painter, viewItemOption, index);
}
virtual bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
const QModelIndex &index)
{
Q_ASSERT(event);
Q_ASSERT(model);
// make sure that the item is checkable
Qt::ItemFlags flags = model->flags(index);
if (!(flags & Qt::ItemIsUserCheckable) || !(flags & Qt::ItemIsEnabled))
return false;
// make sure that we have a check state
QVariant value = index.data(Qt::CheckStateRole);
if (!value.isValid())
return false;
// make sure that we have the right event type
if (event->type() == QEvent::MouseButtonRelease) {
const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
QRect checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter,
option.decorationSize,
QRect(option.rect.x() + (2 * textMargin), option.rect.y(),
option.rect.width() - (2 * textMargin),
option.rect.height()));
} else {
return false;
}
Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
? Qt::Unchecked : Qt::Checked);
emit(clickSignal(index.row()));
return model->setData(index, state, Qt::CheckStateRole);
}
};
the class where I have a connect QTableView do this:
connect(check,SIGNAL(clickSignal(int)),this,SLOT(CheckMark(int))); //check the itemDelegate
performed the operation with the check that were marked
Without too much fussing instead of directly setting rect:
BtnStyle.rect = option.rect;
Construct a new QRect and move x coordinate to the right as much as you like:
QRect r = option.rect;
QRect r1(r.x() + 34, r.y(), r.width(), r.height());
BtnStyle.rect = r1;
The solution in Python to center checkbox and allow user check/uncheck here

QAbstractTableModel data return html code to display

I want my AbstracttableModel subclass data() method to return html i.e.
PreText<b>Text</b>PostText
And this text must be displayed int table as in html:
PreTextTextPostText
How can I do this?
You can create a delegate for the view that will display the html.
class HtmlDelegate : public QItemDelegate {
public:
HtmlDelegate(QObject *parent = 0) : QItemDelegate(parent) {}
// This function is only called to paint the text
void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option,
const QRect &rect, const QString &text) const
{
QTextDocument doc;
// Since the QTextDocument will do all the rendering, the color,
// and the font have to be put back inside the doc
QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
? QPalette::Normal : QPalette::Disabled;
if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
cg = QPalette::Inactive;
QColor textColor = option.palette.color(cg, QPalette::Text);
doc.setDefaultStyleSheet(QString("body { color: %1}")
.arg(textColor.name()));
doc.setDefaultFont(option.font);
doc.setHtml(text);
doc.setDocumentMargin(1); // the default is 4 which is too much
painter->save();
painter->translate(rect.topLeft());
doc.drawContents(painter);
painter->restore();
}
// bold and underlined characters take more space
// so you have to redefine this function as well
// (if you have a checkbox or an icon in the item, you will have
// to include their size to the returned value)
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QTextDocument doc;
doc.setDefaultFont(option.font);
doc.setHtml(index.data(Qt::DisplayRole).toString());
doc.setDocumentMargin(1);
return doc.size().toSize();
}
};
Then assign it to a view:
view->setItemDelegateForColumn(0, new HtmlDelegate(view));
alexisdm answer works fine, but maybe using a QLabel is lighter than QTextDocument and it works smartly too:
class HtmlDelegateWithLabel : public QItemDelegate
{
public:
HtmlDelegateWithLabel(QObject *parent = 0) : QItemDelegate(parent)
{
}
inline void setupLabel( QLabel& label, const QModelIndex &index ) const
{
QString txt = index.model()->data( index, Qt::DisplayRole ).toString();
label.setText( txt );
}
// This function is only called to paint the text
void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option,
const QRect &rect, const QString &text) const
{
QLabel label;
setupLabel( label, option.index );
label.setEnabled( option.state & QStyle::State_Enabled );
label.setAttribute(Qt::WA_TranslucentBackground);
painter->save();
painter->translate(rect.topLeft());
label.resize( rect.size() );
label.render( painter );
painter->restore();
}
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QLabel label;
setupLabel( label, index );
return label.sizeHint();
}
};
Moreover, text gets aligned vertically on the row, which is not the case when using QTextDocument.

How to make QComboBox as MultiSelect in QT?

How to make QComboBox as MultiSelect in QT ?
There is no option of MultiSelect in Combox in QT ?
OR
Anybody can suggest me some diffrent control but look & feel should be like QCombobox only.
//This is the file named as CheckBoxList.h
#ifndef CHECKBOXLIST_H
#define CHECKBOXLIST_H
#include <QtGui>
class CheckBoxList: public QComboBox
{
Q_OBJECT;
public:
CheckBoxList(QWidget *widget = 0);
virtual ~CheckBoxList();
bool eventFilter(QObject *object, QEvent *event);
virtual void paintEvent(QPaintEvent *);
void SetDisplayText(QString text);
QString GetDisplayText() const;
private:
QString m_DisplayText;
};
#endif // CHECKBOXLIST_H
//This is the file named as CheckBoxList.cpp
#include "CheckBoxList.h"
#include <QtGui>
// internal private delegate
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);
//QMessageBox::information(0,"Info",text);
}
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);
}
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
editor->setGeometry(option.rect);
}
};
//min-width:10em;
CheckBoxList::CheckBoxList(QWidget *widget )
:QComboBox(widget),m_DisplayText(0)
{
// set delegate items view
view()->setItemDelegate(new CheckBoxListDelegate(this));
//view()->setStyleSheet(" padding: 15px; ");
// Enable editing on items view
view()->setEditTriggers(QAbstractItemView::CurrentChanged);
// set "CheckBoxList::eventFilter" as event filter for items view
view()->viewport()->installEventFilter(this);
// it just cool to have it as defualt ;)
view()->setAlternatingRowColors(true);
}
CheckBoxList::~CheckBoxList()
{
;
}
bool CheckBoxList::eventFilter(QObject *object, QEvent *event)
{
// don't close items view after we release the mouse button
// by simple eating MouseButtonRelease in viewport of items view
if(event->type() == QEvent::MouseButtonRelease && object==view()->viewport())
{
return true;
}
return QComboBox::eventFilter(object,event);
}
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;
}
One alternative is to set menu with checkable actions to a button, as I've shown here.
Or you can change the selection model of the combo and control the hiding and showing of the pop up window as shown here.

Resources