Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Delegate + Multi-Line Text
QtWS25 Last Chance

Delegate + Multi-Line Text

Scheduled Pinned Locked Moved General and Desktop
2 Posts 1 Posters 7.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Q Offline
    Q Offline
    qtnewb11
    wrote on last edited by
    #1

    I have a QTreeView, QStandardItemModel, and QStandardItems. The items that contain text I want to give the ability to be displayed over multiple lines within the treeview row it belongs to which is a word-wrapping effect. I'm not sure how to achieve this using a custom delegate, paint, and size hint functions. I also want it to key off the column size so when the treeview is expanded the 'word wrapping' effect will adjust as necessary. Any help would be appreciated. Below is the skeleton, but I'm not sure how to make use of the two key functions to get the desired results.

    wordwrapdelegate.h
    @
    #ifndef WORDWRAPITEMDELEGATE_H
    #define WORDWRAPITEMDELEGATE_H

    #include <QStyledItemDelegate>
    #include <QWidget>
    #include <QtGui>

    class WordWrapItemDelegate : public QStyledItemDelegate
    {
    Q_OBJECT

    public:
    WordWrapItemDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) {}

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

    };

    #endif // WORDWRAPITEMDELEGATE_H
    @

    wordwrapdelegate.cpp
    @
    #include <QtGui>

    #include "wordwrapitemdelegate.h"

    void WordWrapItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
    //Try and word wrap strings
    if(qVariantCanConvert<QString>(index.data()))
    {
    painter->save();

        QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
        if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
            cg = QPalette::Inactive;
    
        //set pen color depending on behavior
        if (option.state & QStyle::State_Selected)
            painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
        else
            painter->setPen(opt.palette.color(cg, QPalette::Text));
    
        QString text = qvariant_cast<QString>(index.data());
        QFont font = QApplication::font();
    
        painter->setFont(font);
    
        //How to break text into multiple lines and re-size row accordingly?
    
        painter->restore();
    }
    else
    {
        //Fall back on original
        QStyledItemDelegate::paint(painter, option, index);
    }
    

    }

    QSize WordWrapItemDelegate::sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const
    {
    //Try and word wrap strings
    if(qVariantCanConvert<QString>(index.data()))
    {
    //How to figure out size hint?
    return( QSize() );
    }
    else
    {
    //Fall back on original size hint of item
    return QStyledItemDelegate::sizeHint(option, index);
    }
    }
    @

    1 Reply Last reply
    0
    • Q Offline
      Q Offline
      qtnewb11
      wrote on last edited by
      #2

      I sort of figured it out, but have some issues.

      1)When rendered there are issues with the height of items (word-wrapped or not word-wrapped), the rectangle has padding at the top and bottom which I don't want
      2)Selecting an item makes it vanish and doesn't provide normal highlighting behavior
      3)Editing an item puts it back to a single line and doesn't provide word wrapping (which is fine, but I coded it to include word wrapping for presentational purposes and it's not working).

      I'm using a text layout to figure out word wrapping and I also want to provide the '...' truncating functionality b/c I don't want to allow extremely large entries of dozens of lines to be displayed, those I just defer to tool tips.

      Any help would be appreciated.

      wordwrapitemdelegate.h
      @
      #ifndef WORDWRAPITEMDELEGATE_H
      #define WORDWRAPITEMDELEGATE_H

      #include <QStyledItemDelegate>
      #include <QWidget>
      #include <QtGui>

      #define LINE_LIMIT 5 /Truncate with ... after a certain amount of word wrapped lines/

      class WordWrapItemDelegate : public QStyledItemDelegate
      {
      Q_OBJECT

      public:
      WordWrapItemDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) {}

      void paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index) const;
      QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
      void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &) const;
      

      private:
      void details( QString text, QFont font, const QStyleOptionViewItem &option, int *lineCount, int *widthUsed ) const;
      };

      #endif // WORDWRAPITEMDELEGATE_H
      @

      wordwrapitemdelegate.cpp
      @
      #include <QtGui>

      #include "wordwrapitemdelegate.h"

      void WordWrapItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
      {
      int widthUsed, lineCount;

      //Try and word wrap strings
      if(qVariantCanConvert<QString>(index.data()))
      {
          painter->save();
      
          QPalette::ColorGroup group = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
          if (group == QPalette::Normal && !(option.state & QStyle::State_Active))
              group = QPalette::Inactive;
      
          //set pen color depending on behavior
          painter->setFont( QApplication::font() );
          if (option.state & QStyle::State_Selected)
              painter->setPen(option.palette.color(group, QPalette::HighlightedText));
          else
              painter->setPen(option.palette.color(group, QPalette::Text));
      
          //Text from item
          QString text = index.data(Qt::DisplayRole).toString();
      
          //Begin word-wrapping effect (use the provided rectangles width to determine when to wrap)
          details(text, QApplication::font(), option, &lineCount, &widthUsed);
      
          //Word wrap the text, 'elide' it if it goes past a pre-determined maximum
          QString newText = painter->fontMetrics().elidedText(text, Qt::ElideRight, widthUsed);
          painter->drawText( option.rect, (Qt::TextWrapAnywhere|Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft), newText );
          painter->restore();
      }
      else
      {
          //Fall back on original
          QStyledItemDelegate::paint(painter, option, index);
      }
      

      }

      QSize WordWrapItemDelegate::sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const
      {
      int widthUsed, lineCount;

      //Try and word wrap strings
      if(qVariantCanConvert<QString>(index.data()))
      {
          //Update the size based on the number of lines (original size of a single line multiplied
          //by the number of lines)
          QString text = index.data(Qt::DisplayRole).toString();
          details(text, QApplication::font(), option, &lineCount, &widthUsed);
      
          QSize size = QStyledItemDelegate::sizeHint(option, index);
          size.setHeight(lineCount *  size.height());
      
          return size;
      }
      else
      {
          //Fall back on original size hint of item
          return QStyledItemDelegate::sizeHint(option, index);
      }
      

      }

      void WordWrapItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index ) const
      {
      int lineCount, widthUsed;

      //Fix editor's geometry and produce the word-wrapped effect for strings...
      if(qVariantCanConvert<QString>(index.data()))
      {
          //We need to expand our editor accordingly (not really necessary but looks nice)
          QString text = index.data(Qt::DisplayRole).toString();
          details(text, QApplication::font(), option, &lineCount, &widthUsed);
      
          //Expand
          QSize extraSize = QSize(option.rect.width(), lineCount * option.rect.height());
          QRect extraRect = option.rect;
          extraRect.setSize(extraSize);
          editor->setGeometry(option.rect);
      }
      else
      {
          //Fall back on original update
          QStyledItemDelegate::updateEditorGeometry(editor, option, index);
      }
      

      }

      void WordWrapItemDelegate::details( QString text, const QFont font, const QStyleOptionViewItem &option, int *lineCount, int *widthUsed ) const
      {
      //Use text layout to word-wrap and provide informmation about line counts and width's
      QTextLayout textLayout(text);

      *widthUsed = 0;
      *lineCount = 0;
      textLayout.setFont(font);
      textLayout.beginLayout();
      while (*lineCount < LINE_LIMIT)
      {
          *lineCount = *lineCount + 1;
          QTextLine line = textLayout.createLine();
          if (!line.isValid())
              break;
      
          line.setLineWidth(option.rect.width());
          *widthUsed = (*widthUsed + line.naturalTextWidth());
      }
      textLayout.endLayout();
      *widthUsed = (*widthUsed + option.rect.width());
      

      }
      @

      1 Reply Last reply
      0

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved