How to make padding around the text of TextCtrl?

How to make padding around the text of TextCtrl?

I don’t think it is possible. TextCtrl is a simple control.

Not sure what you mean. Are you saying you want a way to pad the textctrl widget (the box) from other widgets? Or are talking about centering the text in the textctrl widget? If you take a look at the demo for wxPython and open the TextCtrl widget you will notice that you text is padded (the widget does it) within the space you setup on the panel. However, if you need to pad it more you can add spaces to the text string and that will make the widget see it as a larger string and the widget will try to fit the size correctly
Johnf

I’ve noticed that in a single line TextCtrl the text is offset from the edge of the control by a set amount, whereas in a multi-line TextCtrl it isn’t.

wx.TextCtrl is derived from wx.TextEntry which has a SetMargins() method, however, calling that method has no effect on a multi-line TextCtrl (at least on linux, which is all I can test on). The documentation for SetMargins() says that it attempts to set the control margins, but doesn’t specify where it might not work.

In contrast the text in a RichTextCtrl is offset from the edge of the control by default.

Screenshot at 2022-12-06 08-34-27

One way to give the text in a multi-line TextCtrl an offset could be to create a class derived from Panel that contains a TextCtrl in a BoxSizer. Below is a quick example that gives the Panel a border and sets its background colour to that of the TextCtrl. It also sets the TextCtrl to not have its own border and uses the BoxSizer to inset the TextCtrl in the Panel by the specified margin.

import wx

class InsetTextCtrl(wx.Panel):
    def __init__(self, parent, id=wx.ID_ANY, value="", margin=4, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, style=wx.TAB_TRAVERSAL | wx.BORDER_SUNKEN,
                 validator=wx.DefaultValidator, name="InsetTextCtrl"):
        wx.Panel.__init__(self, parent, id, pos, size, style, name)
        self.text_ctrl = wx.TextCtrl(self, id=wx.ID_ANY, value=value,
                                     style=wx.TE_MULTILINE | wx.BORDER_NONE,
                                     validator=validator)
        self.SetBackgroundColour(self.text_ctrl.GetBackgroundColour())
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.text_ctrl, 1, wx.EXPAND | wx.ALL, margin)
        self.SetSizer(sizer)
        self.Layout()

    def GetValue(self):
        return self.text_ctrl.GetValue()

    def SetValue(self, value):
        self.text_ctrl.SetValue(value)


class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((500, 200))
        self.SetTitle("InsetTextCtrl margins")
        self.panel = wx.Panel(self, wx.ID_ANY)
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.text_ctrl = InsetTextCtrl(self.panel, wx.ID_ANY, "", 8)
        sizer.Add(self.text_ctrl, 1, wx.EXPAND | wx.TOP, 4)
        self.panel.SetSizer(sizer)
        self.Layout()

        self.text_ctrl.SetValue("multi-line InsetTextCtrl " * 20)


class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

Screenshot at 2022-12-06 11-27-02

Tested on: Python 3.10.6 + wxPython 4.2.0 gtk3 (phoenix) wxWidgets 3.2.0 + Linux Mint 21

2 Likes

Hi Richard,

Thanks! I didn’t notice SetMargins method… It seems to work on Windows.

Code Example (click to expand)
"""Quote-Unquote

    Anything one man can imagine, other man can make real.
    --- Jules Verne (1828--1905)

https://en.wikipedia.org/wiki/Jules_Verne
"""
import wx

class Frame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        self.tc = wx.TextCtrl(self, value=__doc__,
                    style=wx.TE_MULTILINE
                        | wx.TE_PROCESS_ENTER
                        | wx.TE_AUTO_URL
                        )
        self.tc.SetMargins(16)
        self.tc.SetStyle(0, 13, wx.TextAttr('red', 'yellow'))
        self.tc.Bind(wx.EVT_TEXT_URL, self.OnURL)
    
    def OnURL(self, evt): #<wx._core.TextUrlEvent>
        url = self.tc.Value[evt.URLStart:evt.URLEnd]
        print(url)

if __name__ == "__main__":
    app = wx.App()
    frm = Frame(None)
    frm.Show()
    app.MainLoop()

image
wxPython 4.2.0 / Python 3.10.4 on Windows 10.

There’s a bug report for wxWidgets on GTK3:

The report was raised in 2012 and, going by the comments, a fix would be non-trivial, so I doubt it’s going to happen.