Python Forum
[Tkinter] Defining a self made module's function to interact with the main .py variables?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Defining a self made module's function to interact with the main .py variables?
#1
Question 
I'm using Tkinter. (self learner)
My goal is to display the function's output in the main .py text widget.
How can I make the function send the output to the text box in the main .py file?

** UPDATE 2 **
[Image: GaLRq.jpg]
[Image: KBjss.jpg]

** UPDATE **
i've updated the code and now I get that:

[Image: mwsrw.jpg]
[Image: ghjkb.jpg]

[Image: 2Sxck.jpg]

Main .py:

import tkinter as tk
import multiprocessing as mp
import os
import testping
import sys


class GUI(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.geometry("860x600")
        self.title("GUI Project")

        menu = tk.Frame(self, relief="solid")
        container = tk.Frame(self, relief="solid")

        menu.pack(side="left", fill="y")
        container.pack(side="right", fill="y", expand=True)

        menu.grid_rowconfigure(0, weight=1)
        container.grid_rowconfigure(0, weight=1)
        container.grid_rowconfigure(1, weight=1)
        container.grid_rowconfigure(2, weight=1)
        container.grid_rowconfigure(3, weight=1)
        container.grid_rowconfigure(4, weight=1)
        container.grid_rowconfigure(5, weight=1)
        container.grid_rowconfigure(6, weight=1)
        container.grid_columnconfigure(0, weight=1)
        container.grid_columnconfigure(1, weight=2)
        container.grid_columnconfigure(2, weight=2)
        container.grid_columnconfigure(3, weight=2)
        container.grid_columnconfigure(4, weight=2)
        container.grid_columnconfigure(5, weight=2)
        container.grid_columnconfigure(6, weight=2)

        self.frames = ["Menu", "TestPing", "FutureFeature", "FutureFeature2", "FutureFeature3"]

        self.frames[0] = Menu(parent=menu, controller=self)
        self.frames[1] = TestPing(parent=container, controller=self)
        self.frames[2] = FutureFeature(parent=container, controller=self)
        self.frames[3] = FutureFeature2(parent=container, controller=self)
        self.frames[4] = FutureFeature3(parent=container, controller=self)

        self.frames[0].grid(row=0, column=0, sticky="nsew")
        self.frames[1].grid(row=0, column=0, sticky="nsew")
        self.frames[2].grid(row=0, column=0, sticky="nsew")
        self.frames[3].grid(row=0, column=0, sticky="nsew")
        self.frames[4].grid(row=0, column=0, sticky="nsew")

        self.show_frame(1)

    def show_frame(self, page_name):
        frame = self.frames[page_name]
        print(frame)
        frame.tkraise()
        frame.grid(row=0, column=0, sticky="nsew")


class Menu(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        ping_test_button = tk.Button(self, text="Ping Test", bg="skyblue1", pady=30,
                                     command=lambda: controller.show_frame(1))
        future_feature1_button = tk.Button(self, text="FutureFeature", bg="dark violet", pady=30,
                                           command=lambda: controller.show_frame(2))
        future_feature2_button = tk.Button(self, text="FutureFeature2", bg="pale goldenrod", pady=30,
                                           command=lambda: controller.show_frame(3))
        future_feature3_button = tk.Button(self, text="FutureFeature3", bg="green", pady=30,
                                           command=lambda: controller.show_frame(4))
        app_exit = tk.Button(self, text="Quit", bg="gray40", pady=30,
                             command=lambda: self.terminate())

        ping_test_button.pack(fill="both", expand=True)
        future_feature1_button.pack(fill="both", expand=True)
        future_feature2_button.pack(fill="both", expand=True)
        future_feature3_button.pack(fill="both", expand=True)
        app_exit.pack(fill="both", expand=True)

    def terminate(self):

        while True:
            path = fr'c:/users/{os.getlogin()}/desktop/Gui-Skeleton'

            try:
                os.rmdir(path)
                exit()
            except OSError as err:
                print(f"Error Deleting tmp folder! {err}")
                exit()


class TestPing(tk.Frame):

    def __init__(self, parent, controller):

        tk.Frame.__init__(self, parent, bg="skyblue1")
        self.controller = controller


        self.clear_file = tk.BooleanVar()
        self.clear_file.set(False)

        self.url_label = tk.Label(self, text="Enter URL : ", padx=7, pady=5, bg="skyblue1")
        self.url_input_box = tk.Entry(self)

        self.file_name_label = tk.Label(self, text="Enter Filename: ", bg="skyblue1")
        self.file_name_input_box = tk.Entry(self)

        self.clear_file_label = tk.Label(self, text="Clear File?", padx=5, pady=5, bg="skyblue1")

        self.clear_file_radio_yes = tk.Radiobutton(self, text="yes", value=True, var=self.clear_file, bg="skyblue1",
                                                   command=lambda: self.callback(self.clear_file.get()))
        self.clear_file_radio_no = tk.Radiobutton(self, text="no", value=False, var=self.clear_file, bg="skyblue1",
                                                  command=lambda: self.callback(self.clear_file.get()))
        self.submit_button = tk.Button(self, text="Submit", width=10, height=1,
                                       command=lambda: self.condition(self.url_input_box.get(),
                                                                      self.clear_file.get(),
                                                                      self.file_name_input_box.get()))
        self.clear_fields_button = tk.Button(self, text="Clear Fields", width=10,
                                             command=lambda: self.clear_boxes(self.url_input_box,
                                                                              self.file_name_input_box))

        self.text_input = tk.StringVar()
        self.text_window = tk.Text(self, height=100, width=500, bg="gray")
        self.clear_window_button = tk.Button(self, text="Clear Window", width=10,
                                             command=lambda: self.clean_window())

        self.grid_columnconfigure(0, minsize=50, weight=0)
        self.grid_columnconfigure(1, minsize=20, weight=2)
        self.grid_columnconfigure(2, minsize=50, weight=3)
        self.grid_columnconfigure(3, minsize=20, weight=2)
        self.grid_rowconfigure(0, minsize=50, weight=0)
        self.grid_rowconfigure(1, minsize=20, weight=0)
        self.grid_rowconfigure(2, minsize=30, weight=0)
        self.grid_rowconfigure(3, minsize=10, weight=0)
        self.grid_rowconfigure(4, minsize=10, weight=0)
        self.grid_rowconfigure(5, minsize=10, weight=0)

        self.url_label.grid(row=0, column=0, sticky="w")
        self.url_input_box.grid(row=0, column=1, sticky="w")
        self.file_name_label.grid(row=1, column=0, sticky="w")
        self.file_name_input_box.grid(row=1, column=1, sticky="w")
        self.clear_file_label.grid(row=0, column=1, sticky="n")
        self.clear_file_radio_yes.grid(row=1, column=1)
        self.clear_file_radio_no.grid(row=2, column=1)
        self.submit_button.grid(row=3, column=1, sticky="se")
        self.clear_fields_button.grid(row=3, column=1, sticky="sw")
        self.text_window.grid(row=7, column=1, rowspan=3, sticky="we")
        self.clear_window_button.grid(row=8, column=0)

    def clear_boxes(self, url_input, filename):
        url_input.delete(0, "end")
        filename.delete(0, "end")

    def callback(self, clear):
        print(f'Clear file = {clear}')  # Debugging Mode - check Radio box Var.

    def condition(self, host, clear, filename):

        print(clear, filename)  # Debugging - Input Validation

        if clear is True and filename == '':
            self.handler_clr_yes_fn_no(host)
        elif clear is False and filename == '':
            self.handler_clr_no_fn_no(host)
        elif clear is True and filename != '':
            self.handler_clr_yes_fn_yes(host, filenameInputBox)
        elif clear is False and filename != '':
            self.handler_clr_no_fn_yes(host, filenameInputBox)

    def handler_clr_yes_fn_no(self, host):

        startprocs = []
        lastprocs = []

        proc1 = mp.Process(name="Clear + No Filename + WriteFile",
                           target=testping.clr_yes_fn_no_writefile, args=(host,))
        proc2 = mp.Process(name="Clear + No Filename + PrintOutput",
                           target=testping.clr_yes_fn_no_print_output, args=(host,))
        proc3 = mp.Process(name="Clear + No Filename + Generate PrintOutput to GUI",
                           target=testping.clr_yes_fn_no_print_to_gui, args=(host,))
        proc4 = mp.Process(name="Remove first line + Write new default file",
                           target=testping.delete_default_lines)

        startprocs.append(proc1)
        startprocs.append(proc2)
        startprocs.append(proc3)

        lastprocs.append(proc4)

        for s in startprocs:
            s.start()

        for s2 in startprocs:
            s2.join()

        for l in lastprocs:
            l.start()

    def handler_clr_no_fn_no(self, host):

        procs = []
        nextprocs = []

        proc1 = mp.Process(name="Append to default file",
                           target=testping.clr_no_fn_no_writefile, args=(host,))
        proc2 = mp.Process(name="Print Output", target=testping.clr_no_fn_no_printoutput, args=(host,))

        procs.append(proc1)
        procs.append(proc2)

        for proc in procs:
            proc.start()
        for proc in procs:
            proc.join()

        for p in nextprocs:
            p.start()

    def handler_clr_yes_fn_yes(self, host, filenameInputBox):

        procs = []
        nextprocs = []

        proc1 = mp.Process(name="Clear file + userFilename + Write to file",
                           target=testping.clr_yes_fn_yes_writefile, args=(host, filenameInputBox,))
        proc2 = mp.Process(name="Clear file + user filename + Print output",
                           target=testping.clr_yes_fn_yes_printoutput, args=(host,))
        proc3 = mp.Process(name="Remove Empty Lines from user filename",
                           target=testping.delete_userfile_lines, args=(filenameInputBox,))

        procs.append(proc1)
        procs.append(proc2)
        nextprocs.append(proc3)

        for proc in procs:
            proc.start()

        for p in procs:
            p.join()

        for np in nextprocs:
            np.start()

    def handler_clr_no_fn_yes(self, host, filenameInputBox):

        procs = []

        proc1 = mp.Process(name="Keep File + Userfilename + Append to Userfile",
                           target=testping.clr_no_fn_yes_writefile, args=(host, filenameInputBox,))
        proc2 = mp.Process(name="Keep File + Userfilename + Print Output",
                           target=testping.clr_no_fn_yes_printoutput, args=(host,))

        procs.append(proc1)
        procs.append(proc2)

        for p in procs:
            p.start()

        for p2 in procs:
            p2.join()


class FutureFeature(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent, bg="mediumpurple1")
        self.controller = controller  # can be used to run self.controller.show_frame[]


class FutureFeature2(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent, bg="light goldenrod")
        self.controller = controller


class FutureFeature3(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent, bg="green")
        self.controller = controller


def check_path():
    path = fr'c:/users/{os.getlogin()}/desktop/Gui-Skeleton'

    try:

        if os.path.isdir(path):
            pass

        else:
            os.mkdir(path)
            pass

    except OSError as err:
        print(f"[!] Operation failed! {err}")


if __name__ == "__main__":

    check_path()
    app = GUI()
    app.mainloop()
Module testping.py:

import subprocess as sub
import multiprocessing as mp
import time
import os
import sys
import tkinter as tk

clear_file = False
host = ""
filename = ""
text_box = tk.StringVar()
old_sys = sys.stdout


def delete_default_lines():
    time.sleep(1.5)
    print(f'\nCurrent Proccess: {mp.current_process().name} + {mp.current_process().pid}')
    file = fr'c:/users/{os.getlogin()}/Desktop/Gui-Skeleton/default-tmp.txt'
    newfile = fr'c:/users/{os.getlogin()}/Desktop/default.txt'

    with open(file, 'r') as inp, open(newfile, 'w+') as out:
        for line in inp:
            if not line.isspace():
                out.write(line.lstrip())
                out.write('')
        inp.close()
        out.close()
    os.remove(file)


def delete_userfile_lines(filename):
    time.sleep(1.5)
    print(f'Current Proccess: {mp.current_process().name} + {mp.current_process().pid}')
    file = fr'c:/users/{os.getlogin()}/Desktop/Gui-Skeleton/{filename}-tmp.txt'
    newfile = fr'c:/users/{os.getlogin()}/Desktop/{filename}.txt'

    with open(file, 'r+') as inp, open(newfile, 'w+') as out:
        for line in inp:
            if not line.isspace():
                out.write(line.lstrip())
                out.write('')
        inp.close()
        out.close()
    os.remove(file)


def clr_yes_fn_no_print_output(host):
    print(f'Current Proccess: {mp.current_process().name} + {mp.current_process().pid}\n')
    with sub.Popen(["ping", "-n", "4", f'{host}'], stdout=sub.PIPE,
                   bufsize=1, universal_newlines=True, stderr=sub.STDOUT) as p:
        for line in p.stdout:
            print(line, end=' ')


def clr_yes_fn_no_print_to_gui(host):
    print(f'Current Proccess: {mp.current_process().name} + {mp.current_process().pid}\n')

    cmd = ["ping", "-n", "4", f'{host}']
    proc = sub.Popen(cmd, stdout=sub.PIPE, shell=True, stderr=sub.STDOUT)
    for stdout_line in proc.stdout:
        print(stdout_line.decode(), end='')
        # yield stdout_line
    proc.stdout.close()
    # return_code = proc.wait()
    # if return_code:
    #     raise sub.CalledProcessError(return_code, cmd)


def clr_yes_fn_no_writefile(host):
    print(f'Current Proccess: {mp.current_process().name} + {mp.current_process().pid}\n')
    file = fr'c:/users/{os.getlogin()}/Desktop/Gui-Skeleton/default-tmp.txt'
    ping = sub.Popen(["ping", "-n", '4', f'{host}'], stdout=sub.PIPE)
    with open(file, 'w+') as output:
        data = output.read()
        for line in ping.stdout.readlines():
            data += str(line.decode())
        ping.stdout.close()
        output.seek(0)
        output.write(data.lstrip())


def clr_no_fn_no_printoutput(host):
    print(f'Current Proccess: {mp.current_process().name} + {mp.current_process().pid}\n')
    with sub.Popen(["ping", "-n", '4', f'{host}'], stdout=sub.PIPE,
                   bufsize=1, universal_newlines=True, stderr=sub.STDOUT) as p:
        for line in p.stdout:
            print(line, end=' ')


def clr_no_fn_no_writefile(host):
    print(f'Current Proccess: {mp.current_process().name} + {mp.current_process().pid}\n')
    with open(fr'c:/users/{os.getlogin()}/Desktop/default.txt', 'a') as output:
        sub.call(["ping", "-n", '4', f'{host}'], stdout=output)


def clr_yes_fn_yes_printoutput(host):
    with sub.Popen(["ping", "-n", '4', f'{host}'], stdout=sub.PIPE,
                   bufsize=1, universal_newlines=True, stderr=sub.STDOUT) as p:
        for line in p.stdout:
            print(line, end=' ')


def clr_yes_fn_yes_writefile(host, filename):
    file = fr'c:/users/{os.getlogin()}/Desktop/Gui-Skeleton/{filename}-tmp.txt'
    with open(file, 'w') as output:
        sub.call(["ping", "-n", '4', f'{host}'], stdout=output)


def clr_no_fn_yes_printoutput(host):
    with sub.Popen(["ping", "-n", '4', f'{host}'], stdout=sub.PIPE,
                   bufsize=1, universal_newlines=True, stderr=sub.STDOUT) as p:
        for line in p.stdout:
            print(line, end=' ')


def clr_no_fn_yes_writefile(host, filename):
    with open(fr'c:/users/{os.getlogin()}/Desktop/{filename}.txt', 'a') as output:
        sub.call(["ping", "-n", '4', f'{host}'], stdout=output)
GUI:

[Image: Hv15d.jpg]
Reply
#2
You can add a file handle argument to clr_yes_fn_no_print_output()
def clr_fn_no_print_output(host, file=sys.stdout):
    ...
    for line in p.stdout:
        print(line, end=' ', file=file)
Then in the code that calls this function you give a StringIO instance as file argument
import io

ofh = io.StringIO()
clr_fn_no_print_output(host, file=ofh)
self.text_window.insert(tk.END, ofh.getvalue())
It's an example of dependency injection. As far as I know, functions that do input output operations are good candidates for dependency injection.

The drawback of this code is that the GUI will freeze during the call to clr_fn_no_print_outut(). To avoid this, you can use the technique with the after() method as I said in your other thread about this subject.
Reply
#3
Thanks for your time!
before I make changes and flow with them and finally nothing will work (i mean nothing!), :)
can u please elaborate on the file=file definition?
i'll google the rest :)
Reply
#4
Gilush Wrote:before I make changes and flow with them and finally nothing will work
That's a reason why version control systems exist. I hope you're already using one such as git, to keep tracks of previous versions of your code and potentially restore them.

Gilush Wrote:can u please elaborate on the file=file definition?
It is only the default argument syntax in functions signatures in python
>>> spam = "Hello"
>>> 
>>> def func(x=spam):
...     print(x)
... 
>>> func(x='eggs')
eggs
>>> func()
Hello
Reply
#5
Thanks for replying :)

