Reputation: 575
I am working on a PyQt5 project, but would be happy to read C++/Qt answer as well, because C++ solutions may work on Python too.
I have a MainWindow with a horizontal layout, and a QLabel in it.
My QLabel's size Policy is "Expanding", therefore all my window is filled by the QLabel.
However, the text displayed by my QLabel does not change its size. I would like the text to grow when the window grows, and be as big as possible, in the limit of the QLabel size.
I have heard of QWidget::adjustSize()
but could not figure out how to use it.
The option scaledContents
for my QLabel on QtDesigner does not do anything, so I guess it is only useful for when using pixmap.
For the moment, my solution is to reimplement the resizeEvent()
method of my window and change the font size of my label with setFont()
. But I think that there must be an easier solution. Moreover, my resizeEvent()
method is not very good because I make a linear relation between myWindowWidth* myWindowHeight
and myTextFontSize
, therefore when only myWindowWidth
increase, myTextFontSize
increases and forces myWindowHeight
to increase, which is bad.
Upvotes: 3
Views: 4066
Reputation: 21
I had a similar problem, only I needed the title of a QButton to dynamically change font size whenever the text got too big to fit my Button. The working parts of the implementation only take into account the button width, so making it work with a label (or any other widget if you can access its size and text properties) will only require 2 line changes.
`calculate_font_size(font: QFont, button,minimum_font_size = 9):
font_size = QtGui.QFontMetrics(font)
target_width = button.maximumWidth() - 2 # add some padding
k = font_size.width(button.text())
if k < target_width: # if this size of text already fits, don't change it
return font.pointSize()
else:
ratio = k / target_width # calculate how much bigger the text is compared to the button. E.g. if ratio = 1.2, it's 20% bigger
size_correct = font.pointSize() / ratio
if size_correct < minimum_font_size:
size_correct = minimum_font_size # make it readble and word wrap it instead of making it extra small
return (size_correct)`
change the button
argument to a Label, and change the button.maximumWidth()
and button.text()
properties on lines 2 and 3, to the width of the label and the text you want to fit in the label.
This function by design, only scales the fonts DOWN. This is just what I needed in my project. A hack for this if you also want to scale up the text, is to always run the function with an unreasonably high starting font size (e.g. 3000), and it always give you the correct size to fit.
Upvotes: 2
Reputation: 98425
This is a quick sketch that might point to a solution. Instead of deriving from a label, an event filter can be installed on any label to make its text fill the available space. The filter uses the existing scaledContents
property, and extends its applicability to text content.
The label's font size is adjusted using Newton's algorithm to fill the available space. Some adjustments would be needed to make it work with labels that enable word wrap; the font size should then never overshoot what fits.
// https://github.com/KubaO/stackoverflown/tree/master/questions/label-text-size-36575192
#include <QtWidgets>
class LabelStretcher : public QObject {
Q_OBJECT
public:
LabelStretcher(QObject * parent = 0) : QObject(parent) {
apply(qobject_cast<QLabel*>(parent));
}
void apply(QLabel * label) { if (label) label->installEventFilter(this); }
protected:
bool eventFilter(QObject * obj, QEvent * ev) Q_DECL_OVERRIDE {
if (ev->type() != QEvent::Resize) return false;
auto label = qobject_cast<QLabel*>(obj);
if (!label || label->text().isEmpty() || !label->hasScaledContents()) return false;
qDebug() << "pre: " << label->minimumSizeHint() << label->sizeHint() << label->size();
static auto dSize = [](const QSize & inner, const QSize & outer) -> int {
auto dy = inner.height() - outer.height();
auto dx = inner.width() - outer.width();
return std::max(dx, dy);
};
static auto f = [](qreal fontSize, QLabel * label) -> qreal {
auto font = label->font();
font.setPointSizeF(fontSize);
label->setFont(font);
auto d = dSize(label->sizeHint(), label->size());
qDebug() << "f:" << fontSize << "d" << d;
return d;
};
static auto df = [](qreal fontSize, QLabel * label) -> qreal {
if (fontSize < 1.0) fontSize = 1.0;
return f(fontSize + 0.5, label) - f(fontSize - 0.5, label);
};
// Newton's method
auto font = label->font();
auto fontSize = font.pointSizeF();
int i;
for (i = 0; i < 5; ++i) {
auto d = df(fontSize, label);
qDebug() << "d:" << d;
if (d < 0.1) break;
fontSize -= f(fontSize, label)/d;
}
font.setPointSizeF(fontSize);
label->setFont(font);
qDebug() << "post:" << i << label->minimumSizeHint() << label->sizeHint() << label->size();
return false;
}
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QLabel label{"Hello There!"};
label.setScaledContents(true);
label.show();
LabelStretcher stretch(&label);
return app.exec();
}
#include "main.moc"
Upvotes: 4