Search code examples
shellformattinginputwxpythonwxwidgets

output readonly, input editable with wx.textctrl?


HI, guys,

I am using wxpython to develop a GUI for software configuration, launching and interaction. I want something like a CLI shell window (like pycrust) embedded inside the GUI to interact with a long-term running background process. I could give the input via this shell window and print the output on this window. My current code works very well. But there is problem of editing style, because wx.TextCtrl is simply an editable text window. e.g., I could overwrite or remove any previous text characters or type new input at any location. This is not desirable.

How can I make the wx.TextCtrl like a shell window, i.e. make the output readonly, while keep input editable? e.g.,

1) when input new command, the position only starts after prompt.

2) The user cannot change or replace any previous output text. I want to force certain restriction, for interaction purpose.

Is there a way to fix the curse prompt? If so, then my problem will be solved, because the user will have no chance to move the curse.

Or is there a way to set certain part of the text (the output and the prompt) readonly?

Or another solution, thanks to 9000's answer, is that I make a grid of windows (a StaticTextCtrl or readonly TextCtrl for output in the upper window; prompt ">>>" on the bottom left area; invisible-border editable window or entry dialog on the bottom right area for input).

any suggestions? Is there any better choice? Thanks a lot!


Solution

  • You could consider using some kind of input buffer.

    Capture each wx.EVT_KEY_DOWN event from the TextCtrl. If it's a keystroke that produces a character, append it to your buffer and let it go through. If it's a backspace, remove the last character from the buffer and allow it, or if there are no characters left in the buffer, don't allow it. This will protect your command prompt on the current line.

    You would also have to address each keyboard or mouse event that could reposition the cursor. If you don't want the user to be able to move the cursor around within the current line or move to previous lines, you'll have to detect and cancel arrow keys, home, end, page up, page down, mouse clicks, etc. It could be tough to lock down completely.

    Example for preventing keystrokes:

        # inside your Frame init function...
        self.text = wx.TextCtrl(self.panel, wx.ID_ANY, style=wx.TE_MULTILINE)
        self.text.Bind(wx.EVT_KEY_DOWN, self.OnKey)
        # ...
    
    def OnKey(self, evt):
        # keycodes for arrow keys, page up/down
        KEYS_TO_CANCEL = [314, 315, 316, 317, 366, 367]
    
        keycode = evt.GetKeyCode()
    
        if keycode in KEYS_TO_CANCEL:
            print('Cancelled!')
        else:
            evt.Skip()
    

    Good luck!