Since my last reply i've added multiprocessing and threads so now i'm having some difficulties with your answer because I have a thread running
a process handler that runs the function.

main.py:

Text widget:

    def text_widget(self):

        self.text_window = tk.Text(self, height=100, width=500, bg="gray", wrap=tk.WORD)
        self.text_window.update()
        self.text_window.grid(row=7, column=1, rowspan=3, sticky="we")
        self.text_window.insert(tk.END, ">>>")
        self.thread_update_text_widget_default()

    def thread_update_text_widget_default(self):
        ud = threading.Thread(name="Updating Text Widget from file",
                              target=self.update_text_widget_default, args=())
        ud.daemon = False
        ud.start()

    def update_text_widget_default(self):
        
        print("Updating Text Widget from file")
        file = fr'c:/users/{os.getlogin()}/Desktop/Gui-Skeleton/default-tmp.txt'
        with open(file, 'r') as f:
            console_text = f.readline()
            for line in console_text:
                self.text_window.delete('1.0', tk.END)
                self.text_window.insert(tk.END, f'>>>{line}')
    def thread_handler_clr_yes_fn_no(self, host):
        yn = threading.Thread(target=self.proc_handler_clr_yes_fn_no, args=(host,))
        yn.daemon = False
        yn.start()
    def proc_handler_clr_yes_fn_no(self, host):

        startprocs = []
        lastprocs = []

        proc1 = mp.Process(name="Clear + No Filename + WriteFile",
                           target=testping.clr_yes_fn_no_writefile, args=(host,))
        proc1.daemon = True
        proc2 = mp.Process(name="Clear + No Filename + PrintOutput",
                           target=testping.clr_yes_fn_no_print_output, args=(host,))
        proc3 = mp.Process(name="Clear + No Filename + Generate PrintOutput to GUI",
                           target=testping.clr_yes_fn_no_print_to_gui, args=(host,))
        proc4 = mp.Process(name="Remove first line + Write new default file",
                           target=testping.delete_default_lines)

        startprocs.append(proc1)
        startprocs.append(proc2)
        startprocs.append(proc3)

        lastprocs.append(proc4)

        for s in startprocs:
            s.start()

        for s2 in startprocs:
            s2.join()

        for l in lastprocs:
            l.start()
