How can I delete end-of-line characters in a hidden multiline textctrl

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

``

Dennis Carachiola wrote:

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.

I think I have your answer, but you're not going to like it.

Let's say you type "abcd" Enter "efgh" Enter. If you fetch the text, you'll get 10 characters: "abcd\nefgh\n", but in the actual control, there are 12 characters. Newlines in a text control are stored as "\r\n". You can see this if you print self.hidden_line.GetSelection at the end of onTypeText. When you hit "Enter", the count increases by two.

You might be better served by skipping the "typed_line" thin altogether, and just track the text in a simple string.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

AH HA! Actually, I quite like it. That’s valuable information I didn’t have, thank you. I’ll try to adapt my code first, then convert it to saving the text in a string.

Den