不少时候咱们会发现输入的一长串内容不得不所有删除从新输入,这时比起一直按着退格键不放一个清除内容按钮更受欢迎。html
今天我将介绍三种为QLineEdit添加清除内容按钮的方法,其中两种方法有较强的功能针对性,另外一种方法则是通用的,不只能够用来实现清除输入内容,还能够扩展出其余功能。app
本文索引
这是Qt5.2以后提供的方法,当使用了setClearButtonEnabled(true);
以后会在 QLineEdit的右侧显示一个图标为QStyle::SP_DialogResetButto
的QAction,点击后会清除输入内容:ide
// 方案1 auto edit1 = new QLineEdit; edit1->setClearButtonEnabled(true);
效果:函数
看到右边那个图标,若是是Qt自带的话会是一个相似扫把的图形,若是使用了系统主题那么会有些许差别,点击它,输入内容就会所有清除。布局
如前所述,setClearButtonEnabled
其实只是让实现存在的QAction显示出来而已,因此咱们也能够本身实现这一过程。字体
要实现这一功能,须要Qt5.2以后提供的addAction
方法。它负责把一个QAction添加到edit的指定位置。this
不过要注意的是,这个QAction只能显示出图标,文字内容的显示不出的。3d
// 方案2 auto clearAction = new QAction; clearAction->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogResetButton)); auto edit2 = new QLineEdit; // QLineEdit::TrailingPosition表示将action放置在右边 edit2->addAction(clearAction, QLineEdit::TrailingPosition); QObject::connect(clearAction, &QAction::triggered, edit2, [edit2]{ edit2->setText(""); });
由于咱们知道lineedit默认使用的清除按钮的图标,也知道如何清除输入,因此能够本身实现这一过程。code
这是效果,与方法1时几乎没什么区别:orm
不过方法二的威力不止于此,基于咱们可使用本身的QAction,那么就能够定制一些操做,好比使用咱们本身的图标:
clearAction->setIcon(QIcon(":/clear.png"));
这种方法相比前一种略显复杂,然而却提供了更好的扩展性。
接下来要介绍的最后一种方法更加的灵活,你不只能够显示自定义图标,还能够显示自定义文字,固然做为代价它比第二种方法要复杂很多。
方法3:自定义QLineEdit为其添加按钮
想要在QLineEdit上添加一个widget一点也不复杂,首先咱们要弄清如下几个原理:
因此若是咱们想为QLineEdit或是其派生类添加一个widget好比QPushButton,那么须要以下几部:
提及来简单作起来难,咱们边看代码边讲解。
咱们先看类的定义,ButtonEdit
是一个带有按钮的QLineEdit:
#include <QWidget> #include <QLineEdit> #include <QPushButton> #include <QString> #include <QIcon> class ButtonEdit: public QLineEdit { Q_OBJECT public: explicit ButtonEdit(const QString &btnText, QWidget *parent = nullptr); explicit ButtonEdit(const QIcon &icon, QWidget *parent = nullptr); ~ButtonEdit() override = default; private: // 设置文本按钮或图标按钮的大小和外观 void setTextButton(); void setIconButton(); // 将按钮添加到edit void addButton(); QPushButton *button; Q_SIGNALS: void buttonClicked(bool); }; // 按钮和输入内容的边距 constexpr int buttonMargin = 3;
咱们的类能够从一个string或者icon构建,当edit的按钮被点击那么咱们就发出buttonClicked
信号。
也许你会以为对于按钮的设置分红两类没什么必要。事实否则,图形应用的开发有不少麻烦事,而其中比较头疼的要数如何让控件保持一个恰到好处的尺寸,而对于图标的处理和文本是不同的,因此有分开的必要。固然,若是你不介意文字或者图标只显示一半或者突出到编辑框的话也能够跳过这一步。
下面咱们来看下类成员的实现,构造函数没什么亮点,无非构造button,而后交由其余成员去处理:
ButtonEdit::ButtonEdit(const QString &btnText, QWidget *parent) : QLineEdit(parent) { button = new QPushButton(btnText); setTextButton(); addButton(); } ButtonEdit::ButtonEdit(const QIcon &icon, QWidget *parent) : QLineEdit(parent) { button = new QPushButton; button->setIcon(icon); setIconButton(); addButton(); }
接着是addButton
,在这里咱们先把button添加进layout,随后又设置了输入区域的大小避免输入内容被遮住:
void ButtonEdit::addButton() { connect(button, &QPushButton::clicked, this, &ButtonEdit::buttonClicked); // 按钮已是edit的一部分了,不该该再能被单独聚焦,不然可能致使误触 button->setFocusPolicy(Qt::NoFocus); // 设置鼠标,不然点击按钮时仍然会显示输入内容时的鼠标图标 button->setCursor(Qt::ArrowCursor); auto btnLayout = new QHBoxLayout; btnLayout->addStretch(); btnLayout->addWidget(button); // 设置组件右对齐,按钮会显示在edit的右侧 btnLayout->setAlignment(Qt::AlignRight); btnLayout->setContentsMargins(0, 0, 0, 0); setLayout(btnLayout); // 设置输入区域的范围,从edit的最左到按钮的最左(包含了按钮设置的buttonMargin) setTextMargins(0, 0, button->width(), 0); }
下面就是如何设置button的大小和样式了,大小与咱们设置的图标/文本的大小同样大,而后两边加上buttonMargin
。
对于图标按钮咱们还要设置按钮背景平时不可见,毕竟图标周围有个buttonMargin
宽度的框不太好看:
// 帮助函数,设置按钮的width,大小策略为fixed,不可放大或缩小 static void setButtonSize(QPushButton *button, int width) { auto policy = button->sizePolicy(); policy.setHorizontalPolicy(QSizePolicy::Fixed); button->setSizePolicy(policy); // 固定宽度,加上边距 button->setFixedWidth(width + buttonMargin*2); } void ButtonEdit::setTextButton() { if (!button) { return; } // 得到当前字体下文本内容的像素宽度 auto width = QWidget::fontMetrics().width(button->text()); setButtonSize(button, width); } void ButtonEdit::setIconButton() { if (!button) { return; } // 获取图标的width简单得多 auto width = button->iconSize().width(); setButtonSize(button, width); // 设置背景和边框在非点击时不可见 button->setFlat(true); }
如今工做完成了,无论咱们添加什么样的图标仍是多长的文本,按钮均可以保证有一个合适的大小,输入内容也不会被按钮遮住。
如今咱们看下使用:
// 方案3 // 使用文本按钮 auto edit3_1 = new ButtonEdit("clear"); QObject::connect(edit3_1, &ButtonEdit::buttonClicked, edit3_1, [edit3_1]{ edit3_1->setText(""); }); // 使用图标按钮 auto edit3_2 = new ButtonEdit(QApplication::style()->standardIcon(QStyle::SP_DialogResetButton)); QObject::connect(edit3_2, &ButtonEdit::buttonClicked, edit3_2, [edit3_2]{ edit3_2->setText(""); });
效果以下:
这种方案是最复杂的,但也是最灵活的,咱们能够定制button的外观,经过buttonClicked
信号咱们能够定制按钮按下后的行为。因此我在上一节才说这是扩展性最好的方法。
不过方案二和三都有一个显著的缺点,即便输入框中没有内容按钮或QAction也会一直显示,有些时候这不是咱们须要的行为。解决办法也很简单,合理利用QLineEdit的信号加上QWidget::hide
和QAction::setVisible
就能实现按钮的隐藏,这一功能的实现就当作练习吧。
如今咱们将三种方法合并显示在一块儿,以便你们看到各个方案带来的显示效果:
#include <QLineEdit> #include <QApplication> #include <QWidget> #include <QAction> #include <QObject> #include <QIcon> #include <QFormLayout> #include <QStyle> #include "ButtonEdit" int main(int argc, char *argv[]) { QApplication app(argc, argv); // 方案1 auto edit1 = new QLineEdit; edit1->setClearButtonEnabled(true); // 方案2 auto clearAction = new QAction; clearAction->setIcon(QIcon(":/clear.png")); auto edit2 = new QLineEdit; edit2->addAction(clearAction, QLineEdit::TrailingPosition); QObject::connect(clearAction, &QAction::triggered, edit2, [edit2]{ edit2->setText(""); }); // 方案3 // 使用文本按钮 auto edit3_1 = new ButtonEdit("clear"); QObject::connect(edit3_1, &ButtonEdit::buttonClicked, edit3_1, [edit3_1]{ edit3_1->setText(""); }); // 使用图标按钮 auto edit3_2 = new ButtonEdit(QApplication::style()->standardIcon(QStyle::SP_DialogResetButton)); QObject::connect(edit3_2, &ButtonEdit::buttonClicked, edit3_2, [edit3_2]{ edit3_2->setText(""); }); auto win = new QWidget; auto layout = new QFormLayout; layout->addRow("方案1:", edit1); layout->addRow("方案2:", edit2); layout->addRow("方案3_1:", edit3_1); layout->addRow("方案3_2:", edit3_2); win->setLayout(layout); win->show(); return app.exec(); }
当无输入内容时:
当有输入内容时:
这样三种方法都介绍完了,选用哪一种须要本身决定。
固然最后两种方案不只仅能用来作清除内容按钮,只要加入一点点想象力还有更高级的功能能够用它们来实现。