PyQt:当小部件内容更改时如何处理自动调整大小

12

我在qt4小部件大小随内容改变时遇到了一些问题。

我将用两个简单的场景来说明我的问题:

场景1:

我有一个QLineEdit小部件。有时,当我使用QLineEdit.setText()更改其内容时,一行字符串无法适合当前大小的小部件中。我必须选择小部件并使用箭头键在两个方向上滚动字符串以查看全部内容。

场景2:

我有一个QTextBrowser小部件。有时,当我使用QTextBrowser.setHtml()更改其内容时,呈现的HTML内容不再适合当前大小的小部件中。小部件开始显示水平和/或垂直滚动条,我可以使用它们来滚动HTML内容。

在这种情况下,我希望有一些逻辑来判断在内容更改后,新内容是否不适合小部件,并自动增加小部件大小,使所有内容都适合其中。

这些场景如何处理? 我正在使用PyQt4。

编辑:在阅读了评论和第一个答案(提到在小部件中输入内容)之后,我再次检查了问题。我非常惊讶地发现一个可怕的错字。我的意思是QTextBrowser,而不是QTextEdit,对于这个错误让您产生了误导,我很抱歉。也就是说:我有一个呈现我正在更改的HTML代码的小部件,我希望小部件能够增长足够大以显示所有内容,而不需要滚动条。

至于为什么使用QLineEdit而不是QLabel-我选择QLineEdit,因为我注意到无法使用鼠标从QLabel中选择文本进行复制。但是,使用QLineEdit则可以实现此功能。


只是想让你知道,我没有忽视你的问题...我已经思考了一整天,但我想不出一个简单的方法来做你所要求的事情。这不是你正在使用的项目的设计目的。它们是输入小部件,旨在允许输入比屏幕上舒适的数据更多的数据。如果你真的想要调整大小到当前项目,请尝试在布局中扩展QLabels。 - Caleb Huitt - cjhuitt
5个回答

8

我在这里使用C++进行回答,因为这是我最熟悉的语言,并且您的问题与PyQt无关。

通常情况下,当sizeHint()可能已更改时,只需调用QWidget::updateGeometry(),就像当内容可能已更改时需要调用QWidget::update()一样。

然而,您的问题在于当文本添加到QLineEditQTextEdit中时,sizeHint()不会更改。原因是:人们不希望在输入时自动调整对话框大小 :)

话虽如此,如果您确实想要这些小部件具有随输入而增长的行为,则需要继承它们并重新实现sizeHint()minimumSizeHint()以返回较大的尺寸,并且可能需要重写setText()append()等函数以调用updateGeometry(),以便注意到sizehint的变化。

sizehint计算不会完全简单,并且对于QLineEdit比对于QTextEdit要容易得多(后者是秘密的QAbstractScrollArea),但是您可以查看sizeHint()minimumSizeHint()的实现以获取灵感(还有一个QComboBox的实现,它具有执行您想要的操作的模式:QComboBox::AdjustToContents)。

编辑:使用最近的Qt,可以通过使用QLabel来解决您的两个用例(没有滚动条的QTextBrowser和仅用于选择其中文本的QLineEdit)。在Qt 4.2中,QLabel已获得链接单击通知和所谓的“文本交互标志”(其中之一是TextSelectableByMouse)。我能看出的唯一区别是,QLabel不会自动加载新内容,没有历史记录,并且没有微小的焦点提示(即从链接到链接的制表符)。


QLabel对我而言无法工作的原因是自动换行。当显示链接时,它拒绝将单词分开,这是不可接受的。 - chacham15
我遇到了同样的问题,需要QLabel真正支持WrapAtWordBoundaryOrAnywhere。 - Neil Wightman

2

我通过使用以下的C++类实现了类似的效果:

textedit.h

#ifndef TEXTEDIT_H
#define TEXTEDIT_H

#include <QTextEdit>

class TextEdit : public QTextEdit
{
  Q_DISABLE_COPY( TextEdit )

public:
  TextEdit( QWidget* parent = NULL );
  TextEdit( const QString& text, QWidget* parent = NULL );
  virtual ~TextEdit();

  void fitToDocument( Qt::Orientations orientations );
  virtual QSize sizeHint() const;

private:
  int fittedHeight_;
  Qt::Orientations fittedOrientations_;
  int fittedWidth_;
};

#include "textedit-inl.h"

#endif // TEXTEDIT_H

textedit-inl.h

#ifndef TEXTEDITINL_H
#define TEXTEDITINL_H

#include "textedit.h"

inline TextEdit::TextEdit( QWidget* parent ) :
    QTextEdit( parent ), fittedOrientations_( 0 )
{ }

inline TextEdit::TextEdit( const QString& text, QWidget* parent ) :
    QTextEdit( text, parent ), fittedOrientations_( 0 )
{ }

inline TextEdit::~TextEdit()
{ }

inline QSize TextEdit::sizeHint() const
{
  QSize sizeHint = QTextEdit::sizeHint();
  if( fittedOrientations_ & Qt::Horizontal )
    sizeHint.setWidth( fittedWidth_ );
  if( fittedOrientations_ & Qt::Vertical )
    sizeHint.setHeight( fittedHeight_ );
  return sizeHint;
}

#endif // TEXTEDITINL_H

textedit.cpp

#include "textedit.h"

void TextEdit::fitToDocument( Qt::Orientations orientations )
{
  QSize documentSize( document()->size().toSize() );
  QSizePolicy sizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred );
  if( orientations & Qt::Horizontal ) {
    fittedWidth_ = documentSize.width() + (width() - viewport()->width());
    sizePolicy.setHorizontalPolicy( QSizePolicy::Fixed );
  }
  if( orientations & Qt::Vertical ) {
    fittedHeight_ = documentSize.height() + (width() - viewport()->width());
    sizePolicy.setVerticalPolicy( QSizePolicy::Fixed );
  }
  fittedOrientations_ = orientations;
  setSizePolicy( sizePolicy );
  updateGeometry();
}

例如,调用TextEdit::fitToDocument( Qt::Horizontal )将设置小部件的宽度为恰好足够适应文档及其周围环境(例如,如果有垂直滚动条,则为垂直滚动条)的固定宽度。如果您的目标是每当内容更改时都发生这种情况,请将QTextEdit::textChanged()信号连接到调用TextEdit::fitToDocument()的槽中。
至于您在QLabel上遇到的问题,解决方法很简单:调用QLabel::setTextInteractionFlags( Qt::LinksAccessibleByMouse | Qt::TextSelectableByMouse )

2

对于 QTextBrowser,您应该能够使用以下方法获取文档的大小:

QTextBrowser::document()->size();

设置HTML后,然后在调整QTextBrowser大小。

1
也许你可以看一下Python QT自动小部件调整器。虽然它是用Python编写的,但它可能会给你一些关于如何实现你所需功能的想法。

链接已损坏。这正是为什么只有链接的“答案”不受欢迎的确切原因... - code_dredd

0

好的,实现sizeHint()方法。每当您的内容更改大小时,请调用updateGeometry()。当内容更改而不更改大小时,请使用update()。(updateGeometry()会自动调用update())。


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