Я должен признать, что (до прочтения вопроса ОП) я не знал о QLineEdit::addAction()
. Таким образом, я написал небольшой образец 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();
}
и вот как это выглядит (скомпилировано в cygwin64 ):
После этого я немного покопался в woboq.org , чтобы узнать, как это реализовано.
Я начал в 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);
Это интересно: прямоугольник для содержания извлекается и затем исправляется внутренними смещениями.
QFontMetrics fm = fontMetrics();
...
QRect lineRect(r.x() + d->horizontalMargin, d->vscroll, r.width() - 2*d->horizontalMargin, fm.height());
Насчет d->horizontalMargin
, я не совсем уверен, но пока игнорировал его и следовал вместо 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()); }));
}
Итак, я пришел к выводу, что QLineEditPrivate::effectiveLeftTextMargin()
учитывает пространство для значков действий, когда определяется эффективный размер текстового прямоугольника.
Жаль, что все эти функции private
и поэтому недоступны извне. Подумав некоторое время, как получить к ним доступ извне и изучив документацию. если я что-то не наблюдал, у меня возникла идея использовать QAction
s для этого:
#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();
}
Вывод на консоль:
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)
Чтобы сравнить значения, еще один снимок с измененными значками (рамка, нарисованная в SVG для отображения размера значков), которая была увеличена (коэффициент 5):
Слева QLineEditIconButton
сообщаемое положение (4, 2), но левая рамка значка находится в 8 пикселях от левой границы QLineEdit
. Безусловно, вокруг QLineEditIconButton
есть рамка, которую также необходимо учитывать (и я не исследовал, как ее найти). Ширина кадра может быть предметом стиля движка и, таким образом, варьироваться между платформами. Чтобы сделать такую попытку надежной и переносимой, соответствующие значения должны быть получены из виджетов или из стиля. Это становится утомительным занятием с большим или меньшим шансом на успех.
Однажды я попал в похожую ситуацию, пытаясь ответить SO: Как автоматически увеличивать / уменьшать размер текста в метке в Qt .
Относительно QLineEdit::cursorRect()
:
Я считаю, что использование QLineEdit::cursorRect()
(также) в лучшем случае хрупко.
Я изменил свой пример выше, чтобы проверить это:
#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();
}
Вывод на консоль:
Qt Version: 5.9.4
qEdit.geometry(): QRect(0,0 200x23)
qEdit.cursorRect(): QRect(253,0 9x16)
Забавно, что x-позиция курсора не только достаточно высока & ndash; это даже выше, чем ширина qEdit
. Как идет? Исходный текст "012345678901234567890123456789"
, который я вставил в qEdit
, приводит к тому, что курсор оказывается ближе к праву, в результате чего происходит горизонтальная прокрутка. Положение курсора, похоже, связано с шириной виртуального текста (включая обрезанный диапазон слева).