QTextLayout手动换行

QTextLayout manual line breaking

本文关键字:换行 QTextLayout      更新时间:2023-10-16

我试图使用QTextLayout逐个渲染行。我尝试将wrapMode设置为QTextOption::ManualWrap,并为每行调用QTextLine::setNumColumns,但整个文本出现在一行中。

我也尝试将wrapMode设置为QTextOption::WrapAnywhere,这次文本被分成几行,但空行(仅由n组成的行)不可见。

我试着链接Qt4Qt5,没有结果。

我做错了什么?

QTextLine用于单行文本。如果你想要多行,那么使用QTextEdit

事实证明,Qt通过为每一行创建一个新的QTextLayout来实现这一点。详细信息请参见QPlainTextEdit::paintEvent(QPaintEvent *)源代码

您可以使用QTextLine::setNumColumns()来指定在当前行中断之前适合的字符数。如果你知道你的文本行长度,你可以在你想要的地方断行。换行符似乎被QTextLayout忽略了。

QTextOption opt;
opt.setWrapMode(QTextOption::WrapAnywhere);
QStringList text;
text.append("First line");
text.append("Another line");
layout.setText(text.join(""));
layout.beginLayout();
qreal h = 0;
for(const auto& line : text)
{
   QTextLine l = layout.createLine();
   if(!l.isValid()
      break;
   l.setNumColumns(line.length());
   l.setPosition(QPointF(0, h);
   h += l.height();
}
layout.endLayout();

其中layoutQTextLayout,您可以将其定义为部件类中的成员或其他任何成员。但是请注意(至少在Qt 4.8.x中),如果您使用选项卡,这可能不会像预期的那样工作。我试图创建一个布局,其中有一个右和一个左制表位(可以通过QTextOptionQTextOption::Tab配置),但我不知道如何让它正确设置换行符。计算以像素为单位的线宽也不容易,因为QFontMetrics::size()不支持除左对齐的制表符以外的制表符。

QTextLine by QTextLayout.createLine();

QTextLayout可以绘制一个QTextBlockENTER字符或键创建新的QTextBlock。因此,您必须为每个块绘制布局。

QTextBlock不包含"n"字符,因为该字符将文本分割为新的QTextBlock

我使用这个示例:

class KonuIcerik : public QGraphicsTextItem
{
public:
    QRectF boundingRect() const
    {
        return QRectF( 0 , 0 , this->LineWidth , this->height );
    }

    int height;
    int LineWidth;
    int LineCountMod;
    int CallNumber;
    QString metin;
    QFont font;
    QTextEdit* textEdit;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
               QWidget *widget)
    {
        int y = 0 ;
        CallNumber = 0;
        int PageNumber = 1;
        for( int i = 0 ; i < textEdit->document()->blockCount() ; i++ ){
            QTextBlock block = textEdit->document()->findBlockByNumber(i);
            QTextLayout layout(block);
            layout.setFont(font);
            layout.beginLayout();
            while( true ){
                QTextLine line = layout.createLine();
                if( !line.isValid() ){
                    break;
                }else{
                    if( CallNumber > 37 &&  (CallNumber-37) % LineCountMod == 0 ){
                        y += 300;
                        PageNumber++;
                    }
                    CallNumber++;
                    if( CallNumber == 37 ){
                        y += 300;
                        PageNumber++;
                    }
                    line.setLineWidth( LineWidth );
                    line.setPosition( QPointF( 0 , y ) );
                    y += line.height();
                }
            }
            this->height = y;
            layout.endLayout();
            layout.draw(painter,QPointF(0,0));
        }
    }
    void UPdate(){
        update(-50,-50 , LineWidth+50 , height+50);
    }
};

引用这个类,如果"n"包含,就会看到新行。我希望这对你有帮助。

我通过手动检查QTextLine

中的换行字符解决了这个问题
bool ElidedLabelPrivate::doTextLayout(QTextLayout &text_layout, int width,
                                      int height) const {
  /// if height <= 0 - no height limit
  int line_spacing = QFontMetrics(text_layout.font()).lineSpacing();
  qreal height_used = 0;
  qreal width_used = 0;
  const QString &text = text_layout.text();
  while (true) {
    QTextLine line = text_layout.createLine();
    if (!line.isValid()) {
      return true;  // text fits available size
    }
    line.setLineWidth(width);
    // check for line breaks
    const QStringRef line_text =
        text.midRef(line.textStart(), line.textLength());
    if (line_text.contains('n')) {
      line.setNumColumns(line_text.indexOf('n') + 1);
    }
    
    line.setPosition(QPointF(0, height_used));
    height_used += line_spacing;
    width_used = std::max(width_used, line.naturalTextWidth());
    int current_pos = line.textStart() + line.textLength();
    bool need_next_line = current_pos < text_layout.text().length();
    bool can_insert_line =
        (height <= 0) || (height_used + line_spacing <= height);
    if (need_next_line && !can_insert_line) {
      return false;
    }
  }
}