不間斷 Python 挑戰 Day 32 - 專題:密碼產生器-使用tkinter

2022/05/10閱讀時間約 20 分鐘
先前的文章中,我們曾經實做過文字介面版本的密碼產生器,這篇文章中,我們將添加新的功能,包括記錄密碼使用場域的名稱、網址、帳號等,並能夠將以上記錄存檔,當然最重要的是將它轉換成友善的圖形介面。

密碼產生器

以下動畫展示了密碼產生器的完成品,操作流程包括:
  1. 點選「幫助」功能表的「關於」項目可跳出對話視窗顯示版本訊息。
  2. 在「名稱」、「網址」、「帳號」欄位輸入待產生密碼的相關資訊,點選「產生密碼」按鈕可生成隨機密碼。
  3. 最下方的下拉式選單可選擇密碼中包含大寫字母、小寫字母、數字以及特殊符號的個數。
  4. 點選「檔案」功能表的「儲存密碼」項目可跳出對話視窗,供使用者確認儲存資料,確認無誤後,將密碼及其相關資訊存入CSV檔案。
  5. 點選「檔案」功能表的「結束」項目可關閉視窗。
密碼產生器

實作流程

首先,我們先建立所有的視窗元件並進行版面配置,接著實作「產生密碼」按鈕的方法,這部分將根據文字版密碼產生器一文的程式碼進行改寫,最後再實作功能表項目的內容,包括「儲存密碼」、「結束」視窗以及「關於」程式的版本資訊。

視窗元件配置

由上方的展示動畫可以看到,除了最上方一排的功能表以外,共配置了五列(row)的視窗元件,最下方一列的欄位(column)數最多為八欄,所以在前三列的部分,標籤(label)佔一個欄位,文字方塊(entry)則佔七個欄位;第四列的標籤佔一個欄位,文字方塊佔五個欄位,並靠左對齊,按鈕(button)佔兩個欄位,並靠右對齊。
最下方列的下拉式選單(Combobox)來自tkinter的ttk模組,使用時必須額外載入此模組。下拉式選單的目的在於讓使用者選擇密碼所包含的字符內容,包括「大寫」字母、「小寫」字母、「數字」以及「符號」,並設定有預設值,每項最多可以選擇八個字符。
以下程式碼提供視窗元件配置的實作範例:
# modules
from tkinter import *
from tkinter import ttk

# window
password_gen_window = Tk()
password_gen_window.title("密碼產生器")
password_gen_window.config(padx=20, pady=20)

# labels
name_label = Label(text="名稱:")
name_label.grid(row=0, column=0)

url_label = Label(text="網址:")
url_label.grid(row=1, column=0)

username_label = Label(text="帳號:")
username_label.grid(row=2, column=0)

password_label = Label(text="密碼:")
password_label.grid(row=3, column=0)

u_letter_label = Label(text="大寫")
u_letter_label.grid(row=4, column=0, pady=4)

l_letter_label = Label(text="小寫")
l_letter_label.grid(row=4, column=2, pady=4)

number_label = Label(text="數字")
number_label.grid(row=4, column=4, pady=4)

symbol_label = Label(text="符號")
symbol_label.grid(row=4, column=6, pady=4)

# entries
name_entry = Entry(width=47)
name_entry.grid(row=0, column=1, columnspan=7)
name_entry.focus()

url_entry = Entry(width=47)
url_entry.grid(row=1, column=1, columnspan=7)

username_entry = Entry(width=47)
username_entry.grid(row=2, column=1, columnspan=7)

password_entry = Entry(width=25)
password_entry.grid(row=3, column=1, columnspan=4)

# button
generate_password_button = Button(text="產生密碼", width=20)
generate_password_button.grid(row=3, column=5, columnspan=3)

# combobox
u_letter_combo = ttk.Combobox(values=[0, 1, 2, 3, 4, 5, 6, 7, 8], width=4)
u_letter_combo.grid(row=4, column=1, pady=4)
u_letter_combo.current(4)

l_letter_combo = ttk.Combobox(values=[0, 1, 2, 3, 4, 5, 6, 7, 8], width=4)
l_letter_combo.grid(row=4, column=3, pady=4)
l_letter_combo.current(4)

number_combo = ttk.Combobox(values=[0, 1, 2, 3, 4, 5, 6, 7, 8], width=4)
number_combo.grid(row=4, column=5, pady=4)
number_combo.current(2)

symbol_combo = ttk.Combobox(values=[0, 1, 2, 3, 4, 5, 6, 7, 8], width=4)
symbol_combo.grid(row=4, column=7, pady=4)
symbol_combo.current(2)

# menus
password_gen_menu = Menu()
password_gen_window.config(menu=password_gen_menu)

file_menu = Menu(tearoff=False)
file_menu.add_command(label="儲存密碼")
file_menu.add_command(label="結束")

about_menu = Menu(tearoff=False)
about_menu.add_command(label="關於")

password_gen_menu.add_cascade(label="檔案", menu=file_menu)
password_gen_menu.add_cascade(label="幫助", menu=about_menu)

# mainloop
password_gen_window.mainloop()
執行結果如下:
密碼產生器主視窗
「檔案」功能表
「幫助」功能表

產生密碼

這部分僅為改寫文字版本的密碼產生器,並包裝成一個函式,架構基本上相同,在亂數選取字符的方式由迴圈改成了串列生成(list comprehension),以及在串列合成字串的方式使用了join()方法,讓程式碼更為簡潔。
from random import choice, shuffle