this is on testping.py:

def clr_yes_fn_no_print_to_gui(host, file=sys.stdout):

    print(f'Current Proccess: {mp.current_process().name} + {mp.current_process().pid}\n')
    cmd = ["ping", "-n", "4", f'{host}']
    proc = sub.Popen(cmd, stdout=sub.PIPE, shell=True, stderr=sub.STDOUT)
    for stdout_line in proc.stdout:
        print(stdout_line.decode(), end='', file=file)
    proc.stdout.close()
    return_code = proc.wait()
    if return_code:
        raise sub.CalledProcessError(return_code, cmd)
as for GIT, i'm now using google drive and a local repo but i'll definetly pivot to GIT soon.
Reply
#6
You cannot use threads that easily to update a widget's contents in tkinter because the widgets must be updated from the thread that is running the mainloop().

I give you below a complete example of what I mean with the after() method. In this example, a "producer thread" is started that reads data in a file and puts this data in a queue at a random speed.

At the other end of the queue, there is a generator that extracts items from the queue in a non blocking way (so possiby no items at all) and updates the text widget with the data that it receives. This code is run by the main thread. I'm using a trick here: after trying to extract data from the queue, the function runs the "yield" statement, thus becoming a generator. The GUI will use my custom PeriodicConsumer class to drive this generator by intervals of 500 milliseconds. This is done with Tkinter's after() method.

