【Python】PySimpleGUIでパスワードを表示・非表示するボタンを実装してみる

【Python】PySimpleGUIでパスワードを表示・非表示するボタンを実装してみる

今回は、ログインフォームで実装されていることが多い「パスワードを表示・非表示を切り替えるボタン」をPySimpleGUIで作成したいと思います。

パスワードを表示・非表示を切り替えるボタンは、「PySimpleGUIでログイン仕様のGUIを実装してみる」の記事で作成したログイン仕様GUIのコードに追加していきます。


それでは、まずはどのようなものを作成するのか、実際に使用されている具体例を見てみましょう。


以下の2枚の画像は、Googleアカウントを追加する時の「パスワード入力画面」です。
「パスワードを表示します」にチェックを入れると、パスワードの表示・非表示が入れ替わっています。

Googleアカウントのパスワードの表示・非表示の例


パスワード入力ボックスの下にある「Show password」の部分が「パスワードを表示・非表示を切り替えるボタン」です。

このような、押すたびにON/OFFと切り替わるボタンのことを「トグルボタン(toggle button)」と言います。

それではこちらのボタンを実装していきます。

パスワードの非表示方法

それでは、前回使用したコードの「パスワード入力欄」にて、入力した文字をすべて「*」となるように非表示にします。

前回のコードにおいてパスワードのレイアウト部分を、afterのコードのように変更してください。

# ログイン画面のレイアウト 3行目を以下のように変更
# -----------------------------------------------------
# before そのまま表示している
[sg.Text("パスワード:", size=(10, 1)), sg.Input("", size=(25, 1), key="-password-")],

# after 入力された部分を非表示化する
[sg.Text("パスワード:", size=(10, 1)), sg.Input("", size=(25, 1), password_char="*", key="-password-")],

sg.Input() の引数に password_char=”*” を追加しました。
password_charの文字をアスタリスク[*]に設定しているので、パスワードテキストを入力すると全てアスタリスクの伏字で表示されます。

変更したコードを実行すると、以下のようにパスワードが非表示になっています。


こちらのpassword_charの文字はスペース[ ]や、クエスチョンマーク[?]など、他の文字にも変更できるため、好みの文字でパスワードを非表示してみてください。

パスワードを表示・非表示するトグルボタンを作成

次に、パスワードの表示・非表示を行うトグルボタンを作成します。
先ほど見たGoogleの画面のように、チェックボックスで実装します。


ログインGUIのレイアウト部分を以下のように変更します。

# before
layout = [
    [sg.Text("ログイン画面")],
    ...
    [sg.Text("パスワード:", size=(10, 1)), sg.Input("", size=(25, 1), key="-password-")],
    [sg.Button("ログイン", size=(10, 1), enable_events=True, key="-login-")]
]

# after
layout = [
    [sg.Text("ログイン画面")],
    ...
    [sg.Text("パスワード:", size=(10, 1)), sg.Input("", size=(25, 1), password_char="*", key="-password-")],
    # 以下の1行を新たに追加
    [sg.Checkbox("パスワードを表示します", enable_events=True, key="-toggle_password-")], 
    [sg.Button("ログイン", size=(10, 1), enable_events=True, key="-login-")]
]


4行目に、チェックボックス要素であるsg.Checkbox(“パスワードを表示します”, enable_events=True, key=”-toggle_password-“)を追加しました。


enable_eventとは、「何かしらのアクションが起きた時に、イベントを発生させる」という意味です。デフォルトでは enable_event=False となっています。

チェックボタンが押されたかどうかで、パスワードの表示判定を行いたいので、今回は enable_event=True と設定します。


こちらを実行すると、チェックボックスが追加されたログイン画面が表示されます。


こちらのボタンを押しても、イベントを追加していないためパスワードの表示・非表示はできません。


それでは次にパスワードを表示・非表示する部分を実装します。

チェックボックスを押してパスワードを表示・非表示を行う


追記:
2021年3月3日に、PySimpleGUI 4.35.0にアップデートされました。
これによって、4.35.0以降でのパスワードの表示・非表示する方法と、それ以前のバージョンで異なる方法になりました。

ご自身のPySimpleGUIのバージョンに合った方法をご覧くださいますようお願いします。

【ver4.35.0以降】パスワードを表示・非表示の方法

ver4.35.0以降では、updateメソッドを使用する事でpassword_charを変更することができるようになりました。


while文のイベント部分に、以下のコードを追加するだけです。

elif event == "-login-":
    ...

elif event == "-toggle_password-":
    # チェックボタンがONだったらパスワードを表示する
    if values["-toggle_password-"]:
        window["-password-"].update(password_char="")

    # チェックボタンがOFFだったらパスワードを非表示にする
    else:
        window["-password-"].update(password_char="*")


Inputの要素に対して、updateメソッドを使用してpassword_charの文字を変更しています。


こちらを追加してプログラムを実行すると、きちんとパスワードの表示・非表示をすることができました。


これで思惑通り、ボタンを押してパスワードの表示・非表示を実装することができました。

【ver4.35.0以前】パスワードを表示・非表示の方法


以下で紹介する方法は、PySimpleGUIのバージョンが4.35.0以前のもので動作可能な方法です。ご了承ください。



パスワードを非表示にするのは簡単ですが、表示に変更するとなると、PySimpleGUIの中にある「Tkinterをいじる」必要があります。

手順としてはこのように行います。

  1. パスワードの入力欄の要素を指定する。
  2. 要素の元であるTKEntryを指定する。
  3. TKEntryのconfigメソッドでpassword_charの元であるshowを空白に更新する。

