Posts: 6
Threads: 2
Joined: Aug 2022
Hi!
I'm having trouble updating a label depending on a result from a function from one of the two processes I'm running. I'm trying using Queues, but can't make it work.
This is a simplified example of the code:
import multiprocessing as mp
from tkinter import DISABLED, NORMAL, Label, LabelFrame, Tk
import queue
class Gui(object):
def __init__(self, q):
self.root = Tk()
self.root.geometry('150x100')
self.frameP1 = LabelFrame(self.root, text="Process1", font=("Helvetica", 14, "bold"), bd=0)
self.frameP1.pack(padx=12)
self.currentUserProcess1 = Label(self.frameP1, text="Current User p1", font=("Helvetica", 10, "bold"))
self.currentUserProcess1.pack()
self.frameP2 = LabelFrame(self.root, text="Process2", font=("Helvetica", 14, "bold"), bd=0)
self.frameP2.pack()
self.currentUserProcess2 = Label(self.frameP2, text="Current User p2", font=("Helvetica", 10, "bold"))
self.currentUserProcess2.pack()
self.root.after(100,self.CheckQueuePoll,q)
def CheckQueuePoll(self, c_queue):
try:
str = c_queue(0)
self.currentUserProcess2.configure(text=str)
except queue.Empty:
pass
finally:
self.root.after(100, self.CheckQueuePoll, q)
def process1():
print("Executing process1")
#doSomething
def process2():
print("Executing process2")
log = "Current User Process 2"
q.put(log)
def startProcesses():
global p1
global p2
p1 = mp.Process(target = process1)
p2 = mp.Process(target = process2)
p1.start()
p2.start()
def stopProcesses():
p1.terminate()
p2.terminate()
if __name__ == '__main__':
q = mp.Queue()
gui = Gui(q)
p1 = mp.Process(target = process1, args=(q,))
p2 = mp.Process(target = process2, args=(q,))
p1.start()
p2.start()
gui.root.mainloop() This is giving me this error:
Error: TypeError: 'Queue' object is not callable
This happens when trying to execute "str = c_queue(0)" on CheckQueuePoll function.
I tried different ways of importing Queue, but I always get errors. I'd appreciate any help or hint in what I'm doing wrong.
Thanks in advance!
Posts: 4,783
Threads: 76
Joined: Jan 2018
Aug-12-2022, 02:37 PM
(This post was last modified: Aug-12-2022, 02:38 PM by Gribouillis.)
The object c_queue is not callable. Try this perhaps
def CheckQueuePoll(self, c_queue):
try:
str = c_queue.get_nowait()
c_queue.task_done()
self.currentUserProcess2.configure(text=str)
except queue.Empty:
pass
finally:
self.root.after(100, self.CheckQueuePoll, q)
Posts: 536
Threads: 0
Joined: Feb 2018
Pass gui.currentUserProcess 1 or 2 to the process as an arg. Each process can then update it.
Posts: 6
Threads: 2
Joined: Aug 2022
(Aug-12-2022, 02:37 PM)Gribouillis Wrote: The object c_queue is not callable. Try this perhaps
def CheckQueuePoll(self, c_queue):
try:
str = c_queue.get_nowait()
c_queue.task_done()
self.currentUserProcess2.configure(text=str)
except queue.Empty:
pass
finally:
self.root.after(100, self.CheckQueuePoll, q)
I tried it but now it gives me this errors:
Error: TypeError: process1() takes 0 positional arguments but 1 was given
Error: TypeError: process2() takes 0 positional arguments but 1 was given
So I tried passing the "q" as an argument to process1() and process2() and now I have this error:
Error: AttributeError: 'Queue' object has no attribute 'task_done'
There is maybe a problem with the import? I tried importing queue in different ways though.
Posts: 6
Threads: 2
Joined: Aug 2022
(Aug-12-2022, 07:04 PM)woooee Wrote: Pass gui.currentUserProcess 1 or 2 to the process as an arg. Each process can then update it.
I tried it. This is the code I got, in case I did something wrong:
class Gui(object):
def __init__(self, q):
self.root = Tk()
self.root.geometry('150x100')
self.frameP1 = LabelFrame(self.root, text="Process1", font=("Helvetica", 14, "bold"), bd=0)
self.frameP1.pack(padx=12)
self.currentUserProcess1 = Label(self.frameP1, text="Current User p1", font=("Helvetica", 10, "bold"))
self.currentUserProcess1.pack()
self.frameP2 = LabelFrame(self.root, text="Process2", font=("Helvetica", 14, "bold"), bd=0)
self.frameP2.pack()
self.currentUserProcess2 = Label(self.frameP2, text="Current User p2", font=("Helvetica", 10, "bold"))
self.currentUserProcess2.pack()
def process1():
print("Executing process1")
#doSomething
def process2(currentUserProcess2):
print("Executing process2")
log = "Current user process 2"
currentUserProcess2.configure(text=log)
def startProcesses():
global p1
global p2
p1 = mp.Process(target = process1, args=(gui.currentUserProcess2,))
p2 = mp.Process(target = process2, args=(gui.currentUserProcess2,))
p1.start()
p2.start()
def stopProcesses():
p1.terminate()
p2.terminate()
if __name__ == '__main__':
q = mp.Queue()
gui = Gui(q)
p1 = mp.Process(target = process1, args=(gui.currentUserProcess2,))
p2 = mp.Process(target = process2, args=(gui.currentUserProcess2,))
p1.start()
p2.start()
gui.root.mainloop() I got this:
Error: Traceback (most recent call last):
File "c:\Users\User1\Desktop\MultiTkinter\main.py", line 63, in <module>
p1.start()
File "C:\Users\User1\AppData\Local\Programs\Python\Python310\lib\multiprocessing\process.py", line 121, in start
self._popen = self._Popen(self)
File "C:\Users\User1\AppData\Local\Programs\Python\Python310\lib\multiprocessing\context.py", line 224, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
File "C:\Users\User1\AppData\Local\Programs\Python\Python310\lib\multiprocessing\context.py", line 327, in _Popen
return Popen(process_obj)
File "C:\Users\User1\AppData\Local\Programs\Python\Python310\lib\multiprocessing\popen_spawn_win32.py", line 93, in __init__
reduction.dump(process_obj, to_child)
File "C:\Users\User1\AppData\Local\Programs\Python\Python310\lib\multiprocessing\reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
TypeError: cannot pickle '_tkinter.tkapp' object
PS C:\Users\User1\Desktop\MultiTkinter> Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:\Users\User1\AppData\Local\Programs\Python\Python310\lib\multiprocessing\spawn.py", line 107, in spawn_main
new_handle = reduction.duplicate(pipe_handle,
File "C:\Users\User1\AppData\Local\Programs\Python\Python310\lib\multiprocessing\reduction.py", line 79, in duplicate
return _winapi.DuplicateHandle(
PermissionError: [WinError 5] Access is denied
I deleted CheckQueuePoll function as I understand it wouldn't be needed if I'm passing "gui.CurrenUserProcess2" in the parameters.
Posts: 536
Threads: 0
Joined: Feb 2018
Aug-12-2022, 10:00 PM
(This post was last modified: Aug-12-2022, 10:01 PM by woooee.)
I see at least 2 problems self.currentUserProcess1 = Label(self.frameP1, text="Current User p1", font=("Helvetica", 10, "bold"))
self.currentUserProcess2 = Label(self.frameP2, text="Current User p2", font=("Helvetica", 10, "bold"))
p1 = mp.Process(target = process1, args=(gui.currentUserProcess2,))
p2 = mp.Process(target = process2, args=(gui.currentUserProcess2,))
===
def process1():
Posts: 1,144
Threads: 114
Joined: Sep 2019
Aug-15-2022, 07:10 PM
(This post was last modified: Aug-15-2022, 07:10 PM by menator01.
Edit Reason: updated code
)
Are you trying to do something like this?
import multiprocessing as mp
import random as rnd
import tkinter as tk
'''
Function for updating labels
Creates the que
Add to the que
Set label text for que
Call root.after for continuous call
'''
def get_num(root, label):
myque = mp.Queue()
myque.put(rnd.randint(1, 100))
label['text'] = f'Process {myque.get()} running...'
root.after(1000, lambda: get_num(root, label))
'''
Tkinter window
'''
root = tk.Tk()
root.title('Running Processes')
root.columnconfigure(0, weight=1)
root.geometry('+300+300')
'''
Two list, one to hold labelframes and one to hold labels
'''
labels = []
labelframes = []
'''
Set variable j to for labelframe numbers
'''
j = 1
'''
Using for loop to add 10 labels
using j to number labelframes
create and append labelframes to the labelframes list
'''
for i in range(10):
j = j if i % 2 == 0 else(j if i % 3 == 0 else j+1)
labelframes.append(tk.LabelFrame(root, text=f'Processes for frame {j}'))
labelframes[i].grid(column=0, row=i, sticky='new', pady=5, padx=5)
'''
parent is used to place labels in the labelframes. Using i % n in this example
'''
parent = labelframes[0] if i % 2 == 0 else(labelframes[1] if i % 3 == 0 else labelframes[i])
'''
Create and append labels to the labels list
Using parent to color background of grouped labels in labelframe
'''
labels.append(tk.Label(parent, anchor='w', padx=5, width=50))
labels[i]['bg'] = 'sandybrown' if parent == labelframes[0] \
else('tan' if parent == labelframes[1] else 'ivory2')
labels[i]['relief'] = 'ridge'
labels[i].grid(column=0, row=i, sticky='new', pady=5, padx=5)
'''
Create and start the process
'''
process = mp.Process(target=get_num, args=(root, labels[i],))
process.start()
process.join()
'''
Use root.after to call the get_num function
'''
root.after(1, get_num, root, labels[i])
root.mainloop()
|