Better width with Open Sources…

While the Decoding table is being redone for KDE 4.2 there was a bug report pending about the old version of it, in that larger values do not fit into the witdh of the value fields.

The culprit code:

QFontMetrics metric( font() );
const int int16Width = metric.width( "88888888" );
KLineEdit* mInt16Display = new KLineEdit( this );
mInt16Display->setFixedWidth( int16Width );

Bogus, as the width of the lineedit widget also includes the width of the frame plus some left and right margins, not just the width of the rendered string.

While this report was filed as a wish, I considered it still as a bug. And because it looked simple (and to keep the Zarro-Boogs state for Okteta 🙂 ) I navigated my editor to the 4.1 branch… to find out, it wasn’t that simple to fix.

There is no such thing as a void QTreeView::resizeColumnToContents() for QLineEdit, or similar. So I tried QSize QStyle::sizeFromContents(), but the results were not as expected, the widget was always to small.

Frustration. The night was becoming longer. This *peep* little thing should be solveable somehow.

“Use the Source, Luke!” I remembered. Oh yes, of course, the Power of White boxes. A quick look at the implementation of QSize QLineEdit::sizehint() const showed that the content of a QLineEdit also includes the margins, for whatever reason. And, oh shame for the responsible, there are some hardcoded additional margins not exposed by functions like void void QWidget::getContentsMargins(), looks like work in progress. But then it was documented, by the source code itself, so that’s what makes it different from some Blackbox toolkit.

Now the fixing code:

KLineEdit* mInt16Display = new KLineEdit( this );
const int verticalMargin = 1; // hardcoded in gui/widgets/qlineedit.cpp
const int horizontalMargin = 2; // hardcoded in gui/widgets/qlineedit.cpp
const int mysticBonusMargin = 1; // no idea where it come from, but with one pixel more it is equally margined
int leftMargin, rightMargin, topMargin, bottomMargin;
mInt16Display->getContentsMargins( &leftMargin, &topMargin, &rightMargin, &bottomMargin );

QFontMetrics metric( font() );
const int int16Width = metric.width( "88888888" );
const int lineSpacing = fontMetrics.lineSpacing();

const int minLineSpacing = 14;
const int contentHeight =
qMax(lineSpacing,minLineSpacing)
+ topMargin + 2 * verticalMargin + bottomMargin;
const int contentOtherWidth = leftMargin + 2 * horizontalMargin + rightMargin + mysticBonusMargin;
const QSize int16ContentSize( int16Width + contentOtherWidth, contentHeight );

QStyleOptionFrameV2 option;
option.initFrom( mInt16Display );
option.lineWidth = mInt16Display->hasFrame() ?
style()->pixelMetric( QStyle::PM_DefaultFrameWidth, &option, mInt16Display ) : 0;
// rest of QStyleOptionFrameV2 does not seem to have an influence
const int int16DisplayWidth =
style()->sizeFromContents( QStyle::CT_LineEdit, &option, int16ContentSize, mInt16Display ).width();

mInt16Display->setFixedWidth( int16DisplayWidth );

Not wonderful, should be rather a service function in QLineEdit, but well, it works.

And so the rest of the night was saved, and some users will be more happy after the release of KDE 4.1.3. Thank you, Open Sources Knights. 🙂

PS: Still I can not believe it had to be solved this complicated. What did I miss?

Update: Problems now reported via the Qt Task Tracker, to have things fixed and not just workarounded, see #231859 and #231683 🙂

Advertisements

6 thoughts on “Better width with Open Sources…

  1. if it makes you feel any better, i ran into the same issue leading up to the KDE 4.0 release. the use of hardcoded values in QLineEdit is immensely dissapointing.

  2. Maybe such method should be added to KLineEdit? At least that way KDE compliant applications won’t have to go through all this trouble… (or using KLineEdit and KDE widgets is no longer the recommended way?)

  3. @Aaron: In KLineEdit, I guess? Yes, makes me feel better. Or, wait, you shared your pain with me, I with you, so in the end the pain level stays, oh dear 😉

    @Pinotree: Yes, for whatever reason protected.

    @Anon: Good idea, yes. Even better, these days the Trolls seem to be very interested to add useful things right to Qt itself. I will see to do my first apporaches to the Qt report system for this…

  4. Protected is trivial to work around:

    class QLineEditInitStyleOptionHack : public QLineEdit {
    public: static void initStyleOption(const QLineEdit *e, QStyleOptionFrame *option) { static_cast(e)->QLineEdit::initStyleOption(option); }
    };

    Then use QLineEditInitStyleOptionHack::initStyleOption(yourLineEdit, option);

    Of course the static_cast in that hack probably makes this non-conforming C++. To get rid of that offending cast, you have to actually allocate classes of the QLineEditInitStyleOptionHack type rather than QLineEdit (and in that case even the unchanged code would be valid, but you can avoid having to use that static function and the ugly static_cast and just make the member function public in the subclass).

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s