我有一个QLineEdit
,一个QAction
处于领先位置。我想知道文字的开始位置,但找不到方法:
QLineEdit *le = new QLineEdit(parent);
le->addAction(QIcon(":/myicon"), QLineEdit::LeadingPosition);
// Now I want to get the text start position
// but both return "QMargins(0, 0, 0, 0) QMargins(0, 0, 0, 0)"
qDebug() << le->textMargins() << le->contentsMargins();
我搜索了qt的github源码,以发现addAction()
方法是否在内容或文本空白处执行了某些操作,但没有成功。
答案 0 :(得分:2)
我必须承认(在阅读操作要求之前)我不知道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
来实现这一点:
#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),但是图标的左框距离QLineEdit
的左边界8个像素。在QLineEditIconButton
周围肯定有一个框架也必须考虑(而且我没有研究如何检索它)。框架的宽度可能是样式引擎的主题,因此在平台之间会有所不同。为了使这种尝试变得健壮和可移植,应从小部件或样式中检索相应的值。这变得越来越繁琐,或多或少都有成功的机会。
在尝试回答SO: How to automatically increase/decrease text size in label in Qt时,我遇到了类似情况。
我认为,使用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位置不仅很高,甚至比qEdit
的宽度还高。怎么会?我在"012345678901234567890123456789"
中输入的初始文本qEdit
使光标靠近右侧,从而发生水平滚动。光标位置似乎与虚拟文本的宽度有关(包括左侧的剪切范围)。