2

I have this following code where I am calling the function from the button which takes input from the widgets. It's a function which takes about 4 minutes to run and for solving the 'not responding' problem of tkinter window, I want to get the func process running on the different core and terminate as it can be called again via the application running on mainloop with a different argument. I read the documentation of multiprocessing and Pool seemed to be the choice here but I don't know how to frame it here. Tried a few things with error.

class database(tk.Tk):
    def __init__(self, *args, *kwargs):
        tk.Tk.__init__(self, *args, **kwargs):
        container= tk.Frame(self, width=1000, height=1000)
        container.pack(side="top", fill="both", expand= True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        self.frames = {}
        for F in ( msPage):      #many more pages here
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame(msPage)

    def show_frame(self,cont):
        frame = self,frames[cont]
        frame.tkraise()

def MarkS(msVar):
    ms.func(msVar.get())       # func takes about 4 mins

class msPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        msVar = StringVar()
        msCal = Calendar(self, selectmode='day'
textvariable=msVar).pack(fill="both", expand=True)
        # button2 calls MarkS
        button2 = ttk.Button(self,
                             text="Get Data",
                             command=lambda: MarkS(msVar)).pack(pady=30, padx=10)                


app = database()
app.geometry("1066x568")
app.minsize(width=670, height=550)
app.mainloop()
sagar_acharya
  • 346
  • 4
  • 18
  • Judging by your code you have imported tkinter twice. Once as `tk` and once with `*`. You should only do one or the other and I recommend using `import tkinter as tk` to help prevent any chance of overriding other methods. There are also several typos that would prevent your code form working at all. – Mike - SMT Jul 26 '18 at 18:02
  • Are you asking us how to write the multiprocessing code for you? – Bryan Oakley Jul 26 '18 at 18:07
  • I thought that since I'm not mentioning the very long function, I'll just give the basic structure of code which you can help me. Yes, I want a basic sample of how can I implement. Or atleast hint me how can I start? PS. Yes Mike, I've done that. I'll correct it. – sagar_acharya Jul 26 '18 at 18:15
  • If you are just looking for an example of how to multithread then I would take a look at this Stack Overflow post: [Tkinter: How to use threads to preventing main event loop from “freezing”](https://stackoverflow.com/questions/16745507/tkinter-how-to-use-threads-to-preventing-main-event-loop-from-freezing) – Mike - SMT Jul 26 '18 at 18:24

2 Answers2

1

This is a standalone example that might help you get started:

from multiprocessing import Process

class ms_var_class():
    value = None
    def __init__(self, value):
        self.value = value
    def get(self):
        return self.value

# This is to simulate type(ms)
class ms_class():
    process = None
    # This is for simulating your long running function
    def func(self, ms_var):
        print(ms_var)

def MarkS(msVar):
    ms.process = Process(target=ms.func, args=(msVar.get(),))
    ms.process.start()
    # Call ms.process.join() later

ms_var = ms_var_class("bogus")
ms = ms_class()
MarkS(ms_var)
if ms.process is not None:
    ms.process.join()
1

Thank you Mike for commenting and helping me get towards the solution

Here's how I did it

Create a global queue

q= queue.Queue()

Defined the function MarkS within the class msPage

def MarkS(msVar):
        q.put([7 , datetime.datetime.strptime(msVar.get(), '%x').strftime('%d-%b-%Y').upper(),0])
        ThreadedTask(q).start()

7 is the unique number of the 9 functions that I had for each page (class) Made another class of ThreadedTask as in the link below Tkinter: How to use threads to preventing main event loop from "freezing"

class ThreadedTask(threading.Thread):
    def __init__(self,queue):
        threading.Thread.__init__(self)
        q = queue
    def run(self):
        items = q.get()
        if items[0]==7:
            ms.func(items[1])

ThreadedTask(q).start() creates a constructor object and the run function automatically starts depending on the argument here which is of course the 1st element of q which is a list of 3 in my case. It is detected and the desired function is run in another thread which prevents the tkinter window from closing.

Hope this helps! :)

sagar_acharya
  • 346
  • 4
  • 18