I am attempting to emulate a multiline password field. I have a textctrl (hidden) in which the plaintext are placed and a second textctrl (shown) in which “"s are placed. I have added an EVT_CHAR event handler. In general, when a char it typed in the shown textctrl, the typed character is WriteText-ed into the hidden textctrl, and an "” is WriteText-ed into the shown textctrl. DELETE and BACK are emulated by setting a selection, then Remove-ing the selected chars. If a DELETE, the selection is set by setting a begin location to the current location and an end location to the current location plus one. This deletes the next character. If a BACK, the selection is set by setting the begin location to the current location minus one and the end location to the current location. This deletes the previous character. This works fine unless the character to be deleted is a “\n” character representing the end of a line. Whether the cursor is set at the beginning of a line and BACK is typed, or the cursor is set at the end of a line and DEL is typed. The results are: the shown line of "*"s is shown correctly, but the hidden line of the actual texts, remains the same, i.e. no "\n"s are deleted.
Below’s a slimmed down version of what I have. when run, typed into the textctrl -------- "*s will be displayed in the box. If OK is pressed, the textctrl in the hidden textctrl will be typed in the console. If CANCEL is pressed, the program exits.
I’ve tried (a) setting a selection and Remove-ing it in the hidden texttrl; (b) WriteText-ing the BACK or DEL into the hidden textctrl; © using EmulateKeyPress(event) into the hidden texttrl. Nothing seems to works. Any suggestions would be welcome.
import wx
wxapp = wx.App()
class TypingDialog (wx.Dialog):
def __init__(self):
super().__init__(None,
id=wx.ID_ANY,
title="Title")
main_sizer = wx.BoxSizer(wx.VERTICAL)
self.typed_line = wx.TextCtrl(self,
wx.ID_ANY,
wx.EmptyString,
wx.DefaultPosition,
wx.DefaultSize,
wx.TE_MULTILINE | wx.TE_WORDWRAP)
main_sizer.Add(self.typed_line, 1, wx.ALL | wx.EXPAND, 5)
self.typed_line.Hide()
self.hidden_line = wx.TextCtrl(self,
wx.ID_ANY,
"hidden",
wx.DefaultPosition,
wx.DefaultSize,
wx.TE_MULTILINE | wx.TE_WORDWRAP)
main_sizer.Add(self.hidden_line, 1, wx.ALL | wx.EXPAND, 5)
self.hidden_line.Show()
self.hidden_line.SetFocus()
button_sizer = wx.StdDialogButtonSizer()
self.button_sizerOK = wx.Button(self, wx.ID_OK)
button_sizer.AddButton(self.button_sizerOK)
self.button_sizerCancel = wx.Button(self, wx.ID_CANCEL)
button_sizer.AddButton(self.button_sizerCancel)
button_sizer.Realize()
main_sizer.Add(button_sizer, 0, wx.EXPAND, 5)
self.SetSizer(main_sizer)
self.Layout()
self.Centre(wx.BOTH)
self.hidden_line.Bind(wx.EVT_CHAR, self.onTypedText)
pass
def onTypedText(self, event):
UCkeycode = event.GetUnicodeKey()
keycode = event.GetKeyCode()
beg, end = self.hidden_line.GetSelection()
if UCkeycode == wx.WXK_NONE:
if keycode == wx.WXK_DELETE:
end += 1 if beg == end else 0
self.typed_line.Remove(beg, end)
event.Skip()
elif UCkeycode == wx.WXK_BACK:
beg -= 1 if beg == end else 0
self.typed_line.Remove(beg, end)
event.Skip()
elif UCkeycode in [wx.WXK_RETURN]:
self.typed_line.SetSelection(beg, end)
self.typed_line.WriteText(chr(UCkeycode))
self.hidden_line.WriteText(chr(UCkeycode))
elif UCkeycode < wx.WXK_SPACE:
pass
else:
self.typed_line.SetSelection(beg, end)
self.typed_line.WriteText(chr(UCkeycode))
self.hidden_line.WriteText("*")
self.hidden_line.SetFocus()
if name == ‘main’:
with TypingDialog() as td:
rtn = ''
while rtn is not None:
rtn = td.ShowModal()
if rtn == wx.ID_CANCEL: break
print("\ntyped:\n------\n%s" % td.typed_line.GetValue())
print(" OK:", rtn == wx.ID_OK)
print()
print("\nCancel:", rtn == wx.ID_CANCEL)
pass
``