Monday, May 21, 2018

QLineEdit width cannot be set in terms of characters

Hopefully this will be a short post, but I can't believe how much time I've wasted on this, including digging into the QLineEdit source.

I used to use a GUI toolkit called Motif. It was written nearly 30 years ago. Of course it had a simple, single-line text editor widget. Like all widgets, you could set it's width and height, and it could be resized by managers (layouts).
There was a property you could set on the text widget to tell it how many characters it should display. This took into account the current font and always did a reasonable job of setting the width of the widget.

Fast forward nearly 30 years. I'm learning this shiny new Qt toolkit and want to set the number of characters to display in my QLineEdit. Nope, all you get is width in pixels. To fix this, you actually have to subclass QLineEdit and re-implement the sizeHint function:

QSize QLineEdit::sizeHint() const
{
    Q_D(const QLineEdit);
    ensurePolished();
    QFontMetrics fm(font());
    int h = qMax(fm.height(), 14) + 2*d->verticalMargin
            + d->topTextMargin + d->bottomTextMargin
            + d->topmargin + d->bottommargin;
    int w = fm.horizontalAdvance(QLatin1Char('x')) * 17 + 2*d->horizontalMargin
            + d->effectiveLeftTextMargin() + d->effectiveRightTextMargin()
            + d->leftmargin + d->rightmargin; // "some"
    QStyleOptionFrame opt;
    initStyleOption(&opt);
    return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
                                      expandedTo(QApplication::globalStrut()), this));
}
Notice the 17? That's how many characters you get. Silly programmer didn't you know 17 is always the right length?

Now that I know how stupid the code is, I can fix it, but a subclass is never a first class widget in the QtDesigner, so it will always be annoying, forcing me to add an extra function call for ever QLineEdit rather than just setting a property in QtDesigner.

No comments:

Post a Comment