Tkinter text.insert()

How does text or insert() on the text widget work? I thought that with string parameters indicating line and column text string could be placed in whatever part of the window, e.g. via:

text = tk.Text(okno, height=10)
text.insert("5.3", f"Toto je test")
text.pack(expand=True, fill = "both")

But it doesn’t work. Sample text is always on the first line from the top left corner. If I add the insert method, it does work within a non-empty line:

text = tk.Text(okno, height=10)
text.insert("1.0", f"Toto je test")
text.insert("1.5", "TEST")
text.pack(expand=True, fill = "both")

So is there a rule for the text widget on how the text is deployed in it or what?

A text widget is not just a rectangle where you can just write whatever text at any pixel position - or even line and character position. It is a text field, which stores a single string of text which it displays with consistent line spacing and word wrapping - like the one in your browser where you typed the post.

Internally, the text of the text widget is a single string. Inserting at line 5, column 3 of an empty string is just going to set the text - there isn’t already a fifth line of the text, so the new text can’t go “into” that line, etc.

You could pre-initialize the text with some spaces and newlines; but then (if I’m thinking straight) the insert calls could push extra spaces to the right, and anyway your text can only be in proper “columns” if you use a monospace (typewriter) font.

1 Like

So even if I set height=10, it would createt the area of 10 lines heigh, but it will still be one text line devided somehow with newlines for ten lines, right?

That setting only tells Tkinter how much space to use for displaying the field (i.e., the rectangle surrounding the text). It doesn’t put any text into the Text widget’s underlying value. There is no “division” going on; when the underlying C library draws the text on the screen, it just… doesn’t, if there isn’t any text.

2 Likes

A Text is initialized with a single undeletable undisplayed newline. Although I cannot find this explicitly documented, it is implied by “there is always a last newline”. Text indexes are slice positions (between chars or before/after the always present first/last char). The initial indexed are ‘1.0’ and ‘2.0’.

The sometext.index(index) method converts any legal index to the actual text-dependent index that would be used by other Text methods that takes index arguments. Initially, t.index('5.3') returns ‘2.0’, that being the position after the default newline. With no text, this is effectively the same as ‘1.0’, as indicated in the insert doc: “If index refers to the end of the text (the character after the last newline) then the new text is inserted just before the last newline instead.” (This should say *position after the last newline.)

2 Likes

Here’s a test code for a text box. This one might help you.

import tkinter as tk

class App(tk.Tk):
    
    def __init__(self):
        
        super().__init__()      # Can use either one but only one
        #tk.Tk.__init__(self)
        
        self.title("Text Demo")
        self.resizable(0, 0)

        # Create editable text box
        self.text = tk.Text(self, width = 50, height = 5)

        # Create three buttons
        self.btn_clear = tk.Button(self, text = "Clear text",
                                   command = self.clear_text)
        self.btn_insert = tk.Button(self, text = "Insert text",
                                    command = self.insert_text)
        self.btn_print = tk.Button(self, text = "Print selection",
                                   command = self.print_selection)

        # Display/pack widgets
        self.text.pack()
        self.btn_clear.pack(side = tk.LEFT, expand = True, pady = 10)
        self.btn_insert.pack(side = tk.LEFT, expand = True, pady = 10)
        self.btn_print.pack(side = tk.LEFT, expand = True, pady = 10)
    
    def clear_text(self):
        
        self.text.delete("1.0", tk.END)
    
    def insert_text(self):
        
        self.text.insert(tk.INSERT, "Hello, world")
    
    def print_selection(self):
        
        selection = self.text.tag_ranges(tk.SEL)
        
        if selection: # Checks if selection is not empty
            
            content = self.text.get(*selection)
            print(content)

if __name__ == "__main__":
    
    app = App()
    app.mainloop()

By the way, can you provide a screenshot of the widget in question so that we can clearly understand your objective with the widget?

Unfortunately not, I have deleted that code already. I am in the process of learning and thinking. But sometimes I encounter problems I don’t understand or I am not able to find a solution online. So this was one of them.

Here, I have created a simple test script whereby it demonstrates how to move the text anywhere you want on a window merely by changing the values of x and y of the place geometry manager. Aside from the place(), there is the pack() and the grid() geometry managers. The place() is generally the placement geometry manager that gives you the most degrees of freedom but may not necessarily be the best for your application.

import tkinter as tk

class App(tk.Tk): 
    
    def __init__(self):
        
        super().__init__()

        self.x_value = 160
        self.y_value = 90       

        tk.Tk.title(self,'Place Geometry Manager') # Window title
        tk.Tk.geometry(self, '380x380')            # Window size

        self.label = tk.Label(self, text = "Text Location") # Create label
        self.label.place(anchor = tk.W, x = self.x_value, y = self.y_value)

        # Create buttons
        self.btn_pos_x = tk.Button(self, text = "+X", command = self.move_x_pos)                       
        self.btn_neg_x = tk.Button(self, text = "-X", command = self.move_x_neg)
        self.btn_pos_y = tk.Button(self, text = "+Y", command = self.move_y_pos)                            
        self.btn_neg_y = tk.Button(self, text = "-Y", command = self.move_y_neg)

        # Display buttons
        self.btn_pos_x.place(x = 40, y = 320)                       
        self.btn_neg_x.place(x = 130, y = 320) 
        self.btn_pos_y.place(x = 210, y = 320)                             
        self.btn_neg_y.place(x = 320, y = 320)        

    # Methods move the position of the text
    def move_x_pos(self):
        self.x_value += 10
        self.label.place( x = self.x_value)
        
    def move_x_neg(self):
        self.x_value -= 10
        self.label.place(x = self.x_value)

    def move_y_pos(self):
        self.y_value += 10
        self.label.place(y = self.y_value)

    def move_y_neg(self):
        self.y_value -= 10
        self.label.place(y = self.y_value)  

if __name__ == "__main__":
    
    app = App()
    app.mainloop()