PDA

View Full Version : QTableView checkbox center with stylesheet



quiet
1st March 2009, 22:28
Hi!

I tried to center the checkbox in QTableView by something like this:

qApp->setStyleSheet("::indicator {subcontrol-position: center; subcontrol-origin: padding;}");

But it doesn't work for QTableView item (set by Qt::CheckStateRole in model), although it works good for any other usual widget like QCheckBox or QRadioButton.
Is that bug in Qt or maybe Qt just does't provide this stylesheet subcontrol feature for item views?

I see that other properties like e.g 'left' also work for checkbox indicator in view.

Jennie Bystrom
28th January 2011, 09:01
Hi,

almost a year since you posted this issue. Did you find a solution? I have the exact problem and it would be really nice if I could solve it using stylesheets. I haven't found a way to solve it in the model-view-delegate either, it is really annoying with the left-aligned checkboxes in my treeviews and tableviews.

rovshanb
10th March 2011, 14:52
Hi,

If this is still actual here is how I managed to put checkboxes at the center:

1) Create widget class:



#ifndef CENTEREDCHECKBOXWIDGET_H
#define CENTEREDCHECKBOXWIDGET_H

#include <QWidget>

class QCheckBox;

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

QCheckBox *checkBox() const;

private:
QCheckBox *checkbox;

};

#endif // CENTEREDCHECKBOXWIDGET_H

#include "centeredcheckboxwidget.h"
#include <QtGui>

CenteredCheckBoxWidget::CenteredCheckBoxWidget(QWi dget *parent) :
QWidget(parent)
{
setContentsMargins(0, 0, 0, 0);
setAutoFillBackground(true);

QHBoxLayout *layout=new QHBoxLayout();
checkbox=new QCheckBox();
layout->addWidget(checkbox);
layout->setAlignment(checkbox, Qt::AlignHCenter | Qt::AlignVCenter);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);

setLayout(layout);

setFocusProxy(checkbox);
}

QCheckBox *CenteredCheckBoxWidget::checkBox() const
{
return checkbox;
}


2) Create custom delegate:


#ifndef BOOLEANDELEGATE_H
#define BOOLEANDELEGATE_H

#include <QStyledItemDelegate>

class BooleanDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit BooleanDelegate(QObject *parent, bool defaultValue=true);

void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const;

QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;

void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;

void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const;

private:
bool defaultValue;

};

#endif // BOOLEANDELEGATE_H

#include "booleandelegate.h"
#include "widgets/centeredcheckboxwidget.h"
#include <QtGui>

BooleanDelegate::BooleanDelegate(QObject *parent, bool defaultValue) :
QStyledItemDelegate(parent), defaultValue(defaultValue)
{
}

void BooleanDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QVariant value=index.data();
if (!value.isValid() || qVariantCanConvert<bool>(value)) {
bool boolVal = value.isValid() ? value.toBool() : defaultValue;

QStyle *style=qApp->style();

QRect checkBoxRect=style->subElementRect(QStyle::SE_CheckBoxIndicator, &option);
int chkWidth=checkBoxRect.width();
int chkHeight=checkBoxRect.height();

int centerX=option.rect.left() + qMax(option.rect.width()/2-chkWidth/2, 0);
int centerY=option.rect.top() + qMax(option.rect.height()/2-chkHeight/2, 0);
QStyleOptionViewItem modifiedOption(option);
modifiedOption.rect.moveTo(centerX, centerY);
modifiedOption.rect.setSize(QSize(chkWidth, chkHeight));
if(boolVal){
modifiedOption.state |= QStyle::State_On;
}

style->drawPrimitive(QStyle::PE_IndicatorItemViewItemChec k, &modifiedOption, painter);
}else {
QStyledItemDelegate::paint(painter, option, index);
}
}

QWidget *BooleanDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
CenteredCheckBoxWidget *editor=new CenteredCheckBoxWidget(parent);
editor->checkBox()->setChecked(defaultValue);

return editor;
}

void BooleanDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QVariant data=index.model()->data(index, Qt::EditRole);
bool value;
if(!data.isNull()){
value=data.toBool();
}else{
value=defaultValue;
}


CenteredCheckBoxWidget *checkBoxWidget = static_cast<CenteredCheckBoxWidget*>(editor);
checkBoxWidget->checkBox()->setChecked(value);
}

void BooleanDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
CenteredCheckBoxWidget *checkBoxWidget = static_cast<CenteredCheckBoxWidget*>(editor);

bool value = checkBoxWidget->checkBox()->isChecked();

model->setData(index, value, Qt::EditRole);
}

void BooleanDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
CenteredCheckBoxWidget *checkBoxWidget = static_cast<CenteredCheckBoxWidget*>(editor);

QSize size=checkBoxWidget->sizeHint();
editor->setMinimumHeight(size.height());
editor->setMinimumWidth(size.width());
editor->setGeometry(option.rect);
}



3) Set the above delegate for the column:


BooleanDelegate *isNullableDelegate=new BooleanDelegate(this);
table->setItemDelegateForColumn(columnIndex, isNullableDelegate);


When retrieving data for this cell use Qt::EditRole and cast it to boolean


QVariant nullable=model->index(rowIndex, columnIndex).data(Qt::EditRole);
bool isNullable=nullable.isValid() ? nullable.toBool() : defaultValue; //replace defaultValue with true or false depending on your scenario


Hope this is useful.