简体   繁体   中英

Python multiprocessing and tkinter - how to connect this process (GUI and spawned process)?

long time ago I started to use threading. Thread for any functions in my GUI. But last time I focused on multiprocessing module. The problem here is that when I spawn new process I don't know how to connect with my GUI. Here is sample code - one button "execute" Thread and it works as expected. Second button spawn Process but my GUI is not updated (input field is not filled with text). How to fix that? How to receive "print" statements from Process? Thanks!

import tkinter as tk
import time
from multiprocessing import Process, Pool
from threading import Thread


root = tk.Tk()
inputEn = tk.Entry(root)
inputEn.pack()


def runner(txt):
    print("runner")
    time.sleep(5)
    # this doesn't work when I use it with Process
    inputEn.insert(0, "{}".format(txt))
    print("runner end")


def process():
    p = Process(target=runner, args=("process",))
    p.start()


def thread():
    p = Thread(target=runner, args=("thread",))
    p.start()



btnStart = tk.Button(root, text="Start Process", command=process)
btnStart.pack()

btnStart2 = tk.Button(root, text="Start Thread", command=thread)
btnStart2.pack()



if __name__=="__main__":
    root.mainloop()

When spawned using process, the child process cannot update the variable of the parent process. You can experiment by modifying your code :

inputEn.pack()
globalv = 0

def runner(txt):
    global globalv
    print("runner")
    time.sleep(5)
    # this doesn't work when I use it with Process
    inputEn.insert(0, "{}".format(txt))
    globalv = globalv + 1
    print 'globalv : ', globalv

globalv will then be updated when runner is called via thread, by not updated when runner is called via process. You would have to use queue to make child interact with your application.

This is because a child process is instanciated using a copy of the context of the parent process - whereas a thread uses the same context as the parent.

You have not said why multiprocessing is necessary here. If you just want to update a variable, tkinter's after() works well for that. A not so elegant example

import Tkinter as tk
import random

class UpdateLabel(object):
    def __init__(self, master):
        self.master=master
        self.str_var=tk.StringVar()
        self.str_var.set("start")
        tk.Entry(root, textvariable=self.str_var, width=50).pack()

        tk.Button(self.master, text="Exit", bg="orange",
                  command=self.master.quit).pack()

        self.ctr=0
        self.change_it()

    def change_it(self):
        """ use random to simulate getting some kind of data 10 times
        """
        this_lit=self.str_var.get()
        next_lit=random.choice(range(100))
        self.str_var.set(this_lit+", "+str(next_lit))
        self.ctr += 1
        if self.ctr < 10:
            self.master.after(500, self.change_it)

root = tk.Tk()
UL=UpdateLabel(root)
root.mainloop()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM