PDA

View Full Version : Reimplement paint() in QItemDelegate



john_erlandsson
19th January 2012, 03:37
Hi!

I have subclassed a QSqlQueryModel and a QItemDelegate. Making a column containing a date editable, and displayed as a QCheckBox. Cell contains a date = checked cell is null = not checked. Checking a cell = insert todays date, unchecking a cell = set date to "".

The only thing left to do is to allways display the checkbox delegate, even when not editing. After a bit of googling I found out that i have to reimplement the paint() function in my QItemDelegate, to display a CheckBox instead of text.

The problem is that i have no idea where to begin. The manual gives a short example, but it doesent make much sense to me.

Does anyone know of a better example?

The implementation of my QItemDelegate (Basically yanked from the SpinBoxDelegate example):

#include "economyhoursattdelegate.h"
#include <QCheckBox>
#include <QDate>

/* Constructor
*
*/
EconomyHoursAttDelegate::EconomyHoursAttDelegate(Q Object *parent) :
QItemDelegate(parent)
{
}

/* Reimplemented function: createEditor
* Create a QCheckbox in the att column
*/
QWidget *EconomyHoursAttDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &/*option*/,
const QModelIndex &/*index*/ ) const
{
QCheckBox *editor = new QCheckBox( parent );

return editor;
}

/* Reimplemented function: setEditorData
* Set the checkbox checked if cell contains a date
*/
void EconomyHoursAttDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
{
QString value = index.model()->data( index, Qt::EditRole ).toString();

QCheckBox *checkBox = static_cast<QCheckBox*>(editor);

bool checked = value == "" ? false : true;

checkBox->setChecked( checked );
}

/* Reimplemented function: setModelData
* Set model data to todays date if the checkbox is checked
*/
void EconomyHoursAttDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index ) const
{
QCheckBox *checkBox = static_cast<QCheckBox*>(editor);

QDate now = QDate::currentDate();

if( checkBox->isChecked() )
model->setData( index, now, Qt::EditRole );
else
model->setData( index, QString(), Qt::EditRole );
}

/* Reimplemented function: updateEditorGeometry
* Adjust the size of the checkbox to fit the cell size
*/
void EconomyHoursAttDelegate::updateEditorGeometry( QWidget *editor, const QStyleOptionViewItem &option,
const QModelIndex &/*index*/ ) const
{
editor->setGeometry( option.rect );
}


Any help is apreciated...

//John

wysota
19th January 2012, 10:49
How about using Qt::CheckStateRole in your model instead?

john_erlandsson
19th January 2012, 17:53
How about using Qt::CheckStateRole in your model instead?

I am sorry, but i don't follow. Could you elaborate?

This is the implementation of my model:

#include "economyhoursmodel.h"
#include <QSqlQuery>
#include <QDebug>

/* Constructor
*
*/
EconomyHoursModel::EconomyHoursModel( QObject *parent ) :
QSqlQueryModel( parent )
{
}

/* Reimplemented function: flags
* Set the att coulumn editable flag
*/
Qt::ItemFlags EconomyHoursModel::flags( const QModelIndex &index ) const
{
Qt::ItemFlags flags = QSqlQueryModel::flags( index );

if( index.column() == 3 )
flags |= Qt::ItemIsEditable;

return flags;
}

/* Reimplemented function: setData
* Sets data for the att column
*/
bool EconomyHoursModel::setData( const QModelIndex &index, const QVariant &value, int /*role*/ )
{
if( index.column() != 3 )
return false;

QModelIndex idIndex = QSqlQueryModel::index( index.row(), 4 );

int id = data( idIndex ).toInt();

clear();

QSqlQuery query;
query.prepare( "UPDATE hours SET att=? WHERE id=?" );
query.addBindValue( value );
query.addBindValue( id );

bool ret = query.exec();

if( ret )
refresh();

return ret;
}

/* Public function: refresh
* Refresh the query with current start and end date
*/
void EconomyHoursModel::refresh()
{
QSqlQuery query;

query.prepare( "SELECT hours.date, hours.hours, repairmen.name, hours.att, hours.id\n"
"FROM hours\n"
"LEFT JOIN repairmen\n"
"ON repairmen.id=hours.repairmen_id\n"
"WHERE hours.date>=? AND hours.date<=?;" );
query.addBindValue( StartDate );
query.addBindValue( EndDate );

query.exec();

setQuery( query );

setHeaderData( 0, Qt::Horizontal, "Datum" );
setHeaderData( 1, Qt::Horizontal, "Antal" );
setHeaderData( 2, Qt::Horizontal, "Reparatör" );
setHeaderData( 3, Qt::Horizontal, "Att" );
setHeaderData( 4, Qt::Horizontal, "ID" );
}

/* Public function: setStartDate
* set start date for the query and refresh
*/
void EconomyHoursModel::setStartDate( QDate date )
{
StartDate = date;
refresh();
}

/* Public function: setEndDate
* set end date for the query and refresh
*/
void EconomyHoursModel::setEndDate( QDate date )
{
EndDate = date;
refresh();
}

wysota
19th January 2012, 21:22
Check state role allows you to store information about each item in regards of whether it is checked or unchecked and display and edit that information using a standard delegate. I'm sure some of Qt model-view examples demonstrate it.

john_erlandsson
19th January 2012, 21:37
Solved it!

Nice solution. I removed my delegate and reimplemented these functions in my model:

/* Reimplemented function: flags
* Set the att coulumn editable flag
*/
Qt::ItemFlags EconomyHoursModel::flags( const QModelIndex &index ) const
{
Qt::ItemFlags flags = QSqlQueryModel::flags( index );

if( index.column() == 5 )
flags |= Qt::ItemIsEditable | Qt::ItemIsUserCheckable;

return flags;
}

/* Reimplemented function: data
* Have to reimplement this in order to show a checkbox when not editing the table
*/
QVariant EconomyHoursModel::data(const QModelIndex &index, int role) const
{
QVariant ret;

if( role == Qt::CheckStateRole && index.column() == 5 )
{
if( QSqlQueryModel::data( index, Qt::DisplayRole ).toString() == "" )
ret = Qt::Unchecked;
else
ret = Qt::Checked;
}
else if( role == Qt::DisplayRole && index.column() == 5 ) //Don't show date as text
{
ret = QVariant();
}
else
{
ret = QSqlQueryModel::data( index, role );
}

return ret;
}

/* Reimplemented function: setData
* Sets data for the att column
*/
bool EconomyHoursModel::setData( const QModelIndex &index, const QVariant &value, int role )
{
bool ret = false;

if( role == Qt::CheckStateRole )
{
if( index.column() != 5 )
return false;

QModelIndex idIndex = QSqlQueryModel::index( index.row(), 0 );

int id = data( idIndex ).toInt();

QString storeValue = "";

if( value.toInt() == Qt::Checked )
storeValue = QDate::currentDate().toString( "yyyy-MM-dd" );

clear();

QSqlQuery query;
query.prepare( "UPDATE hours SET att=? WHERE id=?" );
query.addBindValue( storeValue );
query.addBindValue( id );

ret = query.exec();

if( ret )
refresh();
}
else
{
ret = QSqlQueryModel::setData( index, value, role );
}

return ret;
}


Thanks for pointing me in the right direction!!!

//John