三种方法为QLineEdit添加清除内容按钮
很多时候我们会发现输入的一长串内容不得不全部删除重新输入,这时比起一直按着退格键不放一个清除内容按钮更受欢迎。
今天我将介绍三种为QLineEdit添加清除内容按钮的方法,其中两种方法有较强的功能针对性,另一种方法则是通用的,不仅可以用来实现清除输入内容,还可以扩展出其他功能。
本文索引
方法1:setClearButtonEnabled显示清除按钮
这是Qt5.2之后提供的方法,当使用了`setClearButtonEnabled(true);`之后会在 QLineEdit的右侧显示一个图标为`QStyle::SP_DialogResetButto`的QAction,点击后会清除输入内容:
```c++
// 方案1
auto edit1 = new QLineEdit;
edit1->setClearButtonEnabled(true);
```
效果:

看到右边那个图标,如果是Qt自带的话会是一个类似扫把的图形,如果使用了系统主题那么会有些许差异,点击它,输入内容就会全部清除。
方法2:使用QAction实现清除按钮
如前所述,`setClearButtonEnabled`其实只是让实现存在的QAction显示出来而已,所以我们也可以自己实现这一过程。
要实现这一功能,需要Qt5.2之后提供的addAction方法。它负责把一个QAction添加到edit的指定位置。
不过要注意的是,这个QAction只能显示出图标,文字内容的显示不出的。
// 方案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默认使用的清除按钮的图标,也知道如何清除输入,所以可以自己实现这一过程。
这是效果,与方法1时几乎没什么区别:

不过方法二的威力不止于此,基于我们可以使用自己的QAction,那么就可以定制一些操作,比如使用我们自己的图标:
clearAction->setIcon(QIcon(":/clear.png"));

这种方法相比前一种略显复杂,然而却提供了更好的扩展性。
接下来要介绍的最后一种方法更加的灵活,你不仅可以显示自定义图标,还可以显示自定义文字,当然作为代价它比第二种方法要复杂不少。
方法3:自定义QLineEdit为其添加按钮
这种方法对Qt的版本没有什么要求,所以它也足够通用。
想要在QLineEdit上添加一个widget一点也不复杂,首先我们要弄清以下几个原理:
- qt的widget和layout是可以堆叠的,之前在实现半透明遮罩中有提过
- 你可以为QLineEdit设置layout,如你所料layout会堆叠在edit的输入框上
- edit的layout会只使用控件的最小尺寸,这样不会导致将整个输入框遮盖掉
- edit的可输入区域是可以设置的,你可以合理的设置输入区的大小避免文字进入layout之下被遮盖
所以如果我们想为QLineEdit或是其派生类添加一个widget比如QPushButton,那么需要如下几部:
- 创建你需要的widget以及一个布局管理器
- 添加拉伸因子和widget至布局管理器,拉伸因子可以不添加,只要设置好布局管理器的排列方向即可
- 设置布局管理器里组件的排列方向并把布局管理器添加到QLineEdit
- 获取你添加的widget的宽度,然后在加上合适的边框距离,将QLineEdit的输入区域限制在合理的大小
说起来简单做起来难,我们边看代码边讲解。
我们先看类的定义,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();
}
当无输入内容时:

当有输入内容时:

