Python – How do I set a Margin or Offset tag?

How do I set a Margin or Offset tag?… here is a solution to the problem.

How do I set a Margin or Offset tag?

I

tried to add a small auto margin to my text widget, but I had trouble writing the label.

I

have a text box and I try to insert text into the box with margins.

I

can make the inserted text have margins, but when I enter more than the last line, the margins disappear. All I’ve been able to dig into so far is how to write tags and use them with insert(), but I want to keep margins at all times.

Question: Is there a way to keep the margins of all lines, not just those inserted from a file or string?

Note that the same issue extends to the Offset tag, as I had the same problem typing after inserting text.

This is an example I tried in Minimal, Complete, and Verifiable example.

import tkinter as tk

root = tk. Tk()

text = tk. Text(root, width = 10, height = 10)
text.pack()

text.tag_configure("marg", lmargin1 = 10, lmargin2 = 10)
text.insert("end", "Some random text!", ("marg"))

root.mainloop()

enter image description here

Solution

Unfortunately, edge cases of adding and removing text at the beginning and end of widgets make it difficult to use labels.

If your goal is to maintain margins, one solution is to create a proxy for text widgets so that you can intercept all insertions and deletions and always add margins every time the widget content changes.

For example, the event that starts with generating a custom widget <<TextModified>> whenever the widget is modified:

class CustomText(tk. Text):
    def __init__(self, *args, **kwargs):
        tk. Text.__init__(self, *args, **kwargs)

# create a proxy for the underlying widget
        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._proxy)

def _proxy(self, command, *args):
        cmd = (self._orig, command) + args
        result = self.tk.call(cmd)

if command in ("insert", "delete", "replace"):
            self.event_generate("<<TextModified>>")

return result

(See https://stackoverflow.com/a/40618152/7432.)

Next, modify your program to use this proxy to force margin tags to always apply to the entire content:

def add_margin(event):
    event.widget.tag_add("marg", "1.0", "end")

text = CustomText(root, width = 10, height = 6)
text.bind("<<TextModified>>", add_margin)

Related Problems and Solutions