我有一个带有输入掩码的QLineEdit
,因此可以轻松输入(或粘贴)某种代码。因为即使没有文本(因为输入掩码中有占位符),您可以将光标放在QLineEdit
中的任何位置:
如果人们不小心且不专心,这会导致他们在文本框的中间打字,而他们应该在开头打字。我尝试了通过安装事件过滤器确保光标在焦点开始时的简单方法:
bool MyWindowPrivate::eventFilter(QObject * object, QEvent * event)
{
if (object == ui.tbFoo && event->type() == QEvent::FocusIn) {
ui.tbFoo->setCursorPosition(0);
}
return false;
}
这适用于keybaord焦点,即当按⇆或⇧ + ⇆时,但是当用鼠标点击时光标总是结束我点击的地方。我的猜测是QLineEdit
在获得焦点后点击后设置光标位置,从而撤消我的位置变化。
深入挖掘,点击¹,然后按顺序更改焦点,会引发以下事件:
FocusIn
MouseButtonPress
MouseButtonRelease
我无法在事件过滤器中完全捕捉到鼠标点击,因此有一种很好的方法可以设置光标位置,以便在控制聚焦时(无论是通过鼠标还是键盘)启动 ?
¹旁注:我讨厌Qt没有任何关于此类常见场景的信号/事件订单的文档。
答案 0 :(得分:7)
以下是在单独的类中考虑的实现。在为对象发布任何待处理事件后,它将光标的设置推迟到,从而回避了事件顺序的问题。
#include <QApplication>
#include <QLineEdit>
#include <QFormLayout>
#include <QMetaObject>
// Note: A helpful implementation of
// QDebug operator<<(QDebug str, const QEvent * ev)
// is given in http://stackoverflow.com/q/22535469/1329652
/// Returns a cursor to zero position on a QLineEdit on focus-in.
class ReturnOnFocus : public QObject {
Q_OBJECT
/// Catches FocusIn events on the target line edit, and appends a call
/// to resetCursor at the end of the event queue.
bool eventFilter(QObject * obj, QEvent * ev) {
QLineEdit * w = qobject_cast<QLineEdit*>(obj);
// w is nullptr if the object isn't a QLineEdit
if (w && ev->type() == QEvent::FocusIn) {
QMetaObject::invokeMethod(this, "resetCursor",
Qt::QueuedConnection, Q_ARG(QWidget*, w));
}
// A base QObject is free to be an event filter itself
return QObject::eventFilter(obj, ev);
}
// Q_INVOKABLE is invokable, but is not a slot
/// Resets the cursor position of a given widget.
/// The widget must be a line edit.
Q_INVOKABLE void resetCursor(QWidget * w) {
static_cast<QLineEdit*>(w)->setCursorPosition(0);
}
public:
ReturnOnFocus(QObject * parent = 0) : QObject(parent) {}
/// Installs the reset functionality on a given line edit
void installOn(QLineEdit * ed) { ed->installEventFilter(this); }
};
class Ui : public QWidget {
QFormLayout m_layout;
QLineEdit m_maskedLine, m_line;
ReturnOnFocus m_return;
public:
Ui() : m_layout(this) {
m_layout.addRow(&m_maskedLine);
m_layout.addRow(&m_line);
m_maskedLine.setInputMask("NNNN-NNNN-NNNN-NNNN");
m_return.installOn(&m_maskedLine);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Ui ui;
ui.show();
return a.exec();
}
#include "main.moc"
答案 1 :(得分:3)
您可以使用QTimer
中的focusInEvent
来调用将光标位置设置为0的插槽。
这很有效,因为单发计时器会在对象的事件队列末尾发布计时器事件。引发鼠标的焦点事件必然会将鼠标点击发布到事件队列中。因此,您可以确保在任何拖延鼠标按下事件后调用计时器的事件(以及产生的插槽调用)。
void LineEdit::focusInEvent(QFocusEvent *e)
{
QLineEdit::focusInEvent(e);
QTimer::singleShot(0, this, SLOT(resetCursorPos()));
}
void LineEdit::resetCursorPos()
{
setCursorPosition(0);
}