It is a complete example, so you can run it and try to understand it.

import threading

class Error(RuntimeError):
    pass

class PeriodicConsumer:
    def __init__(self, widget):
        self.master =  widget
        self._job = None
        self._stopped = threading.Event()
        self._stopped.set()
        self._seq = None
        
        
    def start(self, sequence, millisecs):
        self.ms = millisecs
        if self._stopped.is_set():
            self._stopped.clear()
            self._seq = sequence
            self._job = self.master.after(self.ms, func=self._step)
        else:
            raise Error('Expected AfterThread in stopped state')

    def stop(self):
        if self._stopped.is_set():
            return
        self._stopped.set()
        if self._job and (
            threading.current_thread() is threading.main_thread()):
            self.master.after_cancel(self._job)
            self._job = None

    def _step(self):
        if self._stopped.is_set():
            return
        try:
            next(self._seq)
        except StopIteration:
            self.stop()
        else:
            self._job = self.master.after(self.ms, func=self._step)

if __name__ == '__main__':
    import io
    import queue
    import random
    import time
    import tkinter as tk
    root = tk.Tk()
    text = tk.Text(root)
    text.pack()
    pc = PeriodicConsumer(root)
    
    def update_text_from_queue(aqueue):
        while True:
            result = []
            try:
                while True:
                    x = aqueue.get_nowait()
                    if x is None:
                        # None in the queue is our signal for
                        # end of data.
                        if result:
                            text.insert(tk.END, "".join(result))
                        return
                    else:
                        result.append(x)
            except queue.Empty:
                pass
            if result:
                text.insert(tk.END, "".join(result))
            yield
    
    myqueue = queue.Queue()
    pc.start(update_text_from_queue(myqueue), 500)
    

    source_file = io.StringIO("""\
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Proin commodo turpis ex, commodo
pretium nunc tincidunt vel. Maecenas quis mi ac
ligula sagittis placerat ut ac justo.
Fusce nec sodales tortor. Duis hendrerit leo at odio faucibus.
""")
    
    def produce(aqueue):
        for line in source_file:
            aqueue.put(line)
            time.sleep(random.random())
        aqueue.put(None) # our convention for end of input
    
    producer = threading.Thread(target=produce, args=(myqueue,))
    producer.start()
    root.mainloop()
