如何调整QTextEdit以适应其内容

8
我正在开发一个Qt应用程序,我正在尝试找到一种方法,使用QTextEdit作为一个没有滚动条的长文本标签。在我的UI中,我有一个QScrollArea,在其中我想放置几个QTextEdit小部件,并且我只想在QScrollArea内使用滚动。问题是无论如何调整QTextEdit的大小,它似乎都有一个最大高度并且会截断文本,即使我手动设置大小并且QTextEdit::size返回正确的值。
我用QLabel做了同样的事情,它工作得很好,但在这种情况下,我需要一些仅在QTextEdit中提供的方法。
我发现了这篇文章:Resizing QT's QTextEdit to Match Text Height: maximumViewportSize()
给出的答案如下:
我解决了这个问题。有两件事情我必须做才能让它工作: 1.向上遍历窗口部件层次结构,并确保所有大小策略都有意义,以确保如果任何子窗口部件想要变大/小,则父窗口部件将希望成为相同的东西。 2.这是修复的主要来源。事实证明,由于QTextEdit位于QScrollArea的主窗口部件中,因此QScrollArea有一个约束条件,即除非widgetResizable属性为true,否则它不会调整内部窗口部件的大小。其文档在此处:http://doc.qt.io/qt-4.8/qscrollarea.html#widgetResizable-prop。直到我尝试了这个设置并使其工作,文档才变得清晰明了。从文档中可以看出,此属性仅处理主滚动区域想要调整小部件的情况(即从父级到子级)。实际上,这意味着如果滚动区域中的主窗口部件想要调整大小(即从子级到父级),则必须将此设置设置为true。因此,故事的教训是QTextEdit代码在覆盖sizeHint时是正确的,但QScrollArea忽略了从主框架的sizeHint返回的值。
问题是我不知道如何访问QTextEdit的QScrollArea以启用widgetResizable。有人能解释一下我如何实现这一点或建议一种不同的方法来调整QTextEdit以完美地适应其内容吗?

你无法访问QTextEdit的QScrollArea,因为它不是QScrollArea,它继承自QAbstractScrollArea,而这个类没有setWidgetResizable标志。 - Llopeth
5个回答

4

这将允许文本框的高度根据需要更改。您可以稍微编辑代码来处理宽度。

connect( m_textField, SIGNAL( textChanged() ), this, SLOT( onTextChanged() ) );

void MyClass::onTextChanged()
{
  QSize size = m_textField->document()->size().toSize();

  m_textField->setFixedHeight( size.height() + 3 );
}

这对我不起作用 - 当框的内容被刷新时,尺寸在两个高度之间振荡,即使文本没有改变。 - Richard Whitehead
不起作用,高度始终为零。 - IceFire
不起作用,对我来说。 - HiFile.app - best file manager
这对我有效,如果对其他人无效,请确保 QTextEdit 小部件可见并显示在屏幕上,然后再调整其大小。如果编辑器未显示在屏幕上,您尝试使用此代码将不起作用(对我来说也是如此),但是如果您在 show() QTextEdit 后运行代码,则可以正常工作。 - marko
1
大小对我来说似乎是行数,所以应该乘以行高?(使用QPlainTextEdit) - thomasa88

3
尝试这个:

试一试:

QTextEdit textEdit;
textEdit.setHtml("<p>test test test test test test</p><p>|||||||||</p>");
textEdit.show();
textEdit.setFixedWidth(textEdit.document()->idealWidth() +
                       textEdit.contentsMargins().left() +
                       textEdit.contentsMargins().right());

1
在Python、Pyside 2和Qt 5.6.1中,idealWidth()在我的情况下返回-1。这可能与使用no wrap标志有关,但我没有检查。文档只是说textWidth默认为-1,我认为这是相关的。也许当-1时使用其他东西。 - Rafe

2
没有具体的例子很难判断,但是看起来你只是想要一个 QTextEdit,它的 sizeHint 取决于当前文档的大小。
class text_edit: public QTextEdit {
  using super = QTextEdit;
public:
  explicit text_edit (QWidget *parent = nullptr)
    : super(parent)
    {
      setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
      setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
      setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    }
  virtual QSize sizeHint () const override
    {
      QSize s(document()->size().toSize());

      /*
       * Make sure width and height have `usable' values.
       */
      s.rwidth() = std::max(100, s.width());
      s.rheight() = std::max(100, s.height());
      return(s);
    }
protected:
  virtual void resizeEvent (QResizeEvent *event) override
    {

      /*
       * If the widget has been resized then the size hint will
       * also have changed.  Call updateGeometry to make sure
       * any layouts are notified of the change.
       */
      updateGeometry();
      super::resizeEvent(event);
    }
};

然后将其用作...
QScrollArea sa;
sa.setWidgetResizable(true);
text_edit te;
te.setPlainText(...);
sa.setWidget(&te);
sa.show();

根据我所做的几项测试,它似乎按预期工作。


0
在编程中,我定义了一个名为QTextEdit *textEdit的对象,并将其写成可缩放内容的height
int count = 0;
QString str = "";

// set textEdit text
ui->textEdit->setText("hfdsf\ncsad\nfsc\dajkjkjkjhhkdkca\n925");
str = ui->textEdit->toPlainText();

for(int i = 0;i < str.length();i++)
    if(str.at(i).cell() == '\n')
        count++;

// resize textEdit (width and height)
ui->textEdit->resize(ui->textEdit->fontMetrics().width("this is the max-length line in qlabel")
         , ui->textEdit->fontMetrics().height() * (count + 2));

注意:如果您更改QTextEdit的字体或大小,则此工作将起作用!只在高度可缩放(在设置任何内容之前,将QTextEdit的frameShape设置为BOX)。

如果您想要进行宽度可缩放的内容,您应该执行以下步骤:

  • 逐行阅读QTextEdittextEdit对象)文本
  • 计算每行长度
  • 选择最大行长度
  • 使用QTextEdit::fontMetrics().width(QString str)来调查str在宽度上的大小

希望这可以帮助您...


感谢您的回答,问题在于首先我没有“\n”换行符 - 文本被自动换行了。其次,即使我知道正确的大小,QTextEdit 在某个点上只会提供滚动条而不是变得更大 - 这就是我的问题所在。 - madasionka
@madasionka,你能以任何方式“禁用”滚动条属性吗? - BattleTested_закалённый в бою
是的,通过设置:textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff),可以实现这一点,但这并不能改变某些文本被截断的事实。 - madasionka

0
我在我的情况下让它工作。
content_height = field.document().lineCount() * 30
field.setFixedHeight(content_height)
frame.setFixedHeight(content_height + 12)

在这里,“field”是添加到托管QFrame“frame”布局中的QTextEdit。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接