455void QLineEdit::setClearButtonEnabled(
bool enable)
459 if (enable == isClearButtonEnabled())
462 QAction *clearAction =
new QAction(d->clearButtonIcon(), QString(),
this);
463 clearAction->setEnabled(!isReadOnly());
464 clearAction->setObjectName(QLatin1StringView(clearButtonActionNameC));
466 int flags = QLineEditPrivate::SideWidgetClearButton | QLineEditPrivate::SideWidgetFadeInWithText;
467 auto widgetAction = d->addAction(clearAction,
nullptr, QLineEdit::TrailingPosition, flags);
468 widgetAction->setVisible(!text().isEmpty());
470 QAction *clearAction = findChild<QAction *>(QLatin1StringView(clearButtonActionNameC));
471 Q_ASSERT(clearAction);
472 d->removeAction(clearAction);
544void QLineEdit::setEchoMode(EchoMode mode)
547 if (mode == (EchoMode)d->control->echoMode())
549 Qt::InputMethodHints imHints = inputMethodHints();
550 imHints.setFlag(Qt::ImhHiddenText, mode == Password || mode == NoEcho);
551 imHints.setFlag(Qt::ImhNoAutoUppercase, mode != Normal);
552 imHints.setFlag(Qt::ImhNoPredictiveText, mode != Normal);
553 imHints.setFlag(Qt::ImhSensitiveData, mode != Normal);
554 setInputMethodHints(imHints);
555 d->control->setEchoMode(mode);
657QSize QLineEdit::sizeHint()
const
659 Q_D(
const QLineEdit);
661 QFontMetrics fm(font());
662 const int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize,
nullptr,
this);
663 const QMargins tm = d->effectiveTextMargins();
664 int h = qMax(fm.height(), qMax(14, iconSize - 2)) + 2 * QLineEditPrivate::verticalMargin
665 + tm.top() + tm.bottom()
666 + d->topmargin + d->bottommargin;
667 int w = fm.horizontalAdvance(u'x') * 17 + 2 * QLineEditPrivate::horizontalMargin
668 + tm.left() + tm.right()
669 + d->leftmargin + d->rightmargin;
670 QStyleOptionFrame opt;
671 initStyleOption(&opt);
672 return style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h),
this);
682QSize QLineEdit::minimumSizeHint()
const
684 Q_D(
const QLineEdit);
686 QFontMetrics fm = fontMetrics();
687 const QMargins tm = d->effectiveTextMargins();
688 int h = fm.height() + qMax(2 * QLineEditPrivate::verticalMargin, fm.leading())
689 + tm.top() + tm.bottom()
690 + d->topmargin + d->bottommargin;
691 int w = fm.maxWidth() + 2 * QLineEditPrivate::horizontalMargin
692 + tm.left() + tm.right()
693 + d->leftmargin + d->rightmargin;
694 QStyleOptionFrame opt;
695 initStyleOption(&opt);
696 return style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h),
this);
1340void QLineEdit::setReadOnly(
bool enable)
1343 if (d->control->isReadOnly() != enable) {
1344 d->control->setReadOnly(enable);
1345 d->setClearButtonEnabled(!enable);
1346 setAttribute(Qt::WA_MacShowFocusRect, !enable);
1347 setAttribute(Qt::WA_InputMethodEnabled, d->shouldEnableInputMethod());
1349 setCursor(enable ? Qt::ArrowCursor : Qt::IBeamCursor);
1351 QEvent event(QEvent::ReadOnlyChange);
1352 QCoreApplication::sendEvent(
this, &event);
1354#if QT_CONFIG(accessibility)
1355 QAccessible::State changedState;
1356 changedState.readOnly =
true;
1357 QAccessibleStateChangeEvent ev(
this, changedState);
1358 QAccessible::updateAccessibility(&ev);
1434bool QLineEdit::event(QEvent * e)
1437 if (e->type() == QEvent::ContextMenu) {
1439 if (d->control->composeMode())
1443 }
else if (e->type() == QEvent::WindowActivate) {
1444 QTimer::singleShot(0,
this, [
this]() {
1446 d->handleWindowActivate();
1448#ifndef QT_NO_SHORTCUT
1449 }
else if (e->type() == QEvent::ShortcutOverride) {
1450 QKeyEvent *ke =
static_cast<QKeyEvent*>(e);
1451 d->control->processShortcutOverrideEvent(ke);
1453 }
else if (e->type() == QEvent::Show) {
1456 d->control->setBlinkingCursorEnabled(
true);
1457 QStyleOptionFrame opt;
1458 initStyleOption(&opt);
1459 if ((!hasSelectedText() && d->control->preeditAreaText().isEmpty())
1460 || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt,
this))
1461 d->setCursorVisible(
true);
1463 }
else if (e->type() == QEvent::Hide) {
1464 d->control->setBlinkingCursorEnabled(
false);
1465#if QT_CONFIG(action)
1466 }
else if (e->type() == QEvent::ActionRemoved) {
1467 d->removeAction(
static_cast<QActionEvent *>(e)->action());
1469 }
else if (e->type() == QEvent::Resize) {
1470 d->positionSideWidgets();
1471 }
else if (e->type() == QEvent::StyleChange) {
1472 d->initMouseYThreshold();
1474 return QWidget::event(e);
1479void QLineEdit::mousePressEvent(QMouseEvent* e)
1483 d->mousePressPos = e->position().toPoint();
1485 if (d->sendMouseEventToInputContext(e))
1487 if (e->button() == Qt::RightButton) {
1491 if (d->tripleClickTimer.isActive() && (e->position().toPoint() - d->tripleClick).manhattanLength() <
1492 QApplication::startDragDistance()) {
1496 bool mark = e->modifiers() & Qt::ShiftModifier;
1498 mark = mark && (d->imHints & Qt::ImhNoPredictiveText);
1500 int cursor = d->xToPos(e->position().toPoint().x());
1501#if QT_CONFIG(draganddrop)
1502 if (!mark && d->dragEnabled && d->control->echoMode() == Normal &&
1503 e->button() == Qt::LeftButton && d->inSelection(e->position().toPoint().x())) {
1504 if (!d->dndTimer.isActive())
1505 d->dndTimer.start(QApplication::startDragTime(),
this);
1509 d->control->moveCursor(cursor, mark);
1515void QLineEdit::mouseMoveEvent(QMouseEvent * e)
1519 if (e->buttons() & Qt::LeftButton) {
1520#if QT_CONFIG(draganddrop)
1521 if (d->dndTimer.isActive()) {
1522 if ((d->mousePressPos - e->position().toPoint()).manhattanLength() > QApplication::startDragDistance())
1528 const bool select =
true;
1530 const bool select = (d->imHints & Qt::ImhNoPredictiveText);
1533 if (d->mouseYThreshold > 0 && e->position().toPoint().y() > d->mousePressPos.y() + d->mouseYThreshold) {
1534 if (layoutDirection() == Qt::RightToLeft)
1535 d->control->home(select);
1537 d->control->end(select);
1538 }
else if (d->mouseYThreshold > 0 && e->position().toPoint().y() + d->mouseYThreshold < d->mousePressPos.y()) {
1539 if (layoutDirection() == Qt::RightToLeft)
1540 d->control->end(select);
1542 d->control->home(select);
1543 }
else if (d->control->composeMode() && select) {
1544 int startPos = d->xToPos(d->mousePressPos.x());
1545 int currentPos = d->xToPos(e->position().toPoint().x());
1546 if (startPos != currentPos)
1547 d->control->setSelection(startPos, currentPos - startPos);
1552 d->control->moveCursor(d->xToPos(e->position().toPoint().x()), select);
1557 d->sendMouseEventToInputContext(e);
1562void QLineEdit::mouseReleaseEvent(QMouseEvent* e)
1565 if (d->sendMouseEventToInputContext(e))
1567#if QT_CONFIG(draganddrop)
1568 if (e->button() == Qt::LeftButton) {
1569 if (d->dndTimer.isActive()) {
1576#ifndef QT_NO_CLIPBOARD
1577 if (QGuiApplication::clipboard()->supportsSelection()) {
1578 if (e->button() == Qt::LeftButton) {
1579 d->control->copy(QClipboard::Selection);
1580 }
else if (!d->control->isReadOnly() && e->button() == Qt::MiddleButton) {
1582 d->control->paste(QClipboard::Selection);
1587 if (!isReadOnly() && rect().contains(e->position().toPoint()))
1588 d->handleSoftwareInputPanel(e->button(), d->clickCausedFocus);
1589 d->clickCausedFocus = 0;
1594void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e)
1598 if (e->button() == Qt::LeftButton) {
1599 int position = d->xToPos(e->position().toPoint().x());
1603 if (d->control->composeMode()) {
1604 int preeditPos = d->control->cursor();
1605 int posInPreedit = position - d->control->cursor();
1606 int preeditLength = d->control->preeditAreaText().size();
1607 bool positionOnPreedit =
false;
1609 if (posInPreedit >= 0 && posInPreedit <= preeditLength)
1610 positionOnPreedit =
true;
1612 int textLength = d->control->end();
1613 d->control->commitPreedit();
1614 int sizeChange = d->control->end() - textLength;
1616 if (positionOnPreedit) {
1617 if (sizeChange == 0)
1621 position = qBound(preeditPos, position, preeditPos + sizeChange);
1622 }
else if (position > preeditPos) {
1624 position += (sizeChange - preeditLength);
1630 d->control->selectWordAtPos(position);
1632 d->tripleClickTimer.start(QApplication::doubleClickInterval(),
this);
1633 d->tripleClick = e->position().toPoint();
1635 d->sendMouseEventToInputContext(e);
1766QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property, QVariant argument)
const
1768 Q_D(
const QLineEdit);
1771 return isEnabled() && !isReadOnly();
1772 case Qt::ImCursorRectangle:
1773 return d->cursorRect();
1774 case Qt::ImAnchorRectangle:
1775 return d->adjustedControlRect(d->control->anchorRect());
1778 case Qt::ImAbsolutePosition:
1779 case Qt::ImCursorPosition: {
1780 const QPointF pt = argument.toPointF();
1782 return QVariant(d->xToPos(pt.x(), QTextLine::CursorBetweenCharacters));
1783 return QVariant(d->control->cursor()); }
1784 case Qt::ImSurroundingText:
1785 return QVariant(d->control->surroundingText());
1786 case Qt::ImCurrentSelection:
1787 return QVariant(selectedText());
1788 case Qt::ImMaximumTextLength:
1789 return QVariant(maxLength());
1790 case Qt::ImAnchorPosition:
1791 if (d->control->selectionStart() == d->control->selectionEnd())
1792 return QVariant(d->control->cursor());
1793 else if (d->control->selectionStart() == d->control->cursor())
1794 return QVariant(d->control->selectionEnd());
1796 return QVariant(d->control->selectionStart());
1797 case Qt::ImReadOnly:
1798 return isReadOnly();
1799 case Qt::ImTextBeforeCursor: {
1800 const QPointF pt = argument.toPointF();
1802 return d->textBeforeCursor(d->xToPos(pt.x(), QTextLine::CursorBetweenCharacters));
1804 return d->textBeforeCursor(d->control->cursor()); }
1805 case Qt::ImTextAfterCursor: {
1806 const QPointF pt = argument.toPointF();
1808 return d->textAfterCursor(d->xToPos(pt.x(), QTextLine::CursorBetweenCharacters));
1810 return d->textAfterCursor(d->control->cursor()); }
1812 return QWidget::inputMethodQuery(property);
1819void QLineEdit::focusInEvent(QFocusEvent *e)
1822 if (e->reason() == Qt::TabFocusReason ||
1823 e->reason() == Qt::BacktabFocusReason ||
1824 e->reason() == Qt::ShortcutFocusReason) {
1825 if (!d->control->inputMask().isEmpty())
1826 d->control->moveCursor(d->control->nextMaskBlank(0));
1827 else if (!d->control->hasSelectedText())
1831 }
else if (e->reason() == Qt::MouseFocusReason) {
1832 d->clickCausedFocus = 1;
1835 d->control->setBlinkingCursorEnabled(
true);
1836 QStyleOptionFrame opt;
1837 initStyleOption(&opt);
1838 if ((!hasSelectedText() && d->control->preeditAreaText().isEmpty())
1839 || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt,
this))
1840 d->setCursorVisible(
true);
1841#if QT_CONFIG(completer)
1842 if (d->control->completer()) {
1843 d->control->completer()->setWidget(
this);
1844 d->connectCompleter();
1852void QLineEdit::focusOutEvent(QFocusEvent *e)
1855 if (d->control->passwordEchoEditing()) {
1858 d->updatePasswordEchoEditing(
false);
1861 Qt::FocusReason reason = e->reason();
1862 if (reason != Qt::ActiveWindowFocusReason &&
1863 reason != Qt::PopupFocusReason)
1866 d->setCursorVisible(
false);
1867 d->control->setBlinkingCursorEnabled(
false);
1868 if (reason != Qt::PopupFocusReason
1869 || !(QApplication::activePopupWidget() && QApplication::activePopupWidget()->parentWidget() ==
this)) {
1870 if (d->edited && (hasAcceptableInput() || d->control->fixup())) {
1871 emit editingFinished();
1875#if QT_CONFIG(completer)
1876 if (d->control->completer())
1877 d->disconnectCompleter();
1879 QWidget::focusOutEvent(e);
1884void QLineEdit::paintEvent(QPaintEvent *)
1888 QPalette pal = palette();
1890 QStyleOptionFrame panel;
1891 initStyleOption(&panel);
1892 style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p,
this);
1893 QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &panel,
this);
1894 r = r.marginsRemoved(d->effectiveTextMargins());
1897 QFontMetrics fm = fontMetrics();
1899 if (d->shouldShowPlaceholderText())
1900 fmHeight = fm.boundingRect(d->placeholderText).height();
1902 fmHeight = fm.boundingRect(d->control->text() + d->control->preeditAreaText()).height();
1903 fmHeight = qMax(fmHeight, fm.height());
1905 Qt::Alignment va = QStyle::visualAlignment(d->control->layoutDirection(), QFlag(d->alignment));
1906 switch (va & Qt::AlignVertical_Mask) {
1907 case Qt::AlignBottom:
1908 d->vscroll = r.y() + r.height() - fmHeight - QLineEditPrivate::verticalMargin;
1911 d->vscroll = r.y() + QLineEditPrivate::verticalMargin;
1915 d->vscroll = r.y() + (r.height() - fmHeight + 1) / 2;
1918 QRect lineRect(r.x() + QLineEditPrivate::horizontalMargin, d->vscroll,
1919 r.width() - 2 * QLineEditPrivate::horizontalMargin, fmHeight);
1921 if (d->shouldShowPlaceholderText()) {
1922 if (!d->placeholderText.isEmpty()) {
1923 const Qt::LayoutDirection layoutDir = d->placeholderText.isRightToLeft() ? Qt::RightToLeft : Qt::LeftToRight;
1924 const Qt::Alignment alignPhText = QStyle::visualAlignment(layoutDir, QFlag(d->alignment));
1925 const QColor col = pal.placeholderText().color();
1926 QPen oldpen = p.pen();
1928 Qt::LayoutDirection oldLayoutDir = p.layoutDirection();
1929 p.setLayoutDirection(layoutDir);
1931 const QString elidedText = fm.elidedText(d->placeholderText, Qt::ElideRight, lineRect.width());
1932 p.drawText(lineRect, alignPhText, elidedText);
1934 p.setLayoutDirection(oldLayoutDir);
1938 int cix = qRound(d->control->cursorToX());
1945 int widthUsed = qRound(d->control->naturalTextWidth()) + 1;
1946 if (widthUsed <= lineRect.width()) {
1948 switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
1949 case Qt::AlignRight:
1950 d->hscroll = widthUsed - lineRect.width() + 1;
1952 case Qt::AlignHCenter:
1953 d->hscroll = (widthUsed - lineRect.width()) / 2;
1960 }
else if (cix - d->hscroll >= lineRect.width()) {
1962 d->hscroll = cix - lineRect.width() + 1;
1963 }
else if (cix - d->hscroll < 0 && d->hscroll < widthUsed) {
1966 }
else if (widthUsed - d->hscroll < lineRect.width()) {
1969 d->hscroll = widthUsed - lineRect.width() + 1;
1972 d->hscroll = qMax(0, d->hscroll);
1977 QPoint topLeft = lineRect.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
1980#if QT_CONFIG(style_stylesheet)
1981 if (QStyleSheetStyle* cssStyle = qt_styleSheet(style())) {
1982 cssStyle->styleSheetPalette(
this, &panel, &pal);
1985 p.setPen(pal.text().color());
1987 int flags = QWidgetLineControl::DrawText;
1989 if (d->control->hasSelectedText() || (d->cursorVisible && !d->control->inputMask().isEmpty() && !d->control->isReadOnly())){
1990 flags |= QWidgetLineControl::DrawSelections;
1992 if (d->control->palette() != pal
1993 || d->control->palette().currentColorGroup() != pal.currentColorGroup())
1994 d->control->setPalette(pal);
2002 if (d->cursorVisible && !d->control->isReadOnly() && d->control->inputMask().isEmpty())
2003 flags |= QWidgetLineControl::DrawCursor;
2005 d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth, &panel,
this));
2006 d->control->draw(&p, topLeft, r, flags);
2110QMenu *QLineEdit::createStandardContextMenu()
2113 QMenu *popup =
new QMenu(
this);
2114 popup->setObjectName(
"qt_edit_menu"_L1);
2115 QAction *action =
nullptr;
2117 if (!isReadOnly()) {
2118 action = popup->addAction(QLineEdit::tr(
"&Undo") +
ACCEL_KEY(QKeySequence::Undo));
2119 action->setEnabled(d->control->isUndoAvailable());
2120 action->setObjectName(QStringLiteral(
"edit-undo"));
2121 setActionIcon(action, QStringLiteral(
"edit-undo"));
2122 connect(action, &QAction::triggered,
this, &QLineEdit::undo);
2124 action = popup->addAction(QLineEdit::tr(
"&Redo") +
ACCEL_KEY(QKeySequence::Redo));
2125 action->setEnabled(d->control->isRedoAvailable());
2126 action->setObjectName(QStringLiteral(
"edit-redo"));
2127 setActionIcon(action, QStringLiteral(
"edit-redo"));
2128 connect(action, &QAction::triggered,
this, &QLineEdit::redo);
2130 popup->addSeparator();
2133#ifndef QT_NO_CLIPBOARD
2134 if (!isReadOnly()) {
2135 action = popup->addAction(QLineEdit::tr(
"Cu&t") +
ACCEL_KEY(QKeySequence::Cut));
2136 action->setEnabled(!d->control->isReadOnly() && d->control->hasSelectedText()
2137 && d->control->echoMode() == QLineEdit::Normal);
2138 action->setObjectName(QStringLiteral(
"edit-cut"));
2139 setActionIcon(action, QStringLiteral(
"edit-cut"));
2140 connect(action, &QAction::triggered,
this, &QLineEdit::cut);
2143 action = popup->addAction(QLineEdit::tr(
"&Copy") +
ACCEL_KEY(QKeySequence::Copy));
2144 action->setEnabled(d->control->hasSelectedText()
2145 && d->control->echoMode() == QLineEdit::Normal);
2146 action->setObjectName(QStringLiteral(
"edit-copy"));
2147 setActionIcon(action, QStringLiteral(
"edit-copy"));
2148 connect(action, &QAction::triggered,
this, &QLineEdit::copy);
2150 if (!isReadOnly()) {
2151 action = popup->addAction(QLineEdit::tr(
"&Paste") +
ACCEL_KEY(QKeySequence::Paste));
2152 action->setEnabled(!d->control->isReadOnly() && !QGuiApplication::clipboard()->text().isEmpty());
2153 action->setObjectName(QStringLiteral(
"edit-paste"));
2154 setActionIcon(action, QStringLiteral(
"edit-paste"));
2155 connect(action, &QAction::triggered,
this, &QLineEdit::paste);
2159 if (!isReadOnly()) {
2160 action = popup->addAction(QLineEdit::tr(
"Delete"));
2161 action->setEnabled(!d->control->isReadOnly() && !d->control->text().isEmpty() && d->control->hasSelectedText());
2162 action->setObjectName(QStringLiteral(
"edit-delete"));
2163 setActionIcon(action, QStringLiteral(
"edit-delete"));
2164 connect(action, &QAction::triggered,
2165 d->control, &QWidgetLineControl::_q_deleteSelected);
2168 if (!popup->isEmpty())
2169 popup->addSeparator();
2171 action = popup->addAction(QLineEdit::tr(
"Select All") +
ACCEL_KEY(QKeySequence::SelectAll));
2172 action->setEnabled(!d->control->text().isEmpty() && !d->control->allSelected());
2173 action->setObjectName(QStringLiteral(
"select-all"));
2174 setActionIcon(action, QStringLiteral(
"edit-select-all"));
2175 d->selectAllAction = action;
2176 connect(action, &QAction::triggered,
this, &QLineEdit::selectAll);
2178 if (!d->control->isReadOnly() && QGuiApplication::styleHints()->useRtlExtensions()) {
2179 popup->addSeparator();
2180 QUnicodeControlCharacterMenu *ctrlCharacterMenu =
new QUnicodeControlCharacterMenu(
this, popup);
2181 popup->addMenu(ctrlCharacterMenu);
2188void QLineEdit::changeEvent(QEvent *ev)
2193 case QEvent::ActivationChange:
2194 if (!palette().isEqual(QPalette::Active, QPalette::Inactive))
2197 case QEvent::FontChange:
2198 d->control->setFont(font());
2200 case QEvent::StyleChange:
2202 QStyleOptionFrame opt;
2203 initStyleOption(&opt);
2204 d->control->setPasswordCharacter(
char16_t(style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter, &opt,
this)));
2205 d->control->setPasswordMaskDelay(style()->styleHint(QStyle::SH_LineEdit_PasswordMaskDelay, &opt,
this));
2209 case QEvent::LayoutDirectionChange:
2210#if QT_CONFIG(toolbutton)
2211 for (
const auto &e : d->trailingSideWidgets) {
2212 if (e.flags & QLineEditPrivate::SideWidgetClearButton)
2213 static_cast<QLineEditIconButton *>(e.widget)->setIcon(d->clearButtonIcon());
2216 d->positionSideWidgets();
2221 QWidget::changeEvent(ev);