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()
).