三種方法為QLineEdit添加清除內容按鈕

来源:https://www.cnblogs.com/apocelipes/archive/2019/02/12/10367521.html
-Advertisement-
Play Games

很多時候我們會發現輸入的一長串內容不得不全部刪除重新輸入,這時比起一直按著退格鍵不放一個清除內容按鈕更受歡迎。 今天我將介紹三種為QLineEdit添加清除內容按鈕的方法,其中兩種方法有較強的功能針對性,另一種方法則是通用的,不僅可以用來實現清除輸入內容,還可以擴展出其他功能。 本文索引 方法1:s ...


很多時候我們會發現輸入的一長串內容不得不全部刪除重新輸入,這時比起一直按著退格鍵不放一個清除內容按鈕更受歡迎。

今天我將介紹三種為QLineEdit添加清除內容按鈕的方法,其中兩種方法有較強的功能針對性,另一種方法則是通用的,不僅可以用來實現清除輸入內容,還可以擴展出其他功能。

本文索引

方法1:setClearButtonEnabled顯示清除按鈕

這是Qt5.2之後提供的方法,當使用了setClearButtonEnabled(true);之後會在 QLineEdit的右側顯示一個圖標為QStyle::SP_DialogResetButto的QAction,點擊後會清除輸入內容:

// 方案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();
}

當無輸入內容時:

當有輸入內容時:

這樣三種方法都介紹完了,選用哪種需要自己決定。

當然最後兩種方案不僅僅能用來做清除內容按鈕,只要加入一點點想象力還有更高級的功能可以用它們來實現。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、什麼是SSL? SSL(Secure Sockets Layer 安全套接層),及其繼任者傳輸層安全(Transport Layer Security,TLS)是為網路通信提供安全及數據完整性的一種安全協議。TLS與SSL在傳輸層對網路連接進行加密。 SSL協議位於TCP/IP協議與各種應用層協 ...
  • 1. B站博人傳評論數據爬取簡介 今天想了半天不知道抓啥,去B站看跳舞的小姐姐,忽然看到了評論,那就抓取一下B站的評論數據,視頻動畫那麼多,也不知道抓取哪個,選了一個博人傳跟火影相關的,抓取看看。網址: 在這個網頁看到了18560條短評,數據量也不大,抓取看看,使用的還是scrapy。 2. B站博 ...
  • 題意 "題目鏈接" Sol 首先不難想到一種暴力dp,設$f[i][a][b][c]$表示還有$i$輪沒打,場上有$a$個1血,$b$個2血,$c$個三血 發現狀態數只有$s = 166$個,複雜度為$O(ns)$ 矩乘優化一下複雜度為$O(s^3 logn T)$,還是過不去。 因為每次詢問都是獨 ...
  • 今天遇到一個很奇怪的事情,日常刷題中,遇到一個很簡單的題: (不想看我多逼逼只想知道為什麼會出錯看最後) 題目: 題目描述 description 題目描述 description 現有有N個學生的數據記錄,每個記錄包括學號、姓名、三科成績。 編寫一個函數input,用來輸入一個學生的數據記錄。 編 ...
  • # 創建類的線程 import threading import time class MyThread(threading.Thread): def run(self): for i in range(3): time.sleep(1) msg = "我是[線程]" + self.name + '... ...
  • 1.1 數據結構介紹 數據結構:數據用什麼樣的方式組合在一起。 1.2 常見的數據結構 數據存儲的常用結構有:棧、隊列、數組、鏈表和紅黑樹。 棧: 棧:stack,又稱為堆棧,它是運算受限的線性表,其限制是僅允許在標的一端進行插入和刪除操作,不允許在其他任何位置進行添加、查找、刪除等操作。 簡單來說 ...
  • udp: 1.創建套接字 socket 2.綁定本地ip/port bind 3.收發數據 sendto/recvfrom 4.關閉套接字 close tcp客戶端: 1.創建套接字 socket 2.連接服務端 connect 3.收發數據 send/recv 4.關閉套接字 close tcp服 ...
  • “學電腦一定要有一個非常強大的心理狀態,電腦不是黑魔法,都是人想出來的,別人能夠想的出來,那麼,總有一天,我也能夠想的出來。” 指針類型的變數就是保存地址的變數。 int* p=&i;------P是一個指針,P裡面的內容為變數i的地址,即說P指向了i; int* p,q;------註意:*號... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...