Reply
#7
Ok this is too complicated for my current level i'm afraid.
I compermised on just reading from the complete .txt file that contains the output
and display it in the text widget when its done but I got lost trying to refresh with the after() func.
what it does is actually freeze the textbox (and the program) for the amount of ms I set...

how can I make the text window read the file after every time I click submit?

    self.text_widget()

    def text_widget(self):

        self.text_file = open(fr'c:/users/{os.getlogin()}/Desktop/default.txt', 'w+').read()
        self.text_window = tk.Text(self, height=100, width=500, bg="gray", wrap=tk.WORD)
        self.text_window.update()
        self.text_window.grid(row=7, column=1, rowspan=3, sticky="we")
        self.text_window.insert(tk.END, self.read_file)
        self.text_window.after(5000, self.read_file)

    def read_file(self):
        self.text_file = open(fr'c:/users/{os.getlogin()}/Desktop/default.txt', 'w+').read()
        self.text_window.insert(tk.END, self.text_file)
Reply
#8
So i dropped that real time idea for now (too advanced or messy for my current level) and decided to sattle on updating
the textbox from file.

here's my solution:

These are the widget and the reader:

    def text_widget(self):

        self.text_window = tk.Text(self, height=100, width=500, bg="gray", wrap=tk.WORD)
        self.text_window.update()
        self.text_window.grid(row=7, column=1, rowspan=3, sticky="we")
        self.text_window.insert(tk.END, ">>")


    def read_file(self):

        time.sleep(4)
        with open(fr'c:/users/{os.getlogin()}/Desktop/default.txt', 'r', encoding='utf-8') as f:
            self.text_window.insert(tk.END, f.read())
            f.close()
