I must admit that (before reading OPs question) I was not aware about QLineEdit::addAction()
. Thus, I wrote a little sample testQLineEditAction.cc
:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// init GUI
QLineEdit qEdit;
qEdit.addAction(QIcon("./document-properties.svg"), QLineEdit::LeadingPosition);
qEdit.addAction(QIcon("./document-save.svg"), QLineEdit::TrailingPosition);
qEdit.show();
// runtime loop
return app.exec();
}
and this is how it looks (compiled in cygwin64):

Afterwards, I digged a bit through woboq.org to find out how it is implemented.
I started in QLineEdit::paintEvent()
:
void QLineEdit::paintEvent(QPaintEvent *)
{
...
QStyleOptionFrame panel;
initStyleOption(&panel);
...
QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this);
r.setX(r.x() + d->effectiveLeftTextMargin());
r.setY(r.y() + d->topTextMargin);
r.setRight(r.right() - d->effectiveRightTextMargin());
r.setBottom(r.bottom() - d->bottomTextMargin);
This is interesting: The rectangle for contents is retrieved and then corrected by inner offsets.
QFontMetrics fm = fontMetrics();
...
QRect lineRect(r.x() + d->horizontalMargin, d->vscroll, r.width() - 2*d->horizontalMargin, fm.height());
About the d->horizontalMargin
, I'm not quite sure but I ignored it for now and followed instead d->effectiveLeftTextMargin()
:
int QLineEditPrivate::effectiveLeftTextMargin() const
{
return effectiveTextMargin(leftTextMargin, leftSideWidgetList(), sideWidgetParameters());
}
...
static int effectiveTextMargin(int defaultMargin, const QLineEditPrivate::SideWidgetEntryList &widgets,
const QLineEditPrivate::SideWidgetParameters ¶meters)
{
if (widgets.empty())
return defaultMargin;
return defaultMargin + (parameters.margin + parameters.widgetWidth) *
int(std::count_if(widgets.begin(), widgets.end(),
[](const QLineEditPrivate::SideWidgetEntry &e) {
return e.widget->isVisibleTo(e.widget->parentWidget()); }));
}
So, I came to the conclusion that QLineEditPrivate::effectiveLeftTextMargin()
considers the space for action icons when effective size of text rectangle is determined.
It's a pity that all these functions are private
and thus not accessable from outside. After thinking a while how to get access to these from outside and looking into doc. whether I haven't overseen something, I got the idea to use the QAction
s directly for this:
#include <QtWidgets>
void inspect(const QString &cmd, QAction &qCmd)
{
qDebug() << (cmd + "->associatedWidgets().size():")
<< qCmd.associatedWidgets().size();
int i = 0;
for (QWidget *const pQWidget : qCmd.associatedWidgets()) {
qDebug() << '[' << i++ << "]:"
<< typeid(*pQWidget).name()
<< "geometry:" << pQWidget->geometry();
}
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// init GUI
QLineEdit qEdit;
qEdit.setText("012345678901234567890123456789");
QAction *const pQCmd1
= qEdit.addAction(QIcon("./document-properties.svg"), QLineEdit::LeadingPosition);
QAction *const pQCmd2
= qEdit.addAction(QIcon("./document-save.svg"), QLineEdit::TrailingPosition);
qEdit.show();
qDebug() << "qEdit.geometry():" << qEdit.geometry();
inspect("pQCmd1", *pQCmd1);
inspect("pQCmd2", *pQCmd2);
// runtime loop
return app.exec();
}
Console output:
Qt Version: 5.9.4
qEdit.geometry(): QRect(0,0 200x23)
"pQCmd1->associatedWidgets().size():" 2
[ 0 ]: 9QLineEdit geometry: QRect(0,0 200x23)
[ 1 ]: 19QLineEditIconButton geometry: QRect(4,2 22x18)
"pQCmd2->associatedWidgets().size():" 2
[ 0 ]: 9QLineEdit geometry: QRect(0,0 200x23)
[ 1 ]: 19QLineEditIconButton geometry: QRect(174,2 22x18)
To compare the values, another snapshot with modified icons (frame drawn in SVGs to show icon size) which has been magnified (factor 5):

Left QLineEditIconButton
reported position (4, 2) but the left frame of icon is 8 pixels away from left border of QLineEdit
. There is surely a frame around the QLineEditIconButton
which has to be considered as well (and I didn't investigate how to retrieve it). The width of frame might be subject of style engine and thus vary between platforms. To make such attempt robust and portable, the respective values should be retrieved from the widgets or from style. This starts to become a tedious fiddling with more or less chance for success.
I ended up once in a similar situation when trying to answer SO: How to automatically increase/decrease text size in label in Qt.
Concerning QLineEdit::cursorRect()
:
I believe that using QLineEdit::cursorRect()
is (as well) at best fragile.
I modified my above example to check this out:
#include <QtWidgets>
class LineEdit: public QLineEdit {
public:
QRect cursorRect() const { return QLineEdit::cursorRect(); }
};
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// init GUI
LineEdit qEdit;
qEdit.setText("012345678901234567890123456789");
qEdit.addAction(QIcon("./document-properties.svg"), QLineEdit::LeadingPosition);
qEdit.addAction(QIcon("./document-save.svg"), QLineEdit::TrailingPosition);
qEdit.show();
qDebug() << "qEdit.cursorRect():" << qEdit.cursorRect();
// runtime loop
return app.exec();
}
Console output:
Qt Version: 5.9.4
qEdit.geometry(): QRect(0,0 200x23)
qEdit.cursorRect(): QRect(253,0 9x16)
Funny, that the cursor x-position is not only quite high – it's even higher than the width of qEdit
. How comes? The initial text "012345678901234567890123456789"
I put into qEdit
causes the cursor to be close to the right whereby horizontal scrolling happens. The cursor position seems to be related to the virtual text width (including the clipped range on the left side).