PySimpleGUIのリファレンス【PySimpleGUI Reference – Home】にはそのような記載がなく、実際にPySimpleGUIのコードを読まないと表示機能を実装することができませんでした。


少し難しい話をしましたが、コードにすると簡単です。
「パスワードを表示します」のボタンが押された時のイベントを、ログインイベントの処理の下に追加します。

elif event == "-login-":
    ...

elif event == "-toggle_password-":
    # チェックボタンがONだったらパスワードを表示する
    if values["-toggle_password-"]:
        window["-password-"].TKEntry.config(show="")
    # チェックボタンがOFFだったらパスワードを非表示にする
    else:
        window["-password-"].TKEntry.config(show="*")


以下の3つで、パスワードを表示・非表示するトグルボタンを作成できました。

最終プログラムコード

最終的な実行プログラムのコードはこのようになりました。
2021年2月14日時点で、以下の環境で動作済みです。

  • macOS Big Sur version 11.2.1
  • Python 3.7.2
  • PySimpleGUI 4.29.0

こちらのコードをPySimpleGUI 4.35.0 以降で動作させたい場合は、[# 4.35.0以降] とコメントしているコードを用いて実行してください。

# -*- coding: utf-8 -*-
import PySimpleGUI as sg # PySimpleGUIをインポート
from typing import Optional  # 型推定に用いる


def check_data(name: str, password: str) -> bool:
    """
    ログイン名とパスワードが、指定された値と合致しているか判定する関数

    Args:
        name (str): 入力された名前
        password (str): 入力されたパスワード

    Returns:
        bool: 判定結果
    """
    # 正しいと判定するデータ
    correct_data = ("TERU", "TERU_PASSWORD")

    if (name, password) == correct_data:
        return True
    return False


def display_main() -> Optional[bool]:
    """
    メイン画面を表示する関数

    Returns:
        Optional[bool]: ログアウト判定 True or None
                        Noneならログイン画面も終了させる。
    """
    # メイン画面のレイアウト
    main_layout = [
        [sg.Text("メイン画面")],
        [sg.Text("ようこそ メイン画面へ")],
        [sg.Button("ログアウト", size=(10, 1), enable_events=True, key="-logout-")]
    ]
    # windowを宣言
    main_window = sg.Window("メイン画面", main_layout, size=(400, 400))

    # 返り値
    ret = None

    while True:
        # イベントとGUI要素の値を取得する
        event, values = main_window.read()
        if event == sg.WIN_CLOSED or event == 'Exit':
            break

        # ログインボタンが押された時の処理
        elif event == "-logout-":
            # データが一致したら、メイン画面を表示する処理
            logout_ret = sg.PopupOKCancel("ログアウトしますか?", title="ログアウト確認", keep_on_top=True)

            # もしもOKなら 、Trueを返し、メイン画面を終了する。
            if logout_ret == "OK":
                ret = True
                break
            else:
                continue

    # メイン画面を終了する
    main_window.close()

    # 最後に返り値を渡す
    return ret

# テーマカラーを設定
sg.theme("SandyBeach")

# ログイン画面のレイアウト
layout = [
    [sg.Text("ログイン画面")],
    [sg.Text("名前:", size=(10, 1)), sg.Input("", size=(25, 1), key="-name-")],
    [sg.Text("パスワード:", size=(10, 1)), sg.Input("", size=(25, 1), password_char="*", key="-password-")],
    [sg.Checkbox("パスワードを表示します", enable_events=True, key="-toggle_password-")],
    [sg.Button("ログイン", size=(10, 1), enable_events=True, key="-login-")]
]
# windowを宣言
window = sg.Window("ログイン画面", layout, size=(400, 400))


while True:
    # イベントとGUI要素の値を取得する
    event, values = window.read()
    # ×ボタンが押された時はループを抜け出す。
    if event == sg.WIN_CLOSED or event == 'Exit':
        break

    # ログインボタンが押された場合の処理
    elif event == "-login-":
        # データが一致したら、メイン画面を表示する処理
        if check_data(name=values["-name-"], password=values["-password-"]):
            window.Hide() # ログイン画面を隠す
            # メイン画面を表示する
            main_return = display_main()
            # もしNoneが返ってきたらログイン画面も終了させる
            if main_return is None:
                break
            window.UnHide() # ログイン画面を再表示する

    # チェックボタンが押された時の処理
    elif event == "-toggle_password-":
        # チェックボタンがONだったらパスワードを表示する
        if values["-toggle_password-"]:
            window["-password-"].TKEntry.config(show="")  # ver 4.35.0以前            
            # window["-password-"].update(password_char="") # ver 4.35.0以降

        # チェックボタンがOFFだったらパスワードを非表示にする
        else:
            window["-password-"].TKEntry.config(show="*")  # ver 4.35.0以前            
            # window["-password-"].update(password_char="*") # ver 4.35.0以降

# windowを終了させる
window.close()


まとめ

いかがだったでしょうか。

パスワードの表示は簡単でしたが、非表示するのが少し難しかったです。
PySimpleGUIは、Tkinterのラッパー(Tkinterを簡単にしたもの)なので、Tkinterの構造を考えながら実装できる良い機会でした。

DBを用いたデータ認証や、入力欄の自動補完など、自由度が高いようにどんどん付け加えられたら良いなと思います。


こちらの記事が、誰かのお役に立てたら幸いです。

PySimpleGUIカテゴリの最新記事