Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

How to style background in delegate for QCompleter?



  • Hello all. I have a question related to this post: https://stackoverflow.com/questions/1956542/how-to-make-item-view-render-rich-html-text-in-qt#new-answer.
    The post helped me get started which was to have only part of my auto completion bold. I got that using the example and then using html b tags. I also want to style the rows. I can get the text to change colors on mouseover, selection, etc, but I can't seem to style the background color now, any ideas? Here is where I'm at:

    void HtmlDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        QStyleOptionViewItemV4 optionV4 = option;
        initStyleOption(&optionV4, index);
    
        QStyle *style = optionV4.widget? optionV4.widget->style() : QApplication::style();
    
        QTextDocument doc;
        doc.setHtml(optionV4.text);
    
        //Painting item without text
        optionV4.text = QString();
        style->drawControl(QStyle::CE_ItemViewItem, &optionV4, painter);
    
        QAbstractTextDocumentLayout::PaintContext ctx;
    
        //Highlighting text if item is selected
        if (optionV4.state & QStyle::State_Off){
            ctx.palette.setColor(QPalette::Background, QColor("#EEEEEE"));
        }
        if (optionV4.state & QStyle::State_Selected){
            ctx.palette.setColor(QPalette::Background, QColor("#0A246A"));
            ctx.palette.setColor(QPalette::Text, QColor("#FFFFFF"));
        }
        if (optionV4.state & QStyle::State_MouseOver){
            ctx.palette.setColor(QPalette::Background, QColor("#0A246A"));
            ctx.palette.setColor(QPalette::Text, QColor("#FFFFFF"));
        }
    
        QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &optionV4);
        painter->save();
        painter->translate(textRect.topLeft());
        painter->setClipRect(textRect.translated(-textRect.topLeft()));
        doc.documentLayout()->draw(painter, ctx);
        painter->restore();
    }
    
    QSize HtmlDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        QStyleOptionViewItemV4 optionV4 = option;
        initStyleOption(&optionV4, index);
    
        QTextDocument doc;
        doc.setHtml(optionV4.text);
        doc.setTextWidth(optionV4.rect.width());
        return QSize(doc.idealWidth(), doc.size().height());
    }
    

    And this is the output, showing both selected and mouseover which are NOT doing the background I want (the blank row is actually where I have my cursor/mouseover state, showing again white text change but not background):

    0_1552607525878_StyledCompleter.png

    UPDATE: I don't get it, I tried everything. Tried different roles (Base, Windows, Highlight), tried messing with optionV4, style and doc where I could. Tried setting completer popup stylesheet after setting delegate. I just want my hover/select background color! Thanks.


  • Lifetime Qt Champion

    Hi,

    The QPalette documentation states that:

    Warning: Some styles do not use the palette for all drawing, for instance, if they make use of native theme engines. This is the case for both the Windows Vista and the macOS styles.
    

    I wonder if you are hitting that.



  • I think so. I got a little further doing it differently. Here is my current code where I removed the pallete stuff for background and instead added a painter->fillRect(), well, it did something. I now get what I want for just the first item in the list, both by selection and mouseover as expected, but it doesn't work for the rest of the list!

    void HtmlDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        QStyleOptionViewItemV4 optionV4 = option;
        initStyleOption(&optionV4, index);
    
        QStyle *style = optionV4.widget? optionV4.widget->style() : QApplication::style();
    
        QTextDocument doc;
        doc.setHtml(optionV4.text);
    
        //Painting item without text
        optionV4.text = QString();
        style->drawControl(QStyle::CE_ItemViewItem, &optionV4, painter);
    
        QAbstractTextDocumentLayout::PaintContext ctx;
    
        //Highlighting text if item is selected
        if ((optionV4.state & QStyle::State_Selected) || (optionV4.state & QStyle::State_MouseOver)){
            ctx.palette.setColor(QPalette::Text, QColor("#FFFFFF"));
        }
    
        QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &optionV4);
        painter->save();
        painter->translate(textRect.topLeft());
        painter->setClipRect(textRect.translated(-textRect.topLeft()));
        if ((optionV4.state & QStyle::State_Selected) || (optionV4.state & QStyle::State_MouseOver))
            painter->fillRect(optionV4.rect, QBrush(QColor("#0A246A")));
        doc.documentLayout()->draw(painter, ctx);
        painter->restore();
    }
    

    Here's this, first item selected, looks right, others (you can see where my mouse is) still just the white text:
    0_1552607544854_StyledCompleter2.png


  • Lifetime Qt Champion

    Did you check that the rectangle you are painting is correct ? You might be over-painting the same cell.



  • I think so. I tried EVERYTHING and still couldn't get this to work correctly, however they have accepted it as is.
    I have a new issue related to this. QCompleter has a function setMaxVisibleItems which I now want to set to 11 so it doesn't extend over some other elements. Well, if I comment out my delegate:

    HtmlDelegate* mpDelegate = new HtmlDelegate();
    mpCompleter->popup()->setItemDelegate(mpDelegate);
    

    Then the max items works. However, with my delegate set (to at least get the bold name and not bold number) this no longer does, it somehow overrides the max items in the parent QCompleter, feels like a Qt bug. I can at least still set max height on the popup, but then it still gets placed where it would if it was taller so there's a huge space between the field and the popup! This a bug in Qt? There a way around it?


  • Lifetime Qt Champion

    Can you provide a minimal compilable project with your delegate ?

    This will allow to test that more easily.


Log in to reply