def generate_password():
  numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
  symbols = ["~", "!", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+"]
  u_letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
         'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
  l_letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
         'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

password_numbers = [choice(numbers) for _ in range(int(number_combo.get()))]
password_symbols = [choice(symbols) for _ in range(int(symbol_combo.get()))]
password_u_letters = [choice(u_letters) for _ in range(int(u_letter_combo.get()))]
password_l_letters = [choice(l_letters) for _ in range(int(l_letter_combo.get()))]

password_list = password_numbers + password_symbols + password_u_letters + password_l_letters
shuffle(password_list)
password = "".join(password_list)
password_entry.delete(0, END)
password_entry.insert(0, password)
「產生密碼」按鈕的初始化程式碼必須將產生按鈕事件的函式帶入。
generate_password_button = Button(text="產生密碼", width=12, command=generate_password)
執行後,點選「產生密碼」即可依據下方所選定的字符種類及個數亂數產生密碼。
產生密碼

儲存密碼

當「名稱」、「網址」、「帳號」以及「密碼」等欄位都設定完成後,可將資料儲存到檔案中,以便利後續查找。在儲存之前,可以跳出對話方塊以提示使用者對資料做最後的檢查,包括:
  • 是否有欄位為空
  • 輸入資料是否正確
在tkinter的messagebox模組中提供了八種形式的對話方塊,可依據不同情境使用,以下列舉這八種對話方塊,並在本專案中使用其中三種。
  1. 顯示一般訊息:
    messagebox.showinfo(title=None, message=None, **options)
  2. 顯示警告訊息:
    messagebox.showwarning(title=None, message=None, **options)
  3. 顯示錯誤訊息:
    messagebox.showerror(title=None, message=None, **options)
  4. 顯示詢問訊息:
    messagebox.askquestion(title=None, message=None, **options)
  5. 顯示確定或取消訊息:
    messagebox.askokcancel(title=None, message=None, **options)
  6. 顯示重試或取消訊息:
    messagebox.askretrycancel(title=None, message=None, **options)
  7. 顯示是或否訊息:
    messagebox.askyesno(title=None, message=None, **options)
  8. 顯示是或否或取消訊息:
    messagebox.askyesnocancel(title=None, message=None, **options)
其中的參數用法如下:
title:對話方塊的名稱
message:對話方塊內的文字
options:可設定以下參數
  default:選擇預設按鈕,有YES(是)、NO(否)、CANCEL(取消)、OK(確定)、
       RETRY(重試)可以設定
  icon:選擇方塊內顯示的圖示,有INFO、ERROR、 QUESTION、
     WARNING可以設定
  parent:當對話方塊關閉後,焦點視窗返回的父視窗
回到專案,在確認「是否有欄位為空」的部分,程式可透過檢查每個欄位內的字串長度來判定是否有欄位忘了輸入,若有任一欄位內的字串長度為0,可使用messagebox.showwarning()跳出警告訊息,並回到主視窗介面;若確認通過,可用messagebox.askokcancel()跳出確認或取消的對話方塊,並在對話方塊上顯示「名稱」、「網址」、「帳號」、「密碼」等訊息,以提示使用者確認「輸入資料是否正確」,點選「確定」後將資料存入CSV檔案中,並將所有欄位清除,若有需要修改可點選「取消」回到主視窗介面。
from tkinter import messagebox
from csv import writer

def save_password():
  name = name_entry.get()
  url = url_entry.get()
  username = username_entry.get()
  password = password_entry.get()

  if len(name) == 0 or len(url) == 0 or len(username) == 0 or len(password) == 0:
    messagebox.showwarning(title="警告", message="請確認是否有空白欄位!")
  else:
    is_ok = messagebox.askokcancel(title="密碼確認",
                     message=f"您所輸入的資訊:\n名稱:{name}\n網址:{url}\n帳號:{username}\n密碼:{password}")
    if is_ok:
      password_data_list = []
      with open("password_data.csv", mode="a", newline="") as password_file:
        password_data_list.append([name, url, username, password])
        password_data = writer(password_file)
        password_data.writerows(password_data_list)

        name_entry.delete(0, END)
        url_entry.delete(0, END)
        username_entry.delete(0, END)
        password_entry.delete(0, END)
「檔案」功能表的「儲存密碼」項目必須將儲存密碼的函式帶入。
file_menu.add_command(label="儲存密碼", command=save_password)
將程式加入專案並執行密碼儲存後,可看到專案資料夾底下多了一個password_data.csv檔案,裡面儲存了剛剛輸入的內容。
儲存密碼
產生password_data.csv
password_data.csv檔案內容
以EXCEL開啟password_data.csv

關於與結束視窗

「幫助」功能表的「關於」項目使用messagebox.showinfo()顯示版本資訊。
def about():
  messagebox.showinfo(title="關於", message="密碼產生器 V1.0")
同樣將事件的函式帶入該項目中。
about_menu.add_command(label="關於", command=about)
「結束」項目使用視窗元件的destroy()方法,在這裡是將整個視窗關閉,也等同於按視窗右上角的關閉圖示。
file_menu.add_command(label="結束", command=password_gen_window.destroy)
將程式加入專案中後即可執行「關於」與「結束」兩個項目,至此便將本文開頭展示的密碼產生器實作完成。
「關於」與「結束」功能

總結

這篇文章遙遙呼應了前面所實作的文字版密碼產生器,隨著python學習的知識愈來愈多,除了原程式碼的優化以外,也能將文字版本的程式轉換為圖形介面,並將程式輸入或輸出的結果儲存下來,讓程式的使用體驗更貼近於一般使用者。

程式範例

為什麼會看到廣告
Wei-Jie Weng
Wei-Jie Weng
留言0
查看全部
發表第一個留言支持創作者!