Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Delegate + Multi-Line Text

    General and Desktop
    1
    2
    7153
    Loading More Posts
    • 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
      qtnewb11 last edited by

      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 Reply Quote 0
      • Q
        qtnewb11 last edited by

        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 Reply Quote 0
        • First post
          Last post