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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1153714/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 21:35:58  来源:igfitidea点击:

PyQt: how to handle auto-resize of widgets when their content changes

c++pythonqtqt4pyqt4

提问by

I am having some issues with the size of qt4 widgets when their content changes.

当 qt4 小部件的内容发生变化时,它们的大小出现了一些问题。

I will illustrate my problems with two simple scenarios:

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

Scenario 1:

场景一:

I have a QLineEdit widget. Sometimes, when I'm changing its content using QLineEdit.setText(), the one-line string doesn't fit into the widget at its current size anymore. I must select the widget and use the arrow keys to scroll the string in both directions in order to see it all.

我有一个 QLineEdit 小部件。有时,当我使用 QLineEdit.setText() 更改其内容时,单行字符串不再适合当前大小的小部件。我必须选择小部件并使用箭头键在两个方向滚动字符串才能看到所有内容。

Scenario 2:

场景2:

I have a QTextEdit widget. Sometimes, when I'm changing its content using QTextEdit.setHtml(), the rendered HTML content doesn't fit into the widget at its current size anymore. The widget starts displaying horizontal and/or vertical scroll bars and I can use them to scroll the HTML content.

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

What I would want in such scenarios is to have some logic that decides if after a content change, the new content won't fit anymore into the widget and automatically increase the widget size so everything would fit.

在这种情况下,我想要的是有一些逻辑来决定在内容更改后新内容是否不再适合小部件并自动增加小部件大小以便一切都适合。

How are these scenarios handled? I'm using PyQt4.

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

Edit: after reading both the comment and the first answer (which mentions typing content into the widget), I went over the question one more time. I was unpleasantly surprised to find out a horrible typo. I meant QTextBrowser when I wrote QTextEdit, my apologies for misleading you. That is: I have a widget which renders HTML code that I'm changing and I would want the widget to grow enough to display everything without having scrollbars.

编辑:在阅读了评论和第一个答案(其中提到在小部件中输入内容)后,我又看了一遍这个问题。发现一个可怕的错字,我感到很不愉快。当我写 QTextEdit 时,我的意思是 QTextBrowser,我很抱歉误导你。那就是:我有一个小部件,它呈现我正在更改的 HTML 代码,我希望小部件能够增长到足以显示所有内容而没有滚动条。

As for QLineEdit instead of QLabel - I went for QLineEdit since I've noticed I can't select text from a QLabel with the mouse for copying it. With QLineEdit it is possible.

至于 QLineEdit 而不是 QLabel - 我选择了 QLineEdit,因为我注意到我无法用鼠标从 QLabel 中选择文本进行复制。使用 QLineEdit 是可能的。

回答by Marc Mutz - mmutz

I'm answering in C++ here, since that's what I'm most familiar with, and your problem isn't specific to PyQt.

我在这里用 C++ 回答,因为这是我最熟悉的,而且你的问题不是 PyQt 特有的。

Normally, you just need to call QWidget::updateGeometry()when the sizeHint()may have changed, just like you need to call QWidget::update()when the contents may have changed.

通常,您只需要QWidget::updateGeometry()sizeHint()可能更改时调用,就像QWidget::update()在内容可能更改时调用一样。

Your problem, however, is that the sizeHint()doesn't change when text is added to QLineEditand QTextEdit. For a reason: People don't expect their dialogs to grow-as-they-type :)

但是,您的问题是将sizeHint()文本添加到QLineEdit和时 不会改变QTextEdit。有一个原因:人们不希望他们的对话随着他们的类型而增长:)

That said, if you really want grow-as-you-type behaviour in those widgets you need to inherit from them and reimplement sizeHint()and minimumSizeHint()to return the larger size, and potentially setText(), append()etc. to call updateGeometry()so the sizehint change is noticed.

也就是说,如果你真的想长大,作为你型在那些你需要继承他们重新实现小工具的行为sizeHint(),并minimumSizeHint()返回较大的尺寸,和潜在的setText()append()等打电话updateGeometry()让sizehint变化注意到。

The sizehint calculation won't be entirely trivial, and will be way easier for QLineEditthan for QTextEdit(which is secretly a QAbstractScrollArea), but you can look at the sizeHint()and minimumSizeHint()implementations for inspiration (also the one for QComboBox, which has a mode to do exactly what you want: QComboBox::AdjustToContents.

sizehint 的计算并不是完全微不足道的,并且QLineEdit比 for QTextEdit(秘密地 a QAbstractScrollArea)要容易得多,但是您可以查看sizeHint()minimumSizeHint()实现以获取灵感(还有 for QComboBox,它有一种模式可以完全按照您的要求执行操作)想要:QComboBox::AdjustToContents

EDIT: Your two usecases (QTextBrowser w/o scrollbars and QLineEdit instead of QLabel just for selecting the text in there) can be solved by using a QLabel and a recent enough Qt. QLabel has gained both link-clicking notification and so-called "text-interaction flags" (one of which is TextSelectableByMouse) in Qt 4.2. The only difference that I was able to make out is that loading new content isn't automatic, there's no history, and there's no micro focus hinting (ie. tabbing from link to link) in QLabel.

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

回答by Kristian

For the QTextBrowser case you should be able to get the size of the document using

对于 QTextBrowser 情况,您应该能够使用

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

after setting the html, and then resizing it the QTextBrowser afterwards.

设置 html 后,然后调整 QTextBrowser 的大小。

回答by nisavid

i achieve a similar effect by using the following C++ class:

我通过使用以下 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

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();
}

for example, calling TextEdit::fitToDocument( Qt::Horizontal )will set the widget's width to a fixed width exactly large enough to fit the document and its surroundings (e.g. a vertical scrollbar, if there is one). if your goal is to have this happen whenever the contents change, connect the QTextEdit::textChanged()signal to a slot which calls TextEdit::fitToDocument().

例如,调用TextEdit::fitToDocument( Qt::Horizontal )会将小部件的宽度设置为一个固定宽度,该宽度恰好足够适合文档及其周围环境(例如,垂直滚动条,如果有的话)。如果您的目标是在内容更改时发生这种情况,请将QTextEdit::textChanged()信号连接到调用TextEdit::fitToDocument().

as for your issue with QLabel, the solution is simple: call QLabel::setTextInteractionFlags( Qt::LinksAccessibleByMouse | Qt::TextSelectableByMouse ).

至于你的问题QLabel,解决办法很简单:调用QLabel::setTextInteractionFlags( Qt::LinksAccessibleByMouse | Qt::TextSelectableByMouse )

回答by hollahhoo

Maybe take a look at Python QT Automatic Widget Resizer. It's written in python though but it may give you some ideas on how to go about doing what you need.

也许看看Python QT Automatic Widget Resizer。虽然它是用 python 编写的,但它可能会给你一些关于如何去做你需要的事情的想法。

回答by przemo_li

Ok implement sizeHint()method. And every time your content change size call updateGeometry()When content change without changing size use update(). (updateGeometry()automatically call update()).

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