[Solved] Painting in custom delegate



  • Hi, I've created a custom delegate for use in in a class derived from QTableView. This delagate must display as a checkbox centered horizontally and vertically in table cell. I've managed to implement createEditor, setEditorData, setModelData and updateEditorGeometry methods correctly. Now I'm trying to implement the paint method. Below is my code:

    @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();
    
        QStyleOptionViewItem modifiedOption(option);
    
        QRect checkBoxRect=style->subElementRect(QStyle::SE_CheckBoxIndicator, &option);
        int centerX=option.rect.left() + qMax(option.rect.width()/2-checkBoxRect.width()/2, 0);
        int centerY=option.rect.top() + qMax(option.rect.height()/2-checkBoxRect.height()/2, 0);
        modifiedOption.rect.moveTo(centerX, centerY);
    
        if(boolVal){
            modifiedOption.state |= QStyle::State_On;
        }
    
        style->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &modifiedOption, painter);
    }else {
        QStyledItemDelegate::paint(painter, option, index);
    }
    

    }
    @
    On Linux this code works fine, also on Windows XP and Windows 7 with classic style everything is OK.But when I switch to modern styles (on Windows XP and 7) checkbox gets rendered at the bottom right corner of the table cell. On the other hand if I comment out these lines:

    @QRect checkBoxRect=style->subElementRect(QStyle::SE_CheckBoxIndicator, &option);
    int centerX=option.rect.left() + qMax(option.rect.width()/2-checkBoxRect.width()/2, 0);
    int centerY=option.rect.top() + qMax(option.rect.height()/2-checkBoxRect.height()/2, 0);
    modifiedOption.rect.moveTo(centerX, centerY);@

    then checkbox gets rendered at the top left corner of the cell in Linux and Windows classic styles (and at the center on Windows modern styles). I tried setting modifiedOption.decorationAlignment and displayAlignment to Qt::AlignHCenter | Qt::AlignVCenter but it did not help.

    How should I fix it? I want checkbox to be displayed at the center all the time.

    Thanks in advance!



  • I think I found solution:

    @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();
    
        QStyleOptionViewItem modifiedOption(option);
        modifiedOption.rect.moveTo(0, 0);
        modifiedOption.rect.setSize(QSize(chkWidth, chkHeight));
        if(boolVal){
            modifiedOption.state |= QStyle::State_On;
        }
    
        QPixmap checkboxPixmap(chkWidth, chkHeight);
        QPainter pixmapPainter(&checkboxPixmap);
        pixmapPainter.fillRect(0, 0, chkWidth, chkHeight, index.row()%2==0 ? qApp->palette().base() : qApp->palette().alternateBase());
        style->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &modifiedOption, &pixmapPainter);
    
        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);
    
        painter->drawPixmap(centerX, centerY, chkWidth, chkHeight, checkboxPixmap);
    }else {
        QStyledItemDelegate::paint(painter, option, index);
    }
    

    }@

    This seems to work in all scenarios.



  • Final version (just in case it will be useful to someone else):

    @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_IndicatorItemViewItemCheck, &modifiedOption, painter);
    }else {
        QStyledItemDelegate::paint(painter, option, index);
    }
    

    }@



  • this post is old, but not too much to say thank you! :D


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.