0

Is it possible to display the result of any variable in another file to the scrolltext. My question is: Image I have two python files. py1.py is the main file which contains only scrolledtext widget. And what I need to realize is that I want the result of any variable in py2.py to be consciously (incrementally) displayed in the scrolledtext widget (which is embedded in py1.py).

# -*- coding: utf-8 -*-
"""
py1.py
"""

import tkinter as tk
from tkinter import scrolledtext

win = tk.Tk()

text_area = scrolledtext.ScrolledText(win)

# for ii in range(100000):
#     mystr = "Step " + str(ii) + "\n"
#     text_area.insert(tk.END, mystr)
exec(open("py2.py").read())

text_area.see(tk.END)
text_area.pack()

win.mainloop()
"""
py2.py
"""
import tkinter as tk
from py1 import text_area

for ii in range(100000):
    mystr = "Step " + str(ii) + "\n"
    text_area.insert(tk.END, mystr)
Tao Zeng
  • 39
  • 5
  • 1
    ```exec(open("py2.py").read())``` why? Simply ```open(...).read()``` will do –  Jul 28 '21 at 07:32
  • Hi, Sujay, thanks again for your immediate response. If i change exec(open("py2.py").read()) to open(...).read(), the py2.py file does not execute. There would be nothing displayed in the scrolledtext. – Tao Zeng Jul 28 '21 at 07:36

1 Answers1

1

I think this would be a better approach because it would not require the second script to import the first to access its variables (which wouldn't work anyway). Instead have py1.py import the second script and call a function in it and pass the variable as an argument. Here's what I mean:

"""
py1.py
"""

import py2
import tkinter as tk
from tkinter import scrolledtext

win = tk.Tk()

text_area = scrolledtext.ScrolledText(win)
text_area.pack()

btn = tk.Button(text='Display Results', command=lambda: py2.add_results(text_area))
btn.pack()

win.mainloop()

Second script:

"""
py2.py
"""
import tkinter as tk

def add_results(text_area):
    for ii in range(100000):
        mystr = "Step " + str(ii) + "\n"
        text_area.insert(tk.END, mystr)
        text_area.see(tk.END)
        text_area.update_idletasks()  # Update display.

Update

To prevent the tight loop in the add_results() function from making your application freeze-up until the loop is finished, you need to make use of the universal after() widget method to schedule repeated calls to the function until is finished.

So here's a version of the function in the second script showing how to to that:

"""
py2.py - version 2.0
"""
import tkinter as tk

def add_results(text_area, ii=0):
    if ii < 100000:  # Not Done?
        mystr = f"Step {ii}\n"
        text_area.insert(tk.END, mystr)
        text_area.see(tk.END)
        text_area.update_idletasks()  # Update display.
        ii += 1
        # Call this func again in 100 ms (0.1 sec).
        text_area.after(100, add_results, text_area, ii)
martineau
  • 119,623
  • 25
  • 170
  • 301
  • Thanks very mush, really help for me. This problem has confused me several days. – Tao Zeng Jul 28 '21 at 08:43
  • Hello martineau, one annoying thing I found later is that when your code run, i cannot do anything on the main window, even if i try to move it, it crashes... – Tao Zeng Jul 29 '21 at 01:25
  • 1
    It's not crashing, it hanging or freezing. That's because the function in your second script is running a *very* tight loop which interferes with tkinter's own `mainloop()` that processes user input. The common way to avoid that by using the universal widget [`after()`](https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/universal.html) method to schedule periodic calls to a function (which again cannot take too long to execute). There are many question about the topic here on Stackoverflow. – martineau Jul 29 '21 at 01:33
  • Thanks for your suggestion, i will try after method. By the way, is the thread module better??? – Tao Zeng Jul 29 '21 at 01:47
  • 1
    No, not in this case because tkinter doesn't support threading in the sense that only one thread in a multithreaded application can use it. See the update to my answer showing how to use the `after()` method. There are also ways of using a queues to pass information between threads, which (also) uses the `after()` method only what it does in this scenario is periodically check the queue for new data and updates the GUI accordingly when some is received. – martineau Jul 29 '21 at 02:01
  • One problem is that if I add one additional statement time.sleep(10) to replace a long run time code there, the freeze problem still exists, do you have any idea to avoid that – Tao Zeng Aug 21 '21 at 00:40
  • I am not sure what you are trying to simulate, but trying to change my answer like that is not OK. **Of course** putting a call to a long `sleep` in the `add_results()` function will freeze the program because doing so prevents the `mainloop` from running and processing any GUI-related events including calling the function again in 100 ms. – martineau Aug 21 '21 at 01:05
  • In fact, the phrase time.sleep(10) is to imitate a long run code (computation with heavy iteration). Since my main code is long, so i just paste a small portion here. – Tao Zeng Aug 21 '21 at 02:23
  • Putting the sleep in `add_results()` does not simulate that, as the function needs to run as quickly as possible. If you have something else in your main code that's taking a long time, then that, too, will make the GUI freeze. You may be able to workaround the issue by executing the slow code in a separate thread, but how to do that with `tkinter` is another topic. See [Freezing/Hanging tkinter GUI in waiting for the thread to complete](https://stackoverflow.com/questions/53696888/freezing-hanging-tkinter-gui-in-waiting-for-the-thread-to-complete) for an example. – martineau Aug 21 '21 at 07:09