很多时候我们会发现输入的一长串内容不得不全部删除重新输入,这时比起一直按着退格键不放一个清除内容按钮更受欢迎。

今天我将介绍三种为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,那么需要如下几部:

  1. 创建你需要的widget以及一个布局管理器
  2. 添加拉伸因子和widget至布局管理器,拉伸因子可以不添加,只要设置好布局管理器的排列方向即可
  3. 设置布局管理器里组件的排列方向并把布局管理器添加到QLineEdit
  4. 获取你添加的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::hideQAction::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添加清除内容按钮的更多相关文章

  1. C# winform三种方法判断文本框textBox内容是否为空

    使用系统API函数,需要使用命名空间:System.Runtime.InteropServices: 1.if (textBoxPath.Text ==  String.Empty ) 2.if (t ...

  2. 【转】css清除浮动float的三种方法总结,为什么清浮动?浮动会有那些影响?

    摘要: css清除浮动float的三种方法总结,为什么清浮动?浮动会有那些影响?     一.抛一块问题砖(display: block)先看现象: 分析HTML代码结构: <div class ...

  3. MYSQL添加远程用户或允许远程访问三种方法

    添加远程用户admin密码为password GRANT ALL PRIVILEGES ON *.* TO admin@localhost IDENTIFIED BY \'password\' WIT ...

  4. 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 ...

  5. linux清空文件内容的三种方法

    linux系统中清空文件内容的三种方法 1.使用vi/vim命令打开文件后,输入"%d"清空,后保存即可.但当文件内容较大时,处理较慢,命令如下:vim file_name:%d: ...

  6. Ubuntu Linux系统三种方法添加本地软件库

    闲着没事教教大家以Ubuntu Linux系统三种方法添加本地软件库,ubuntu Linux使用本地软件包作为安装源——转2007-04-26 19:47新手重新系统的概率很高,每次重装系统后都要经 ...

  7. mysql 中添加索引的三种方法

    原文:http://www.andyqian.com/2016/04/06/database/mysqleindex/ 在mysql中有多种索引,有普通索引,全文索引,唯一索引,多列索引,小伙伴们可以 ...

  8. Linux 添加开机启动项的三种方法

    linux 添加开机启动项的三种方法. (1)编辑文件 /etc/rc.local 输入命令:vim /etc/rc.local 将出现类似如下的文本片段: #!/bin/sh## This scri ...

  9. 详解linux下批量替换文件内容的三种方法(perl,sed,shell)

    在建设本网站的时候,发现新建了很多的网页,突然发现,每个文件都需要进行修改一样的内容,一个一个打开很是麻烦,所以,总结了一下如何快速修改一个目录下多个文件进行内容替换.第三种方法用的不多 方法一 使用 ...

随机推荐

  1. Angularjs interceptor

    angularJs 请求过滤 新建一个服务, $HttpProvider 中有一个 interceptore 数组,所谓的拦截器就是一个注册到该数组的工厂,该工厂在app.config() 中注入, ...

  2. Android 应用加固(乐固)操作说明

    此处引用腾讯云对加固的优点说明如下: 为什么应用需要加固? 若应用不做任何安全防护,极易被病毒植入.广告替换.支付渠道篡改.钓鱼.信息劫持等,严重侵害开发者的利益. 应用进行安全防护,防止应用分发后, ...

  3. String去重方法

    思路:利用集合的contains方法将某个字符串中的集合中没有的单个字符添加到集合中,然后再将集合中每个元素做拼接 @Test public void aa5(){ String aa="a ...

  4. pyqt5将图片插入面板

    from PyQt5.QtWidgets import * from PyQt5 import QtCore,QtWidgets from PyQt5.QtGui import * import sy ...

  5. 执行Python程序的两种方式

    目录 交互式(了解) 命令行式(了解) Python执行程序的三个阶段(掌握) 交互式(了解) 交互式环境下,敲完一条命令按下enter键马上能看到结果,调试程序方便.程序无法永久保存,关掉cmd窗口 ...

  6. Java:并发不易,先学会用

    我从事Java编程已经11年了,绝对是个老兵:但对于Java并发编程,我只能算是个新兵蛋子.我说这话估计要遭到某些高手的冷嘲热讽,但我并不感到害怕. 因为我知道,每年都会有很多很多的新人要加入Java ...

  7. RabbitMQ的介绍及使用进阶(Docker+.Net Core)

    目录: 一.什么是RabbitMQ 二.RabbitMQ运用场景 三.RabbitMQ优势及特点 四.Centos7中Docker安装RabbitMQ 五..Net Core 中使用RabbitMQ ...

  8. 『片段』Win32 模式窗体 消息路由

    需求背景 近来,有个需求: 和一个外部程序对接. 具体是,我这边 主程序用 Process 启动外部程序.外部程序启动后,我这边调用的窗体不允许再进行任何操作. 当外部程序关闭时,外部程序会向我这边的 ...

  9. Java进阶篇设计模式之五-----外观模式和装饰器模式

    前言 在上一篇中我们学习了结构型模式的适配器模式和桥接模式.本篇则来学习下结构型模式的外观模式和装饰器模式. 外观模式 简介 外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这 ...

  10. HTML入门知识汇总

    1. HTML认识 1.1 什么是HTML HTML是描述(制作)网页的语言,指的是超文本标记语言(Hyper Text Markup Language). 超文本:就是指页面内可以包含图片.链接.甚 ...