14
14
class PasswordGenerator :
15
15
def __init__ (self ):
16
16
self .app = tk .Tk ()
17
- self .app .title ("Memorable Password Generator" )
17
+ self .app .title ("SafePass - Password Generator" )
18
18
self .app .resizable (width = False , height = False )
19
19
self .style = ttk .Style ()
20
20
self .style .theme_use ("xpnative" )
@@ -23,6 +23,8 @@ def __init__(self):
23
23
self .numbers_var = tk .BooleanVar ()
24
24
self .special_chars_var = tk .BooleanVar (value = True )
25
25
self .test_button = tk .Button (text = "Test" )
26
+ self .passphrases = [] # store the passphrases separately
27
+ self .passphrase_labels = [] # store the labels separately
26
28
self .create_widgets ()
27
29
28
30
def toggle_multiple_passphrases (self ):
@@ -34,7 +36,7 @@ def toggle_multiple_passphrases(self):
34
36
self .num_passphrases_label .grid_forget ()
35
37
self .num_passphrases_spinbox .grid_forget ()
36
38
self .num_passphrases_spinbox .config (state = "disabled" )
37
-
39
+
38
40
def create_widgets (self ):
39
41
num_words_label = ttk .Label (self .app , text = "Number of words:" )
40
42
num_words_label .grid (row = 0 , column = 0 , padx = 10 , pady = 5 , sticky = "w" )
@@ -60,12 +62,6 @@ def create_widgets(self):
60
62
generate_button = ttk .Button (self .app , text = "Generate" , command = self .generate_button_clicked )
61
63
generate_button .grid (row = 4 , column = 0 , columnspan = 2 , padx = 10 , pady = 10 )
62
64
63
- self .passphrase_label = ttk .Label (self .app , text = "" , wraplength = 300 )
64
- self .passphrase_label .grid (row = 5 , column = 0 , columnspan = 2 , padx = 10 , pady = 5 )
65
-
66
- self .copy_button = ttk .Button (self .app , text = "Copy" , command = self .copy_to_clipboard , state = tk .DISABLED )
67
- self .copy_button .grid (row = 6 , column = 0 , columnspan = 2 , padx = 10 , pady = 5 )
68
-
69
65
self .strength_label = ttk .Label (self .app , text = "" , wraplength = 300 )
70
66
self .strength_label .grid (row = 7 , column = 0 , columnspan = 2 , padx = 10 , pady = 5 )
71
67
@@ -76,8 +72,6 @@ def create_widgets(self):
76
72
self .feedback_crack_time .grid (row = 9 , column = 0 , columnspan = 2 , padx = 10 , pady = 5 )
77
73
78
74
self .toggle_multiple_passphrases ()
79
-
80
-
81
75
82
76
def generate_passphrase (self , num_words , add_numbers , add_special_chars , min_digits = 1 , max_digits = 4 , capitalize_percentage = 60 , include_spaces = True ):
83
77
words = [secrets .choice (wordlist ).capitalize () for _ in range (num_words )]
@@ -103,7 +97,7 @@ def generate_passphrase(self, num_words, add_numbers, add_special_chars, min_dig
103
97
return passphrase
104
98
105
99
raise RuntimeError (f'Unable to generate a secure passphrase after attempts' )
106
-
100
+
107
101
def generate_button_clicked (self ):
108
102
num_words = self .num_words_entry .get ()
109
103
if num_words is None or num_words == "" :
@@ -125,9 +119,17 @@ def generate_button_clicked(self):
125
119
126
120
for i in range (num_passphrases ):
127
121
passphrases .append (self .generate_passphrase (num_words , self .numbers_var .get (), self .special_chars_var .get (), include_spaces = self .include_spaces .get ()))
128
-
129
- self .passphrase_label .config (text = "\n " .join ([f"Passphrase { i + 1 } : { passphrase } " for i , passphrase in enumerate (passphrases )]))
130
- self .copy_button .config (state = tk .NORMAL )
122
+ #Destroy previous labels, so it does not overlap.
123
+ for label in self .passphrase_labels :
124
+ label .destroy ()
125
+
126
+ self .passphrases = passphrases # store the passphrases
127
+ self .passphrase_labels = [] # clear the old labels
128
+ for i , passphrase in enumerate (passphrases ):
129
+ label = ttk .Label (self .app , text = f"Passphrase { i + 1 } : { passphrase } " , wraplength = 300 )
130
+ label .grid (row = 5 + i , column = 0 , columnspan = 2 , padx = 10 , pady = 5 )
131
+ label .bind ("<Button-1>" , self .copy_to_clipboard ) # bind click event
132
+ self .passphrase_labels .append (label ) # store the label
131
133
132
134
strength_result = test_password (passphrases [0 ])
133
135
self .strength_label .config (text = f"Password Strength: { strength_result ['score' ]} /4" )
@@ -137,13 +139,20 @@ def generate_button_clicked(self):
137
139
except ValueError as e :
138
140
messagebox .showerror ("Error" , f"An error occurred while generating the passphrase:\n { e } " )
139
141
140
- def copy_to_clipboard (self ):
141
- passphrase = self .passphrase_label .cget ("text" ).split (": " )[1 ]
142
+ def copy_to_clipboard (self , event = None ):
143
+ # get the index of the clicked label
144
+ label_index = self .passphrase_labels .index (event .widget )
145
+ # get the corresponding passphrase
146
+ passphrase = self .passphrases [label_index ]
142
147
pyperclip .copy (passphrase )
143
148
threading .Timer (clear_duration , clear_clipboard ).start ()
144
149
150
+ # provide visual feedback
151
+ event .widget .config (foreground = "green" )
152
+ self .app .after (2000 , lambda : event .widget .config (foreground = "black" )) # change color back after 2 seconds
153
+
145
154
def run (self ):
146
155
self .app .mainloop ()
147
156
148
157
if __name__ == "__main__" :
149
- PasswordGenerator ().run ()
158
+ PasswordGenerator ().run ()
0 commit comments