这样三种方法都介绍完了,选用哪种需要自己决定。
当然最后两种方案不仅仅能用来做清除内容按钮,只要加入一点点想象力还有更高级的功能可以用它们来实现。
三种方法为QLineEdit添加清除内容按钮的更多相关文章
- C# winform三种方法判断文本框textBox内容是否为空
使用系统API函数,需要使用命名空间:System.Runtime.InteropServices: 1.if (textBoxPath.Text == String.Empty ) 2.if (t ...
- 【转】css清除浮动float的三种方法总结,为什么清浮动?浮动会有那些影响?
摘要: css清除浮动float的三种方法总结,为什么清浮动?浮动会有那些影响? 一.抛一块问题砖(display: block)先看现象: 分析HTML代码结构: <div class ...
- MYSQL添加远程用户或允许远程访问三种方法
添加远程用户admin密码为password GRANT ALL PRIVILEGES ON *.* TO admin@localhost IDENTIFIED BY \'password\' WIT ...
- HOSt ip is not allowed to connect to this MySql server, MYSQL添加远程用户或允许远程访问三种方法
HOSt ip is not allowed to connect to this MySql server 报错:1130-host ... is not allowed to connect to ...
- linux清空文件内容的三种方法
linux系统中清空文件内容的三种方法 1.使用vi/vim命令打开文件后,输入"%d"清空,后保存即可.但当文件内容较大时,处理较慢,命令如下:vim file_name:%d: ...
- Ubuntu Linux系统三种方法添加本地软件库
闲着没事教教大家以Ubuntu Linux系统三种方法添加本地软件库,ubuntu Linux使用本地软件包作为安装源——转2007-04-26 19:47新手重新系统的概率很高,每次重装系统后都要经 ...
- mysql 中添加索引的三种方法
原文:http://www.andyqian.com/2016/04/06/database/mysqleindex/ 在mysql中有多种索引,有普通索引,全文索引,唯一索引,多列索引,小伙伴们可以 ...
- Linux 添加开机启动项的三种方法
linux 添加开机启动项的三种方法. (1)编辑文件 /etc/rc.local 输入命令:vim /etc/rc.local 将出现类似如下的文本片段: #!/bin/sh## This scri ...
- 详解linux下批量替换文件内容的三种方法(perl,sed,shell)
在建设本网站的时候,发现新建了很多的网页,突然发现,每个文件都需要进行修改一样的内容,一个一个打开很是麻烦,所以,总结了一下如何快速修改一个目录下多个文件进行内容替换.第三种方法用的不多 方法一 使用 ...
随机推荐
- eclipse使用javaFX写一个HelloWorkld
------------------------------------------------ 操作系统:Ubuntu18.04 EclipseVersion: Oxygen.3a Release ...
- jackson json转对象 json转集合 对大小写支持
@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, isGetterVisibi ...
- ActiveMQ详解
Apache ActiveMQ介绍 使用MQ的场景 ActiveMQ的安装 收发消息的简单实现 ActiveMQ内部实现 queue和topic 消息持久化 kahadb原理 最关键的6个配置 Apa ...
- Eclipse 出现项目没有错但是项目名称却有红色感叹号或者红叉的解决办法
错误的起因是本人因为一不小心点了下面圈出来的某一个按钮,具体记不清楚了(好像是"remove from build path"),然后整个项目变得很奇怪了,所有的包都变成了一个普通 ...
- Bagging之随机森林
随机森林(Random Forest)是一种Bagging(Bootstrap Aggregating)集成算法,在样本随机(样本扰动)的基础上,进一步运用特征随机(属性扰动)的机制,得到比一般的Ba ...
- JS实现页面复制文字时自动加版权
经亲自实践,尝试了各种方法,目前可行的方法主要有如下两种: 可以在任何运行使用js代码的网站中使用,比如本人在自己的博客园博客中实现了一下,读者您可亲自在本人博客上测试. 方法1: <scrip ...
- JPA中自定义的插入、更新、删除方法为什么要添加@Modifying注解和@Transactional注解?
前几天,有个同事在使用JPA的自定义SQL方法时,程序一直报异常,捣鼓了半天也没能解决,咨询我的时候,我看了一眼他的程序,差不多是这个样子的: @Repository public interface ...
- .NETCore 下支持分表分库、读写分离的通用 Repository
首先声明这篇文章不是标题党,我说的这个类库是 FreeSql.Repository,它作为扩展库现实了通用仓储层功能,接口规范参考 abp vnext 定义,实现了基础的仓储层(CURD). 安装 d ...
- FreeSql 扩展包实现 Dapper 的使用习惯
简介 FreeSql.Connection.Extensions 这是 FreeSql 衍生出来的扩展包,实现(Mysql/postgresql/sqlserver/Oracle/SQLite)数据库 ...
- Python 中的设计模式详解之:策略模式
虽然设计模式与语言无关,但这并不意味着每一个模式都能在每一门语言中使用.<设计模式:可复用面向对象软件的基础>一书中有 23 个模式,其中有 16 个在动态语言中“不见了,或者简化了”. ...