and this is the handler:

 def proc_handler_clr_yes_fn_no(self, host):

        self.text_window.insert(tk.END, ">>Working...")

        startprocs = []
        nextprocs = []
        lastprocs = []

        proc1 = mp.Process(name="Clear + No Filename + WriteFile",
                           target=testping.clr_yes_fn_no_writefile, args=(host,))
        proc3 = mp.Process(name="Read from file to TextBox",
                           target=self.read_file)
        proc4 = mp.Process(name="Remove first line + Write new default file",
                           target=testping.delete_default_lines)

        startprocs.append(proc1)

        nextprocs.append(proc3)

        lastprocs.append(proc4)

        for s in startprocs:
            s.start()

        for s2 in startprocs:
            s2.join()

        t = threading.Thread(name="Display to TextBox", target=self.read_file)
        t.start()

        for l in lastprocs:
            l.start()
Reply
#9
I don't know how it works for you, but from my point of vue, it is not correct to launch a different thread which updates the text window as you are doing with the read_file method. Such things are not normally supported by tkinter. If you want to wait 4 seconds before reading the file, instead of using a thread, simply do
self.after(4000, self.read_file)
It won't freeze the GUI (but remove the time.sleep() from read_file)

Have you tried running the code I posted above?
Reply
#10
Man I must thank you!
you made me break my head with that listener thread and now I got it working!! (still shocked about it lol)
I gave up on trying to read the std and just merged the files into one and did some re-design.
now I got 3 threads running with 1 communicating with the widget.

