How do I insert text into the Text widget in the current tab?

I recently learned about the Notebook widget. And I wanted to add tabs dynamically.

from tkinter import *
from tkinter import ttk

root = Tk ()

n = ttk.Notebook (root)
n.pack (fill = X)
tab = 1
def new_tab ():
   global tab
   text = Text (root)
   text.pack ()
   n.add (text, text = ("tab" + str (tab)))
   tab += 1

def check ():
   '' 'code to insert text into Text widget' ''
   ...

plus = Button (root, text = '+', command = new_tab)
plus.pack (side = LEFT)

check_button = Button (root, text = 'check', command = check)
check_button.pack (side = LEFT)

root.mainloop ()

I added tabs, but when I try to insert any text using insert in the check function, python gives an error. But the problem is not entirely a bug. I wanted to insert text into the text widget in the current tab.

Upvotes: 0

Views: 748

Answers (1)

martineau
martineau

Reputation: 123531

You need to make a text widget that exists outside of the new_tab() function — in your code it's a local variable which cannot be accessed after the function returns.

A simple way (but not the best, since global variables are bad) is to make the text variable a global. A better way would be to use classes to encapsulate your application's data.

Here's an example of the former:

from tkinter import *
from tkinter import ttk

root = Tk()

n = ttk.Notebook(root)
n.pack(fill=X)
tab = 1
text = None

def new_tab():
   global tab
   global text
   text = Text(root)
   text.pack()
   n.add(text, text=("tab" + str(tab)))
   tab += 1

def check():
   """ Insert text into Text widget if it exists. """
   if text:
       text.insert(END, 'new text\n')

plus = Button(root, text='+', command=new_tab)
plus.pack(side=LEFT)

check_button = Button(root, text='check', command=check)
check_button.pack(side=LEFT)

root.mainloop()

For comparison, here's an example of the latter which has a minimal number of globals because it's based on the object-oriented programming paradigm, aka the OOP way, of implementing software — namely by defining a class that encapsulates the whole application.

Note I've also changed how the imports are being done because, for the most part, wildcard imports are also considered a poor programming practice (see Should wildcard import be avoided?).

import tkinter as tk
import tkinter.ttk as ttk
from tkinter.constants import *


class MyApplication(tk.Tk):
    def __init__(self):
        super().__init__()
        self.nb = ttk.Notebook(self)
        self.nb.pack(fill=X)
        self.tab = 1
        self.text = None

        self.plus = tk.Button(self, text='+', command=self.new_tab)
        self.plus.pack(side=LEFT)

        self.check_button = tk.Button(self, text='check', command=self.check)
        self.check_button.pack(side=LEFT)

    def new_tab(self):
       self.text = tk.Text(self)
       self.text.pack()
       self.nb.add(self.text, text=("tab" + str(self.tab)))
       self.tab += 1

    def check(self):
       """ Insert text into Text widget if it exists. """
       if self.text:
           self.text.insert(END, 'new text\n')


app = MyApplication()
app.mainloop()

Upvotes: 2

Related Questions