2

I'm trying to write a Python GUI program with tkinter.

I want to make two thread. One runing with the main_form function to keep tkinter from keep update and loop (avoid "Not Responding").

The other, when the button1 (btn1) is clicked make function sci_thread() start running and start thread2 that execute the main_scikit with long time code.

But tkinter keep Not Responding.

Below is my code:

import threading

class class_one:
    def main_scikit(seft):
        ######
        code_take_loooong_time
        ######
    def save(seft):
        pass

    def main_form(seft):
        root = Tk(  )
        root.minsize(width=300, height=500)
        ent1 = Entry(width=30)
        ent1.grid(row=0,column=1,padx = 10,pady=5)
        bnt1 = Button(root,text = "Start",command=lambda : seft.sci_thread())
        bnt1.grid(row=5,column=0,padx = 10) 

        root.update() 
        root.mainloop()

    def sci_thread(seft):
        maincal = threading.Thread(2,seft.main_scikit())
        maincal.start()

co = class_one()
mainfz = threading.Thread(1,co.main_form());
mainfz.start() 
Cœur
  • 37,241
  • 25
  • 195
  • 267
erosennin113
  • 21
  • 1
  • 3
  • @erosennin113, please, make your code runnable for peeps, you can't declare threads like that, but try `mainfz = threading.Thread(target=co.main_form)` instead. I don't know what's your `code_take_loooong_time` really is, but with proper thread's declaration and with some time loops in `main_scikit` it works just fine - GUI is responsible and I can create as many threads as I want with it. So spend some time on your code, make it complete and confirm that problem not there anymore, deal? – CommonSense Apr 14 '17 at 07:59
  • Thank you @CommonSense Sorry i can't post the code here , I'm working on scikit-learn and in the `code_take_loooong_time` is some data analysis function take about 500-2000s . and during that time i have some print function to report in a text field on the GUI . But the UI is not responding as the time `code_take_loooong_time` take . At the end, everything is ok print function excute . – erosennin113 Apr 14 '17 at 08:26
  • did you read my advice about declaring threads properly? First of all you need only one parameter `target` and target must be a *callable*. In other words, your scikit-learn 's routine gets called and executed before thread's start. Same as cause why you're using lambda when declare your button - just to prevent execution of that function. – CommonSense Apr 14 '17 at 09:18
  • Ty @CommonSense but , I can't make is work :(( , i declared just like you say . The other part , how i can prevent the scikit won't executed before thread's start . – erosennin113 Apr 16 '17 at 13:15

1 Answers1

1

Your app is unresponsive because your target parameter executed when declared and result of that passed as target. And, obviously, because of that you GUI is unresponsive while code_take_loooong_time being executed in GUI's thread. To deal with it - get rid of redundant parentheses.

Try this snippet:

import threading

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk


class class_one:
    def main_scikit(self):
        ######
        # code_take_loooong_time
        # same as sleep
        threading.Event().wait(5)
        # some print
        self.print_active_threads_count()

        ######
    def save(self):
        pass

    def main_form(self):

        self.root = tk.Tk()
        self.root.minsize(width=300, height=500)
        self.ent1 = tk.Entry(self.root, width=30)
        self.ent1.grid(row=0, column=1, padx=10, pady=5)
        self.bnt1 = tk.Button(self.root, text="Start", command=self.sci_thread)
        self.bnt1.grid(row=5, column=0, padx=10)

        self.root.update()
        self.root.mainloop()

    def sci_thread(self):
        maincal = threading.Thread(target=self.main_scikit)
        maincal.start()

    def print_active_threads_count(self):
        msg = 'Active threads: %d ' % threading.active_count()

        self.ent1.delete(0, 'end')
        self.ent1.insert(0, msg)
        print(msg)


co = class_one()
mainfz = threading.Thread(target=co.main_form)
mainfz.start() 

Links:

P.S.: Also, be careful when you start a tkinter application not in the main thread because tkinter expects (in general) that mainloop is outer-most loop possible and that all Tcl commands invoked from the same thread. So there can be many and more synchronisation problem with all that, even if you just trying to quit GUI! In conclusion, maybe this and that would give you some new ideas.

Community
  • 1
  • 1
CommonSense
  • 4,232
  • 2
  • 14
  • 38