一种qt绘制多行文本是自定义行高的解决办法

qt重没有该接口,很郁闷,经过多方研究,甚至阅读qt源码,终于找到一种方法

从源码中抽出一个方法

void qt_format_text(const QFont &fnt, const QRectF &_r,

                    int tf, const QTextOption *option, const QString& str, QRectF *brect,
                    int tabstops, int *ta, int tabarraylen,
                    QPainter *painter)
{
    Q_ASSERT( !((tf & ~Qt::TextDontPrint)!=0 && option!=0) ); // we either have an option or flags
    if (option) {
        tf |= option->alignment();
        if (option->wrapMode() != QTextOption::NoWrap)
            tf |= Qt::TextWordWrap;
        if (option->flags() & QTextOption::IncludeTrailingSpaces)
            tf |= Qt::TextIncludeTrailingSpaces;
        if (option->tabStop() >= 0 || !option->tabArray().isEmpty())
            tf |= Qt::TextExpandTabs;
    }
    // we need to copy r here to protect against the case (&r == brect).
    QRectF r(_r);
    bool dontclip  = (tf & Qt::TextDontClip);
    bool wordwrap  = (tf & Qt::TextWordWrap) || (tf & Qt::TextWrapAnywhere);
    bool singleline = (tf & Qt::TextSingleLine);
    bool showmnemonic = (tf & Qt::TextShowMnemonic);
    bool hidemnmemonic = (tf & Qt::TextHideMnemonic);
    qDebug()<<"wordwrap is:"<<wordwrap;
    Qt::LayoutDirection layout_direction;
    if (tf & Qt::TextForceLeftToRight)
        layout_direction = Qt::LeftToRight;
    else if (tf & Qt::TextForceRightToLeft)
        layout_direction = Qt::RightToLeft;
    else if (option)
        layout_direction = option->textDirection();
    else if (painter)
        layout_direction = painter->layoutDirection();
    else
        layout_direction = Qt::LeftToRight;
    //tf = QGuiApplicationPrivate::visualAlignment(layout_direction, QFlag(tf));
    bool isRightToLeft = layout_direction == Qt::RightToLeft;
    bool expandtabs = ((tf & Qt::TextExpandTabs) &&
                        (((tf & Qt::AlignLeft) && !isRightToLeft) ||
                          ((tf & Qt::AlignRight) && isRightToLeft)));
    if (!painter)
        tf |= Qt::TextDontPrint;
    uint maxUnderlines = 0;
    QFontMetricsF fm(fnt);
    QString text = str;
    int offset = 0;
start_lengthVariant:
    bool hasMoreLengthVariants = false;
    // compatible behaviour to the old implementation. Replace
    // tabs by spaces
    int old_offset = offset;
    for (; offset < text.length(); offset++) {
        QChar chr = text.at(offset);
        if (chr == QLatin1Char('\r') || (singleline && chr == QLatin1Char('\n'))) {
            text[offset] = QLatin1Char(' ');
        } else if (chr == QLatin1Char('\n')) {
            text[offset] = QChar::LineSeparator;
        } else if (chr == QLatin1Char('&')) {
            ++maxUnderlines;
        } else if (chr == QLatin1Char('\t')) {
            if (!expandtabs) {
                text[offset] = QLatin1Char(' ');
            } else if (!tabarraylen && !tabstops) {
                tabstops = qRound(fm.width(QLatin1Char('x'))*8);
            }
        } else if (chr == QChar(ushort(0x9c))) {
            // string with multiple length variants
            hasMoreLengthVariants = true;
            break;
        }
    }
    QVector<QTextLayout::FormatRange> underlineFormats;
    int length = offset - old_offset;
    if ((hidemnmemonic || showmnemonic) && maxUnderlines > 0) {
        QChar *cout = text.data() + old_offset;
        QChar *cout0 = cout;
        QChar *cin = cout;
        int l = length;
        while (l) {
            if (*cin == QLatin1Char('&')) {
                ++cin;
                --length;
                --l;
                if (!l)
                    break;
                if (*cin != QLatin1Char('&') && !hidemnmemonic && !(tf & Qt::TextDontPrint)) {
                    QTextLayout::FormatRange range;
                    range.start = cout - cout0;
                    range.length = 1;
                    range.format.setFontUnderline(true);
                    underlineFormats.append(range);
                }
            }
            *cout = *cin;
            ++cout;
            ++cin;
            --l;
        }
    }
    qreal height = 0;
    qreal width = 0;
    QString finalText = text.mid(old_offset, length);
    QTextLayout textLayout(finalText);
    textLayout.setFont(fnt);
    textLayout.setCacheEnabled(true);
    textLayout.setFormats(underlineFormats);
    if (finalText.isEmpty()) {
        height = fm.height();
        width = 0;
        tf |= Qt::TextDontPrint;
    } else {
        qreal lineWidth = 0x01000000;
        if (wordwrap || (tf & Qt::TextJustificationForced))
            lineWidth = qMax<qreal>(0, r.width());
        if(!wordwrap)
            tf |= Qt::TextIncludeTrailingSpaces;
        textLayout.beginLayout();
        qreal leading = fm.leading();
        leading=25;//此处控制行高,核心之处
        height = -leading;
        qDebug()<<QString("leading is:%1").arg(leading);
        while (1) {
            QTextLine l = textLayout.createLine();
            if (!l.isValid())
                break;
            l.setLineWidth(lineWidth);
            height += leading;
            // Make sure lines are positioned on whole pixels
            height = qCeil(height);
            l.setPosition(QPointF(0., height));
            width = qMax(width, l.naturalTextWidth());
            if (!dontclip && !brect && height >= r.height())
                break;
        }
        textLayout.endLayout();
    }
    qreal yoff = 0;
    qreal xoff = 0;
    if (tf & Qt::AlignBottom)
        yoff = r.height() - height;
    else if (tf & Qt::AlignVCenter)
        yoff = (r.height() - height)/2;
    if (tf & Qt::AlignRight)
        xoff = r.width() - width;
    else if (tf & Qt::AlignHCenter)
        xoff = (r.width() - width)/2;
    QRectF bounds = QRectF(r.x() + xoff, r.y() + yoff, width, height);
    if (hasMoreLengthVariants && !(tf & Qt::TextLongestVariant) && !r.contains(bounds)) {
        offset++;
        goto start_lengthVariant;
    }
    if (brect)
        *brect = bounds;
    if (!(tf & Qt::TextDontPrint)) {
        bool restore = false;
        if (!dontclip && !r.contains(bounds)) {
            restore = true;
            painter->save();
            painter->setClipRect(r, Qt::IntersectClip);
        }
        for (int i = 0; i < textLayout.lineCount(); i++) {
            qDebug()<<QString("at text line:%1").arg(i);
            QTextLine line = textLayout.lineAt(i);
            xoff = 0;
            line.draw(painter, QPointF(r.x() + xoff, r.y() + yoff));
        }
        if (restore) {
            painter->restore();
        }
    }
}

调用的时候把drawText替换成以下形式就可以了

//painter.drawText(QRect(leftSpace, totalHeight, viewRect.width()-2*leftSpace, textAreaHeight),Qt::TextWordWrap|Qt::AlignLeft, ui->imageViewText->toPlainText());

 
  
        qt_format_text(font, QRect(leftSpace, totalHeight, viewRect.width()-2*leftSpace-40, textAreaHeight), Qt::TextWordWrap|Qt::AlignLeft, 0, ui->imageViewText->toPlainText(), 0, 0, 0, 0, &painter);
 
  

你可能感兴趣的:(c++)