時間が経つと押せる、ダイアログの確認ボタン

# 概要

なにかシステムからのダイアログが出てきた際に反射的にボタンを押してしまう自分がいました。
ほとんどの場合は問題ないのですが、少し待って何の確認なのか見ることは大切です。

ダイアログ側でも何かできないかと思い、ある程度の時間が経つまではボタンが押せないようにできないかと思い、Tkinterで実装してみました。

# 作ってみた画面

![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302006/0a7bf879-fa7e-0f35-6c10-6516063eae2f.gif)

※プログレスバーの色がおかしいですが、GIFで取得した際のものです

# 実装方法について

簡単に作りたかったのでTkinterで実装しました。

```python:main.py
import tkinter
from tkinter import *
from tkinter import simpledialog
from tkinter import ttk


class CustomDialog(simpledialog.Dialog):
    def __init__(self, master, title=None) -> None:
        super(CustomDialog, self).__init__(parent=master, title=title)

    def body(self, master) -> None:
        """
        Dialogオブジェクトへ配置するオブジェクトを定義する。

        Parameters
        ----------
        master:
            Dialogオブジェクトの親オブジェクト

        Returns
        -------
        None
        """
        label: Label = Label(master, text="""
        【重要なお知らせ】

        本システムをご利用いただく前に、以下の事項を必ずお読みください。

        1. セキュリティ対策について
           • 定期的なパスワードの変更をお願いいたします
           • 個人情報の取り扱いには十分ご注意ください
           • 不審な動作を確認した場合は直ちに管理者へご連絡ください

        2. システム利用時の注意事項
           • 5秒間は操作をお待ちください
           • データの入力は慎重に行ってください
           • 作業終了時は必ずログアウトをお願いいたします

        3. 免責事項
           • 本システムの利用により生じた損害について、当社は一切の責任を負いかねます
           • システムの仕様は予告なく変更される場合があります
           • 予期せぬ障害により、サービスを停止する場合があります

        ご理解とご協力のほど、よろしくお願い申し上げます。
        """)
        label.grid(column=0, row=0, padx=20, pady=20)

        button_frame = Frame(master)
        button_frame.grid(column=0, row=2, pady=10)

        self.ok_button = Button(button_frame, text='OK', command=self.ok)
        self.ok_button.pack(side=LEFT, padx=5)
        self.ok_button.configure(state='disabled')

        cancel_button = Button(button_frame, text='キャンセル', command=self.cancel)
        cancel_button.pack(side=LEFT, padx=5)

        self.create_progressbar(master)

        # 5秒後にOKボタンを有効化
        self.after(5000, self.enable_ok_button)

    def create_progressbar(self, master) -> None:
        progress_frame = Frame(master)
        progress_frame.grid(column=0, row=1, pady=10)

        self.progress_label = Label(
            progress_frame,
            text="内容をご確認ください"
        )
        self.progress_label.pack(pady=(0, 5))

        self.progress = ttk.Progressbar(
            progress_frame,
            length=300,
            mode='determinate',
            style='Custom.Horizontal.TProgressbar'
        )
        self.progress.pack()

        # プログレスバーのスタイル設定
        style = ttk.Style()
        style.configure(
            'Custom.Horizontal.TProgressbar',
            troughcolor='#E0E0E0',
            background='#4CAF50'
        )

        self.progress_animation(progressbar=self.progress, progresslabel=self.progress_label, total_time=5000, update_interval=50)
    
    def progress_animation(self, progressbar: ttk.Progressbar, progresslabel: Label, total_time: int, update_interval: int):
        current = progressbar['value']
        if current < 100:
            remaining = (100 - current) * total_time / 100 / 1000
            progresslabel.configure(
                text=f"内容をご確認ください（残り{remaining:.1f}秒）"
            )
            
            increment = (update_interval / total_time) * 100
            progressbar['value'] += increment
            
            self.after(update_interval, self.progress_animation, progressbar, progresslabel, total_time, update_interval)
        else:
            progresslabel.configure(text="確認が完了しましたらOKボタンを押してください")
            self.enable_ok_button()

    def enable_ok_button(self):
        self.ok_button.configure(state='normal')

    def buttonbox(self) -> None:
        pass


if __name__ == "__main__":
    root = tkinter.Tk()

    def display_dialog():
        CustomDialog(root)

    button = Button(root)
    button["text"] = "ダイアログ表示"
    button["command"] = display_dialog
    button.grid(column=0, row=0, padx=10, pady=10)

    root.mainloop()
```

# 所感

利用規約で最後までスクロールしないとチェックボタンが押せない仕組みなど、似たような仕掛けはあります。

システム操作時もフールプルーフのようにうっかりミスを防ぐ仕掛けは欲しいです。
また、そんな仕掛けを考えるもの楽しいなと思いました。