基于CustomTkinter的延迟隐藏密码输入框集成求助
适配CustomTkinter的延迟隐藏密码输入框问题解决
我是Python初学者,尝试将Stack Overflow用户@srccircumflex的Tkinter延迟隐藏密码输入框代码适配到CustomTkinter中,已将原类继承的Entry替换为ctk.CTkEntry,以下是修改后的代码,希望得到技术帮助。
import customtkinter as ctk import tkinter as tk #using messagebox from tkinter import filedialog from tkinter import END, INSERT, SEL_FIRST, SEL_LAST import PyPDF2 from PyPDF2 import PdfWriter from sys import platform from typing import Iterable merger = PdfWriter() def merge_pdfs(): #code to merge pdf files file_password = entry_password.getpass() ... #PASSENTRY # Copyright (c) 2022 Adrian F. Hoefflin [srccircumflex] ------------------------------ class PassEntry(ctk.CTkEntry): def __init__(self, master, show: chr = "*", delay: int = 800, getpass_range: Iterable = None, getpass_call: ... = None, getpass_del: bool = False, **tk_kwargs, ): """ Password entry with delayed hiding. Alternative to `Entry(master, show="*")'. Supports all common character sets(1aA!), multy keys(^`˝) and under Linux also the alternative graphics(↑Ωł). {Deletes the input from the widget and writes it casually into a variable. Markings and the position of the cursor is respected.} howto get the password: - by protected member self._password - by calling self.getpass (args `getpass_*' executed here) - by calling self.get (args `getpass_*' executed here) :param master: root tk :param show: displayed char :param delay: hiding delay :param getpass_range: check password length :param getpass_call: callable, gets `self._password' as argument :param getpass_del: delete `self._password' and flush entry if True :param tk_kwargs: Valid resource names: background, bd, bg, borderwidth, cursor, exportselection, fg, font, foreground, highlightbackground, highlightcolor, highlightthickness, insertbackground, insertborderwidth, insertofftime, insertontime, insertwidth, invalidcommand, invcmd, justify, relief, selectbackground, selectborderwidth, selectforeground, state, takefocus, textvariable, validate, validatecommand, vcmd, width, xscrollcommand """ self._password: str = "" self.delay: int = delay self.show: chr = show self.getpass_range: Iterable = getpass_range self.getpass_call: ... = getpass_call self.getpass_del: bool = getpass_del ctk.CTkEntry.__init__(self, master, **tk_kwargs) self.bind("<Key>", self._run, add='+') self.bind("<Button>", self._run, add='+') self._external: bool = False self.get = self.getpass if platform == "linux": self._states = (0, 16, 17, 144, 145) elif platform == "win32": self._states = (0, 8, 9) def _char(self, event) -> str: def del_mkey(): i = self.index(INSERT) self.delete(i - 1, i) if event.keysym in ('Delete', 'BackSpace'): return "" elif event.keysym == "Multi_key" and len(event.char) == 2: if event.char[0] == event.char[1]: self.after(10, del_mkey) return event.char[0] return event.char elif event.char != '\\' and '\\' in f"{event.char=}": return "" elif event.num in (1, 2, 3): return "" elif event.state in self._states: return event.char return "" def _run(self, event): if self._external and self._char(event): self._external = False self.clear() def hide(index: int, lchar: int): i = self.index(INSERT) for j in range(lchar): self.delete(index + j, index + 1 + j) self.insert(index + j, self.show) self.icursor(i) if event.keysym == 'Delete': if self.select_present(): start = self.index(SEL_FIRST) end = self.index(SEL_LAST) else: start = self.index(INSERT) end = start + 1 self._password = self._password[:start] + self._password[end:] elif event.keysym == 'BackSpace': if self.select_present(): start = self.index(SEL_FIRST) end = self.index(SEL_LAST) else: if not (start := self.index(INSERT)): return end = start start -= 1 self._password = self._password[:start] + self._password[end:] elif char := self._char(event): if self.select_present(): start = self.index(SEL_FIRST) end = self.index(SEL_LAST) else: start = self.index(INSERT) end = start self._password = self._password[:start] + char + self._password[end:] self.after(self.delay, hide, start, len(char)) def insert(self, index, string: str) -> None: self._external = True super().insert(index, string) def delete(self, first, last=None) -> None: self._external = True super().delete(first, last) def clear(self): self._password = "" self.delete(0, END) # 恢复placeholder_text(如果需要) if self.cget("placeholder_text"): self.configure(placeholder_text=self.cget("placeholder_text")) def getpass(self): password = self._password if self.getpass_range: assert len(self._password) in self.getpass_range, f'## Password length not in {self.getpass_range}' if self.getpass_call: password = self.getpass_call(self._password) if self.getpass_del: self._password = "" self.delete(0, END) return password #PASSENTRY---------------------------------------------------------------------------------- if __name__ == "__main__": #main window root = ctk.CTk() root.title("Merge PDF") #Create user input entry for filename ... #Create user input entry for optional password entry_password = PassEntry( master=root, width=200, height=40, border_width=1, fg_color="white", placeholder_text="OPTIONAL: Enter password...", text_color="black", font=('Arial Rounded MT Bold', 14)) entry_password.grid(row=2, column=0, padx=20, pady=(10,20)) # Create a button to merge the selected PDF files ... root.mainloop()
关键修改说明
- 事件绑定追加:在
bind()方法中添加add='+',避免覆盖CTkEntry原有事件处理逻辑 - 替换底层调用:删除自定义的
_get()、_delete()、_insert()方法,直接使用CTkEntry继承的公开方法 - 简化clear方法:去掉不必要的
del self._password,直接重置字符串并清空输入框,可选恢复placeholder_text - 优化方法调用:简化
getpass_call的调用方式,去掉冗余的__call__显式调用 - 明确错误提示:修改断言信息,明确提示密码长度不符合要求
内容的提问来源于stack exchange,提问作者k1dr0ck
相关产品推荐
相关产品推荐