here it is:

    def thread_handler(self, host):

        wt = threading.Thread(target=self.write_to_file, args=(host,))
        pt = threading.Thread(target=self.print_to_box, args=(host,))
        dt = threading.Thread(target=self.delete_default_lines, args=())

        wt.start()
        pt.start()
        dt.start()
also, I started the entire GUI with a thread and kept it alive:

if __name__ == "__main__":

    lock = threading.Lock()
    lock.acquire()
    t = threading.Thread(name="Main GUI", target=main, args=())
    t.start()
and this is the widget update:

    def print_to_box(self, host):
        print(f'Current Proccess: {mp.current_process().name} + {mp.current_process().pid}\n')
        with sub.Popen(["ping", "-n", '4', f'{host}'], stdout=sub.PIPE,
                       bufsize=1, universal_newlines=True, stderr=sub.STDOUT) as p:
            for line in p.stdout:
                self.text_window.insert(tk.END, line)
that did the entire trick.
Thanks again!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  How can I run an interface I made using PyQt5 and a Map program I made using Tkinter bki 6 1,046 Nov-09-2023, 11:12 PM
Last Post: bki
  [PyQt] Managing variables accross a multiple module GUI Oolongtea 18 10,650 Sep-19-2019, 12:13 PM
Last Post: Oolongtea
  “main thread is not in main loop” in Tkinter Long_r 1 24,084 Jun-26-2019, 11:00 PM
Last Post: metulburr
  [Tkinter] Bringing function out of class into main loop zukochew 1 2,652 Jul-30-2018, 06:43 PM
Last Post: Axel_Erfurt
  GTK main window calling a main window DennisT 4 6,689 Oct-19-2016, 09:36 PM
Last Post: DennisT

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020