0

whenever I click the restart button to update the text of notification1 (label)

from tkinter import *
import tkinter as tk
from multiprocessing import Process


def notify(text):
    notify_heading_text.set(f"App : {text}")
    
    
def on_restart():
    notify("This text will be updated")
    t1 = Process(target=print_hi)
    t1.daemon = True
    t1.start()
    
    
def print_hi():
    notify("Hi There")



if __name__ == '__main__':
    root = Tk()
    root.geometry('400x400')
    root.resizable(0, 0)
    global notify_heading_text
    notify_heading_text = tk.StringVar()

    notification1 = Label(height=1, textvariable=notify_heading_text, bd=0)
    notification1.pack(fill=X, side=TOP)
    notification1.configure(bg='white', fg='black', font=('Helvetica', 12, 'bold'), pady=10)
    bind3 = tk.StringVar()
    b3 = Button(root, borderwidth=0, fg="white", activebackground='#40556a', activeforeground='white', bg="black",
                textvariable=bind3, command=on_restart, font=('Helvetica', 12, 'bold'), padx=10, pady=6)
    bind3.set('Restart')
    b3.pack(side=RIGHT)

    root.mainloop()

I get this error

Process Process-1:
Traceback (most recent call last):
  File "C:\Users\prana\AppData\Local\Programs\Python\Python39\lib\multiprocessing\process.py", line 315, in _bootstrap
    self.run()
  File "C:\Users\prana\AppData\Local\Programs\Python\Python39\lib\multiprocessing\process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\prana\PycharmProjects\tkinter\main.py", line 18, in print_hi
    notify("Hi There")
  File "C:\Users\prana\PycharmProjects\tkinter\main.py", line 7, in notify
    notify_heading_text.set(f"App : {text}")
NameError: name 'notify_heading_text' is not defined

notify("This text will be updated") inside on_restart() method works fine and updates text but that same method inside print_hi() method does not update the text of Tkinter window says 'notify_heading_text' is not defined although it is declared as a global variable. For some reason, I can't use root.after() which updates the display of the Tkinter window without errors and works fine but I want to thread.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
Pranav HS
  • 53
  • 7
  • within the function ```def notify(text)``` the variable ```notify_heading_text``` is locally defined. It does not .refer to the ```tk.StringVar ``` defined in main. – itprorh66 Apr 27 '21 at 15:16
  • I inserted 'global notify_heading_text' inside 'notify(text)' function but that too did not work. – Pranav HS Apr 27 '21 at 15:40
  • @itprorh66 That is completely wrong. – TheLizzard Apr 27 '21 at 15:42
  • @PranavPranav I get no errors when running the code. Are you sure you don't call `on_restart` before the `notify_heading_text = tk.StringVar()`? Also the `multiprocessing` library can act weirdly sometimes. I usually stick with `threading`. What python version are you using? – TheLizzard Apr 27 '21 at 15:43
  • I copied the above code from my 'pycharm' IDE as it is, and have called once (i.e only 'command=on_restart' inside b3 button) – Pranav HS Apr 27 '21 at 15:49
  • Brother, I prefer multiprocessing only because as I said in this "https://stackoverflow.com/questions/67285428/tkinter-after-cancel-method-is-not-working-and-is-blocking-button-python" I want to use the stop button this can be achieved by 'terminate' the method of multiprocessing module. Also, I highly doubt the problem to be something to do with Tkinter. – Pranav HS Apr 27 '21 at 15:54
  • Did you try hitting the 'Restart' button? Does text gets updated?. I get the above error mentioned in question when I hit the restart button. – Pranav HS Apr 27 '21 at 15:58
  • I get the same error problem in the command prompt also and the python version is 'Python 3.9.1'.And error only comes up when the restart button is pressed (in order to update text of label) – Pranav HS Apr 27 '21 at 16:00
  • @PranavPranav Interestingly enough I don't get the error when running it through IDLE but I do get it when running it in `cmd`... No idea why. I am currently writing an answer that should help. – TheLizzard Apr 27 '21 at 16:02
  • I get in pycharm IDE too.But thanks for your time – Pranav HS Apr 27 '21 at 16:04
  • I think Tkinter somehow messes with thread because the same function ( that is 'notify() ' function) works fine in the on_restart() method but that same function fails to work inside print_hi(). – Pranav HS Apr 27 '21 at 16:09

1 Answers1

1

Try this:

import tkinter as tk
from threading import Thread

def notify(text):
    label.config(text=f"App : {text}")

def on_restart():
    notify("This text will be updated")
    t1 = Thread(target=print_hi, daemon=True)
    t1.start()

def print_hi():
    notify("Hi There")


root = tk.Tk()

label = tk.Label(root, text="")
label.pack(fill="x", side="top")

button = tk.Button(root, text="Restart", command=on_restart)
button.pack()

root.mainloop()

The problem with your code is that you are using multiprocessing and that creates a new python process with its own memory. The new python process can't find the global notify_heading_text variable so it throws the error. I switched multiprocessing to threading and it should now work. Different threads inside a process use the same memory so that is why the error no longer appears.

Also just to simplify the code I replaced the tk.StringVars and used <tkinter.Label>.config(text=<new text>)

Edit:

The reason I couldn't see the error message in IDLE, is because the error is written to the console but in the IDLE case it runs without a console. Therefore the error was still there but there was no way of seeing it. Also reading this proves that multiprocessing can't find the global variable that you are referencing. That is why I use threading most of the time.

TheLizzard
  • 7,248
  • 2
  • 11
  • 31