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

How to calculate line while wrapping text in QLIstview



  • Hi,

    I am working on messaging application. I have a delegate which arrange text in different rect to draw text. I have to show - Name, date and time, Subject, Message , message status Icon. It doesnt work well (ie it create extra lines) in case if word is long . There is some problem in calculating in sizeHint but i tried different scenarios and couldnt make it working . for long text there are always extra lines coming in QLIstView .
    Please check the link below :
    !http://tinypic.com/r/34dt1de/5(Message shown in QListView)!

    Here's the code for this:
    @
    QSize ConversationViewItemDelegate::sizeHint(const QStyleOptionViewItem& , const QModelIndex& index) const
    {
    QString str = index.data().toString();

    QListView *view = (QListView*)parent();
    QFontMetrics fontMetrics(view->font());
    
    QStringList words = str.split(QChar(' '));
    words.removeAll("\n");
    QStringList lines = str.split(QChar('\n'));
    int noOfLines = lines.size();
    
    QRectF boundingRect = fontMetrics.boundingRect(str);
    int width = view->viewport()->width() -35;
    int height = boundingRect.height();
    int times = 0;
    while (words.size() > 0)
    {
        times++;
        qreal lineWidth = 0;
        bool enoughSpace = true;
        do
        {
            QString word = words.first();
            qreal wordWidth = fontMetrics.width(word);
            wordWidth = wordWidth + lineWidth;
            lineWidth = 0;
            if(wordWidth > width)
            {
                times++;
                while(wordWidth > width )
                {
                    times++;
                    wordWidth -= width;
                }
                lineWidth += wordWidth;
                lineWidth += fontMetrics.width(QChar(' '));
                words.removeFirst();
            }
            else if (wordWidth < width)
            {
                lineWidth += wordWidth;
                lineWidth += fontMetrics.width(QChar(' '));
                words.removeFirst();
            }
            else
                enoughSpace = false;
        }
        while (enoughSpace && words.size() > 0);
    }
    
    height = height * times  + (noOfLines + 3)* boundingRect.height() - times;
    QSize sizeOfSubjectField = QSize();
    if (!index.model()->data(index, ConversationViewMsgSubjectRole).toString().isEmpty())
    {
     QString subject = "Subject: " +  index.model()->data(index, ConversationViewMsgSubjectRole).toString();
     sizeHintforSubject(subject);
    }
    else
    {
        height = height - boundingRect.height();
    }
    
    height += sizeOfSubjectField.height();
    return QSize(width,  height);
    

    }

    QSize ConversationViewItemDelegate::sizeHintforSubject(QString str) const
    {
    QListView p = (QListView)parent();
    QString text = str;
    QFontMetrics fm(p->font());

    float rw = float(p->viewport()->size().width());
    float tw = fm.width(text);
    float ratio = tw/rw;
    int lines = int(ratio) + 1;
    return QSize(rw,lines*fm.height());
    

    }

    @



  • the paint function code is as follows:
    @void ConversationViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex & index) const
    {

    QString displayName = index.model()->data(index, ConversationViewDisplayNameRole).toString();
    QString dateTime = index.model()->data(index, ConversationViewDateTimeRole).toString();
    bool messageStatus = index.model()->data(index, ConversationViewMsgReadRole).toBool();
    QString textMessage = index.model()->data(index, ConversationViewMessageRole).toString();
    
    QString subject = QString();
    
    if (!index.model()->data(index, ConversationViewMsgSubjectRole).toString().isEmpty())
    {
     subject = "Subject: " +  index.model()->data(index, ConversationViewMsgSubjectRole).toString();
    }
    
    QIcon messageStatusIcon =  index.model()->data(index, ConversationViewMsgStatusIcon).value<QIcon>();
    QPixmap pMessageStatusPixmap = messageStatusIcon.pixmap(option.decorationSize);
    
    QRect messageRect = option.rect;
    QRect dateTimeRect = option.rect;
    QRect boundaryRect = option.rect;
    QRect displayNameRect = option.rect;
    QRect sendMessageIconRect = option.rect;
    QRect subjectRect = option.rect;
    
    dateTimeRect.setTop(dateTimeRect.top()+5);
    dateTimeRect.setBottom(dateTimeRect.top()+15);
    dateTimeRect.setLeft(dateTimeRect.right()- 110);
    dateTimeRect.setRight(dateTimeRect.right()-5);
    
    displayNameRect.setTop(displayNameRect.top()+5);
    displayNameRect.setBottom(displayNameRect.top()+15);
    displayNameRect.setLeft(displayNameRect.left()+5);
    displayNameRect.setRight(displayNameRect.right()-120);
    
    boundaryRect.setRight(boundaryRect.right() - 2);
    boundaryRect.setLeft(boundaryRect.left() + 2);
    
    if(!index.model()->data(index, ConversationViewMsgSubjectRole).toString().isEmpty())
    {
        QSize a  = sizeHintforSubject(subject);
        subjectRect.setTop(dateTimeRect.bottom() + 2);
        subjectRect.setLeft(subjectRect.left() + 10);
        subjectRect.setRight(subjectRect.right() - 35);
        subjectRect.setBottom(subjectRect.top() + a.height());
    
        messageRect.setTop(subjectRect.bottom()+ 5);
        messageRect.setRight(messageRect.right() - 5);
    }
    else
    {
        messageRect.setTop(dateTimeRect.bottom()+10);
        messageRect.setRight(messageRect.right() - 25);
    }
    messageRect.setLeft(messageRect.left() + 10);
    messageRect.setBottom(messageRect.bottom() - 5);
    
    sendMessageIconRect.setTop(dateTimeRect.bottom()+2 );
    sendMessageIconRect.setRight(sendMessageIconRect.right()-5);
    sendMessageIconRect.setLeft(sendMessageIconRect.right()- 20);
    sendMessageIconRect.setBottom(dateTimeRect.bottom()+20);
    
    QFont boldFont = QApplication::font();
    boldFont.setBold(true);
    QFont normalFont = QApplication::font();
    QFont italicFont = QApplication::font();
    italicFont.setItalic(true);
    
    //Change color in message is UNREAD
    if(!messageStatus)
    {
       painter->fillRect(boundaryRect, "#C0C0C0");
    }
    //Set selected Message item color
    if (option.state & QStyle::State_Selected)
         painter->fillRect(boundaryRect, "#C8E0FD");
    
    painter->save();
    painter->drawRoundedRect(boundaryRect, 3, 3);
    painter->drawText(dateTimeRect, Qt::AlignLeft  , dateTime);
    painter->drawPixmap(sendMessageIconRect, pMessageStatusPixmap);
    
    QTextOption opt ;
    opt.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
    painter->drawText(messageRect,textMessage, opt );
    
    painter->setFont(italicFont);
    painter->drawText(subjectRect,subject, opt );
    painter->setFont(boldFont);
    painter->drawText(displayNameRect, Qt::AlignLeft  , displayName);
    
    
    painter->restore();
    

    }@

    some how the pic didnt come . the link for it is http://tinypic.com/r/34dt1de/5



  • Any suggestions ????


  • Moderators

    what is exactly the problem?!
    the image you've posted seems ok?



  • Hi Raven,

    Thanks for the reply. Actually I am trying to make a chat view using QLIstview to show previous msges. The problem which i am facing is that where the text is very long there are extra space (extra number of lines from size hint) in list view item. i checked the previous post and wrote the size hint , it works only for small texts. If i show long text having long words then extra spaces comes in list view item. I am using WrapAtWordBoundaryOrAnywhere .

    Regards,
    Prankur


  • Moderators

    maybe your text contains "\n" which cause the extra line breaks?


Log in to reply