Details
-
Bug
-
Resolution: Cannot Reproduce
-
P2: Important
-
4.4.3
-
None
Description
QAbstractTextDocumentLayout::documentSize() will return an an erratic range of sizes even when document is not being changed. This can be demonstrated by running the following example:
By entering some text at about 10 letters or more in the bottom window it will start returning incorrect size values.
///////////////////////////////////////////////////////////////////////////////
// ElasticTextEdit decl //
///////////////////////////////////////////////////////////////////////////////
#include <QtGui/QTextEdit>
#include <QDebug>
/**
- This is a subclass of QTextEdit that changes its preferred height
- as a function of its width and the text it contains. It's otherwise
- the same as QTextEdit.
*/
class ElasticTextEdit : public QTextEdit {
Q_OBJECT
public:
ElasticTextEdit(QWidget* parent = 0);
ElasticTextEdit(const QString& text, QWidget* parent = 0);
~ElasticTextEdit();
// QWidget overrides
int heightForWidth(int width) const;
QSize sizeHint() const;
public slots:
// private
void heightForWidthMayHaveChanged();
} ;
///////////////////////////////////////////////////////////////////////////////
// ElasticTextEdit impl //
///////////////////////////////////////////////////////////////////////////////
#include <QtGui/QAbstractTextDocumentLayout>
#include <QtGui/QSizePolicy>
ElasticTextEdit::ElasticTextEdit(QWidget* parent)
: QTextEdit(parent) {
// Make hasHeightForWidth be enabled by default
QSizePolicy policy(sizePolicy());
policy.setHeightForWidth(true);
setSizePolicy(policy);
connect(this, SIGNAL(textChanged()),
this, SLOT(heightForWidthMayHaveChanged()));
}
ElasticTextEdit::ElasticTextEdit(const QString& text, QWidget* parent)
: QTextEdit(text, parent) {
}
ElasticTextEdit::~ElasticTextEdit() {
}
int
ElasticTextEdit::heightForWidth(int width) const {
QTextDocument* doc = document();
qreal savedWidth = doc->textWidth();
// Fudge factor. This is supposed to be the difference between the
// height of the widget and the height of the area where the text is
// actually drawn. I don't know how to get it exactly.
int fudge = 2;
// Do the calculation assuming no scrollbars
doc->setTextWidth(width);
int noScrollbarHeight =
doc->documentLayout()->documentSize().height() + fudge;
qDebug() << "h: " << doc->documentLayout()->documentSize().height();
qDebug() << "w: " << doc->documentLayout()->documentSize().width();
// (If noScrollbarHeight is greater than the maximum height we'll be
// allowed, then there will be scrollbars, and the actual required
// height will be even higher. But since in this case we've already
// hit the maximum height, it doesn't matter that we underestimate.)
// Get minimum height (even if string is empty): one line of text
int minimumHeight = QFontMetrics(doc->defaultFont()).lineSpacing() + fudge;
int ret = qMax(noScrollbarHeight, minimumHeight);
doc->setTextWidth(savedWidth);
return ret;
}
QSize
ElasticTextEdit::sizeHint() const {
QSize size = QTextEdit::sizeHint();
if (size.width() == 0)
size.setWidth(400); // arbitrary value
size.setHeight(heightForWidth(size.width()));
return size;
}
void
ElasticTextEdit::heightForWidthMayHaveChanged() {
updateGeometry();
}
///////////////////////////////////////////////////////////////////////////////
// test //
///////////////////////////////////////////////////////////////////////////////
#include <QtGui/QApplication>
#include <QtGui/QSizePolicy>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
class Demo : public QWidget {
public:
Demo(QWidget* parent = 0);
} ;
Demo::Demo(QWidget* parent)
: QWidget(parent) {
QVBoxLayout* verticalLayout = new QVBoxLayout(this);
QTextEdit* top = new QTextEdit(this);
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(top->sizePolicy().hasHeightForWidth());
top->setSizePolicy(sizePolicy);
top->setMinimumSize(QSize(0, 50));
verticalLayout->addWidget(top);
ElasticTextEdit* bottom = new ElasticTextEdit(this);
QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Preferred);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(bottom->sizePolicy().hasHeightForWidth());
bottom->setSizePolicy(sizePolicy1);
verticalLayout->addWidget(bottom);
}
#include "main.moc"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Demo demo;
demo.show();
return app.exec();
}