【问题标题】:wxPython multiline password fieldwxPython 多行密码字段
【发布时间】:2026-01-23 08:10:02
【问题描述】:

在 wxPython 中,密码样式仅适用于单行文本控件。我需要一个多行密码字段。我想到了两种方法:

  1. 我创建了一个字体,在每个代码点中都有一个字形(实心点)。但是,我可以理解用户不希望在他们的机器上安装字体。在 wxWidgets 中你可以使用私有字体,但在 wxPython 中不行。我缺少一种为此特定对话框动态加载此字体的方法。

  2. 子类化 wx.TextCtrl 并实现按输入存储文本,但仅显示单个字符。这听起来要复杂得多。并且需要一些关于我如何解决这个问题的建议。

我确实需要这个,我已经考虑过了。所以,我正在寻找关于我上面想到的两种方式的一些想法,或者任何其他可能的实现。

【问题讨论】:

    标签: wxpython wxtextctrl


    【解决方案1】:

    在输入密码时将密码存储在 textctrl 中!

    import wx
    
    ########################################################################
    class LoginDialog(wx.Dialog):
        """
        Class to define login dialog
        """
        def __init__(self):
            wx.Dialog.__init__(self, None, title="Login")
            self.logged_in = False
            self.attempts = 3
            self.stored_password = ""
            # user info
            user_sizer = wx.BoxSizer(wx.HORIZONTAL)
            user_lbl = wx.StaticText(self, label="Username:")
            user_sizer.Add(user_lbl, 0, wx.ALL|wx.CENTER, 5)
            self.user = wx.TextCtrl(self)
            user_sizer.Add(self.user, 0, wx.ALL, 5)
    
            # password info
            p_sizer = wx.BoxSizer(wx.HORIZONTAL)
            p_lbl = wx.StaticText(self, label="Password:")
            p_sizer.Add(p_lbl, 0, wx.ALL|wx.CENTER, 5)
            self.password = wx.TextCtrl(self, style=wx.TE_MULTILINE)
            self.password.Bind(wx.EVT_TEXT,self.OnMask)
            p_sizer.Add(self.password, 0, wx.ALL, 5)
    
            main_sizer = wx.BoxSizer(wx.VERTICAL)
            main_sizer.Add(user_sizer, 0, wx.ALL, 5)
            main_sizer.Add(p_sizer, 0, wx.ALL, 5)
    
            btn = wx.Button(self, label="Login")
            btn.Bind(wx.EVT_BUTTON, self.onLogin)
            main_sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
    
            self.SetSizer(main_sizer)
    
        def OnMask(self, event):
            disp_pass = self.password.GetValue()
            #Test for backspace/clear event
            p_len = disp_pass.count('*')
            if p_len < len(self.stored_password):
                self.stored_password = self.stored_password[:p_len]
                return
            #Store the last input character
            try:
                char = disp_pass[-1]
                self.stored_password = self.stored_password + char
            #Mask the input
                self.password.ChangeValue("*" * len(disp_pass))
            except:
                pass
    
        def onLogin(self, event):
            valid_password = "password1\npassword2\npassword3"
            user_password = self.stored_password
            if user_password == valid_password:
                self.logged_in = True
                self.Close()
                return
            else:
                wx.MessageBox('Login failed', 'Error', wx.OK | wx.ICON_ERROR)
                self.stored_password = ""
                self.password.SetValue("")
            self.attempts -= 1
            if self.attempts < 1:
                wx.MessageBox('Too many Login attempts', 'Error', wx.OK | wx.ICON_ERROR)
                self.Close()
    
    class MyPanel(wx.Panel):
        def __init__(self, parent):
            wx.Panel.__init__(self, parent)
            user_lbl = wx.StaticText(self, label="Log in Successfull")
    
    class MainFrame(wx.Frame):
        def __init__(self):
            wx.Frame.__init__(self, None, title="Main App")
            panel = MyPanel(self)
            dlg = LoginDialog()
            dlg.ShowModal()
            authenticated = dlg.logged_in
            dlg.Destroy()
            if not authenticated:
                wx.MessageBox('Login failed', 'Error', wx.OK | wx.ICON_ERROR)
                self.Destroy()
            self.Show()
    
    if __name__ == "__main__":
        app = wx.App()
        frame = MainFrame()
        app.MainLoop()
    

    请注意 self.password.ChangeValue() 而不是 self.password.SetValue(),防止在更新时触发 EVT_TEXT。

    【讨论】:

    • 这已经最接近我的需要了。我已将此作为子类化我的 textctrls 的起点。谢谢。
    【解决方案2】:

    wx.TE_MULTILINEwx.TE_PASSWORD 可以一起使用样式。

    ...
    editor = wx.TextCtrl(..., style=wx.TE_MULTILINE | wx.TE_PASSWORD)
    ...
    

    【讨论】:

    • 您可以在代码中指定两者,就像您所做的那样。但是多行 textctrl 不作为密码字段操作。