1

I want to change the text displaying in frame after my mainloop() has been called. I have created loginfo function to append text in my string but nothing happens. The GUI gets started and displays the text originally contained in it("hi"), I don't see the text I add through loginfo function ("hello") and after exiting the GUI I get the below error.

Traceback (most recent call last):
  File "1.py", line 5, in <module>
    monitor.loginfo()
  File "/home/shreyas/Desktop/test/main.py", line 45, in loginfo
    self.text.configure(state='normal')
  File "/usr/lib/python3.8/tkinter/__init__.py", line 1637, in configure
    return self._configure('configure', cnf, kw)
  File "/usr/lib/python3.8/tkinter/__init__.py", line 1627, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".!frame.!text"

My task is to create a function that i will call any time with the text i want to insert. The function will be called after the mainloop is running as i recieve the text to display.

These are the 2 files I created:

main.py

import tkinter
from tkinter import *

class Monitor:
    def __init__(self):
        self.root = Tk()
        self.root.title('Monitor')
        self.root.geometry("800x400")
        self.root.grid_columnconfigure((0,1), weight=1)
        self.root.grid_rowconfigure(0, weight=1)

        """-----------------------------------------------"""
        self.console = Frame(self.root,borderwidth=1)
        self.console.grid(row = 0, column = 0, sticky = W+E+N+S)

        self.console.grid_columnconfigure(0, weight=1)
        self.console.grid_rowconfigure(2, weight=1)

        self.lbl_c = Label(self.console, text="console",bg='white')
        self.lbl_c.grid(row = 1, column = 0, sticky = W+E+N+S)

        self.text = tkinter.Text(self.console)
        self.text.grid(row = 2, column = 0,rowspan = 3, columnspan = 1, sticky = N+S+E+W)
        self.text.insert(tkinter.END,"hi")
        self.text.configure(state='disabled')
        """------------------------------------------------"""
        self.fm = Frame(self.root,borderwidth=1)
        self.fm.grid(row = 0, column = 1, sticky = W+E+N+S)

        self.fm.grid_columnconfigure(0, weight=1)
        self.fm.grid_rowconfigure(2, weight=1)

        self.lbl_fm = Label(self.fm, text="frequency_monitor",bg='white')
        self.lbl_fm.grid(row = 1, column = 0, sticky = W+E+N+S)

        self.text1 = tkinter.Text(self.fm)
        self.text1.grid(row = 2, column = 0,rowspan = 1, columnspan = 1, sticky = N+S+E+W)
        self.text1.insert(tkinter.END,"<---------- Frequency Monitor ---------->\n\n"+"Camera100\n"+"Frequency: 9.6 CPU Time: 3.0ms\n"+("----------------------------------------")+"Screen100\n"+"Frequency: 29.8 CPU Time: 6.0ms\n"+("----------------------------------------"))
        self.text1.configure(state='disabled')
        


    def loginfo(self):
        self.text.configure(state='normal')
        self.text.insert(tkinter.END,"hello")
        self.text.update()
        self.text.configure(state='disabled')

1.py

import main as m

monitor = m.Monitor()
monitor.root.mainloop()
monitor.loginfo()

I use python 3.1 to run my code. Can someone please tell me what's causing the error and how could I achieve the expected result.

update: when i use mainloop() like so

import main as m

monitor = m.Monitor()
monitor.root.mainloop()
monitor.root.update()
monitor.root.update_idletasks()
monitor.loginfo()

i get the same error but when i use while

import main as m

monitor = m.Monitor()
#monitor.root.mainloop()
#monitor.loginfo()


while True:
    monitor.root.update()
    monitor.root.update_idletasks()
    monitor.loginfo()

it updates text and keeps updating it since i called loginfo in while But it doesnot update if i call it outside the while loop.

pain
  • 17
  • 8

1 Answers1

0

The code after mainloop() gets called only after your applications is closed. So after the application is closed, the method is called, but the widgets used in the method is destroyed. So change your code to:

monitor = Monitor()
monitor.loginfo()
monitor.root.mainloop()

This way, the function is called before you exit the GUI. Think of mainloop() as a while loop that keeps updating till the window is closed. Technically saying mainloop() is same as:

while True: # Only exits, because update cannot be used on a destroyed application
    root.update()
    root.update_idletasks()

Edit: Since you wanted a delay, you have to add a button or something that calls this method while the GUI is active, an example is to use after to show the function after some time, like:

monitor = Monitor()

monitor.root.after(1000,monitor.loginfo) # Cause a delay of 1 second or 1000 millisecond 

monitor.root.mainloop()
Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
  • But I want to update the text anytime after it is running. I had tried the above code before it just updates the text before launching the GUI. – pain Apr 15 '21 at 16:20
  • Fire up an event, add a button or something, ill include an example. – Delrius Euphoria Apr 15 '21 at 16:21
  • So you mean instead of calling mainloop i use a while loop. – pain Apr 15 '21 at 16:24
  • I think that will work. I will let you know if complete the task. Big Thnaks!! – pain Apr 15 '21 at 16:25
  • @pain Why use a `while`, use a `mainloop()` that is what it was made for ;) – Delrius Euphoria Apr 15 '21 at 16:25
  • @pain It is actually hard to understand code from comment, update your question with it. – Delrius Euphoria Apr 15 '21 at 16:32
  • @pain The problem with the code is in the `while` loop and it will keep on adding text forever and when you close the application it will give the same error as before, better to use a button the update i provided. – Delrius Euphoria Apr 15 '21 at 16:41
  • Actually the problem is there should not be a button in the gui and i have to call log info inside of a function.@Cool Cloud – pain Apr 15 '21 at 16:43
  • @pain Okay, lets go through this one more time. Tell me what exactly your lookin for, how do you want to call the function and when do you want to call it. – Delrius Euphoria Apr 15 '21 at 17:05
  • Firstly my GUI will start with displaying 'hi'. Then some function will run and generate data. Then i want to display this data after "hi". So i created a loginfo() function for that which i will call whenever i want to update the text. My problem is I'm unable to call loginfo once i enter the mainloop(). @Cool Cloud – pain Apr 15 '21 at 17:13
  • @pain So you should start by writing the function to run and generate data and then after the data is generated, add `monitor.loginfo()` to the end of it. – Delrius Euphoria Apr 15 '21 at 17:17
  • No but the data is generated any time and mostly after the GUI is started and i have to update it there. – pain Apr 15 '21 at 17:19
  • Yes where ever the data is generated, just add `monitor.loginfo()` to the end of the code after it, show some sample of generating data and ill try to show. – Delrius Euphoria Apr 15 '21 at 17:20
  • @pain ~ Would appreciate marking this as the correct answer if this answered your questions correctly. Click [here](https://meta.stackexchange.com/a/5235/775796) to learn how :D – Delrius Euphoria Apr 19 '21 at 23:52
  • actually using after method just called loginfo after every 1000 milsec, but i wanted to call it at some event. But i ended up using seperate thread for mainloop and loginfo to do that.I will update that in some days. Should i accept this answer ? – pain Apr 20 '21 at 14:20
  • @pain If you were able to find an answer here, then you can accept it. Adding a `thread` seems outside scope for your question because what you asked and threading is not related. Eventually `tkinter` will crash if you use multiple threads because tkinter is single threaded. – Delrius Euphoria Apr 20 '21 at 14:21
  • 1
    Okay i'll do that! – pain Apr 20 '21 at 15:52