PyQt: как обрабатывать автоматическое изменение размеров виджетов при изменении их содержимого

У меня возникают некоторые проблемы с размером виджетов qt4 при изменении их содержимого.

Я проиллюстрирую свои проблемы двумя простыми сценариями:

Сценарий 1:

У меня есть виджет QLineEdit. Иногда, когда я изменяю его содержимое с помощью QLineEdit.setText(), однострочная строка больше не помещается в виджет с его текущим размером. Я должен выбрать виджет и использовать клавиши со стрелками для прокрутки строки в обоих направлениях, чтобы увидеть все это.

Сценарий 2:

У меня есть виджет QTextEdit. Иногда, когда я изменяю его содержимое с помощью QTextEdit.setHtml(), отображаемое содержимое HTML больше не помещается в виджет с его текущим размером. Виджет начинает отображать горизонтальные и / или вертикальные полосы прокрутки, и я могу использовать их для прокрутки содержимого HTML.

В таких сценариях я хотел бы иметь какую-то логику, которая решает, будет ли после изменения содержимого новое содержимое больше не помещаться в виджет, и автоматически увеличивает размер виджета, чтобы все подходило.

Как обрабатываются эти сценарии? Я использую PyQt4.

Редактировать: после прочтения как комментария, так и первого ответа (в котором упоминается ввод содержимого в виджет) я еще раз рассмотрел вопрос. Я был неприятно удивлен, обнаружив ужасную опечатку. Я имел в виду QTextBrowser, когда писал QTextEdit, извиняюсь за то, что ввел вас в заблуждение. То есть: у меня есть виджет, который отображает HTML-код, который я изменяю, и я бы хотел, чтобы этот виджет рос настолько, чтобы отображать все без полос прокрутки.

Что касается QLineEdit вместо QLabel - я выбрал QLineEdit, поскольку заметил, что не могу выделить текст из QLabel с помощью мыши для его копирования. С QLineEdit это возможно.

5 ответов

Я отвечаю на C++ здесь, так как это то, с чем я больше всего знаком, и ваша проблема не относится к PyQt.

Обычно вам просто нужно позвонить QWidget::updateGeometry() когда sizeHint() возможно, изменился, так же, как вам нужно позвонить QWidget::update() когда содержимое могло измениться.

Ваша проблема, однако, в том, что sizeHint() не изменяется при добавлении текста в QLineEdit а также QTextEdit, По причине: люди не ожидают, что их диалоги будут расти как они:)

Тем не менее, если вам действительно нужно поведение типа "расти как вы" в этих виджетах, вам нужно наследовать их и переопределять sizeHint() а также minimumSizeHint() вернуть больший размер, и потенциально setText(), append() и т.д. позвонить updateGeometry() так что изменение sizehint замечено.

Расчет sizehint будет не совсем тривиальным, и его будет намного проще QLineEdit чем для QTextEdit (который тайно QAbstractScrollArea), но вы можете посмотреть на sizeHint() а также minimumSizeHint() реализации для вдохновения (также один для QComboBox, который имеет режим, чтобы делать именно то, что вы хотите: QComboBox::AdjustToContents,

РЕДАКТИРОВАТЬ: Ваши два варианта использования (QTextBrowser без полос прокрутки и QLineEdit вместо QLabel только для выделения текста там) могут быть решены с помощью QLabel и достаточно недавнего Qt. QLabel получил как уведомление о щелчке по ссылке, так и так называемые "текстовые флаги взаимодействия" (одним из которых является TextSelectableByMouse) в Qt 4.2. Единственное отличие, которое я смог разглядеть, заключается в том, что загрузка нового контента не происходит автоматически, в ней нет истории, и в QLabel нет подсказок по микрофокусам (т. Е. Переход от ссылки к ссылке).

Может быть, взгляните на Python QT Automatic Widget Resizer. Он написан на Python, но может дать вам некоторые идеи о том, как делать то, что вам нужно.

Для случая QTextBrowser вы должны быть в состоянии получить размер документа, используя

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

после установки HTML, а затем изменив его размер в QTextBrowser.

Я достигаю подобного эффекта, используя следующий класс 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 ),

Хорошо реализовать sizeHint() метод. И каждый раз, когда ваш контент меняется размер вызова updateGeometry()Когда содержание меняется без изменения размера использования update(), (updateGeometry() автоматически звонить update()).

Другие вопросы по тегам