I've got a program that will eventually receive data from an external source over serial, but I'm trying to develop the display-side first.
I've got this "main" module that has the simulated data send and receive. It updates a global that is used by a Matplotlib stripchart. All of this works.
#-------------------------------------------------------------------------------
# Name: BBQData
# Purpose: Gets the data from the Arduino, and runs the threads.
#-------------------------------------------------------------------------------
import time
import math
import random
from threading import Thread
import my_globals as bbq
import sys
import BBQStripChart as sc
import serial
import BBQControl as control
ser = serial.serial_for_url('loop://', timeout=10)
def simData():
newTime = time.time()
if not hasattr(simData, "lastUpdate"):
simData.lastUpdate = newTime # it doesn't exist yet, so initialize it
simData.firstTime = newTime # it doesn't exist yet, so initialize it
if newTime > simData.lastUpdate:
simData.lastUpdate = newTime
return (140 + 0.05*(simData.lastUpdate - simData.firstTime), \
145 + 0.022*(simData.lastUpdate - simData.firstTime), \
210 + random.randrange(-10, 10))
else:
return None
def serialDataPump():
testCtr = 0;
while not bbq.closing and testCtr<100:
newData = simData()
if newData != None:
reportStr = "D " + "".join(['{:3.0f} ' for x in newData]) + '\n'
reportStr = reportStr.format(*newData)
ser.write(bytes(reportStr, 'ascii'))
testCtr+=1
time.sleep(1)
bbq.closing = True
def serialDataRcv():
while not bbq.closing:
line = ser.readline()
rcvdTime = time.time()
temps = str(line, 'ascii').split(" ")
temps = temps[1:-1]
for j, x in enumerate(temps):
bbq.temps[j].append(float(x))
bbq.plotTimes.append(rcvdTime)
def main():
sendThread = Thread(target = serialDataPump)
receiveThread = Thread(target = serialDataRcv)
sendThread.start()
receiveThread.start()
# sc.runUI()
control.runControl() #blocks until user closes window
bbq.closing = True
time.sleep(2)
exit()
if __name__ == '__main__':
main()
## testSerMain()
However, I'd like to add a SEPARATE tkinter window that just has the most recent data on it, a close button, etc. I can get that window to come up, and show data initially, but none of the other threads run. (and nothing works when I try to run the window and the plot at the same time.)
#-------------------------------------------------------------------------------
# Name: BBQ Display/Control
# Purpose: displays current temp data, and control options
#-------------------------------------------------------------------------------
import tkinter as tk
import tkinter.font
import my_globals as bbq
import threading
fontSize = 78
class BBQControl(tk.Tk):
def __init__(self,parent):
tk.Tk.__init__(self,parent)
self.parent = parent
self.labelFont = tkinter.font.Font(family='Helvetica', size=int(fontSize*0.8))
self.dataFont = tkinter.font.Font(family='Helvetica', size=fontSize, weight = 'bold')
self.makeWindow()
def makeWindow(self):
self.grid()
btnClose = tk.Button(self,text=u"Close")
btnClose.grid(column=1,row=5)
lblFood = tk.Label(self,anchor=tk.CENTER, text="Food Temps", \
font = self.labelFont)
lblFood.grid(column=0,row=0)
lblPit = tk.Label(self,anchor=tk.CENTER, text="Pit Temps", \
font = self.labelFont)
lblPit.grid(column=1,row=0)
self.food1Temp = tk.StringVar()
lblFoodTemp1 = tk.Label(self,anchor=tk.E, \
textvariable=self.food1Temp, font = self.dataFont)
lblFoodTemp1.grid(column=0,row=1)
#spawn thread to update temps
updateThread = threading.Thread(target = self.updateLoop)
updateThread.start()
def updateLoop(self):
self.food1Temp.set(str(bbq.temps[1][-1]))
def runControl():
app = BBQControl(None)
app.title('BBQ Display')
app.after(0, app.updateLoop)
app.mainloop()
bbq.closing = True
if __name__ == '__main__':
runControl()
Your title sums up the problem nicely: Tkinter doesn't play well with threads. That's not a question, that's the answer.
You can only access tkinter widgets from the same thread that created the widgets. If you want to use threads, you'll need your non-gui threads to put data on a queue and have the gui thread poll the queue periodically.
One way of getting tkinter to play well with threads is to modify the library so all method calls run on a single thread. Two other questions deal with this same problem: Updating a TKinter GUI from a multiprocessing calculation and Python GUI is not responding while thread is executing. In turn, the given answers point to several modules that help to solve the problem you are facing. Whenever I work with tkinter, I always use the safetkinter module in case threads appear to be helpful in the program.
Related
i'm pretty new to python, so my knowledge is quiet basic. (i'm a system engineer)
i have a raspberry pi, an led strip and a python script to simulate a fire on the led strip :D
now i want to start the script by pressing my flic button. i found the fliclib sdk on github and installed it. my problem is now, how to handle the event correctly. i successfully can start the script, but i'd like to stop it by doublepress the flic button. but it seems like i'm stuck in the fire.py script as soon as i press the button once. can anybody help me how to set this up correctly please? :-)
Edit after suggestion:
i just edited my scripts as the following. i can see when the button is pressed once or twice with this output:
Starting Fire
Stopping Fire
but the led wont turn on, seems like, fire.py isn't opened or something like that.. when i set button=1 in fire.py itself, the fire turns on.
main.py
#!/usr/bin/env /usr/bin/python3
# -*- coding: utf-8 -*-
import flicbutton
import fire
button = 0
flicbutton.py
#!/usr/bin/env /usr/bin/python3
# -*- coding: utf-8 -*-
import fliclib
client = fliclib.FlicClient("localhost")
MyButton1 = '80:e4:da:71:83:42' #turquoise flic button
def got_button(bd_addr):
cc = fliclib.ButtonConnectionChannel(bd_addr)
cc.on_button_single_or_double_click_or_hold = some_handler
cc.on_connection_status_changed = \
lambda channel, connection_status, disconnect_reason: \
print(channel.bd_addr + " " + str(connection_status) + (" " + str(disconnect_reason) if connection_status == fliclib.ConnectionStatus.Disconnected else ""))
client.add_connection_channel(cc)
def got_info(items):
print(items)
for bd_addr in items["bd_addr_of_verified_buttons"]:
got_button(bd_addr)
def some_handler(channel, click_type, was_queued, time_diff):
if channel.bd_addr == MyButton1:
try:
if click_type == fliclib.ClickType.ButtonSingleClick:
print("Starting Fire")
button=1
if click_type == fliclib.ClickType.ButtonDoubleClick:
print("Stopping Fire")
button=2
if click_type == fliclib.ClickType.ButtonHold:
print("ButtonHold has not been assigned an action")
except Exception:
import datetime
print('An error occured: {:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now()))
client.get_info(got_info)
client.on_new_verified_button = got_button
client.handle_events()
fire.py
import RPi.GPIO as GPIO
import threading
import time
import random
import math
R = 17
G = 22
pwms = []
intensity = 1.0
def initialize_gpio():
GPIO.setmode(GPIO.BCM)
GPIO.setup([17,22], GPIO.OUT)
def red_light():
p = GPIO.PWM(R, 300)
p.start(100)
pwms.append(p)
while True:
p.ChangeDutyCycle(min(random.randint(50, 100) * math.pow(intensity + 0.1, 0.75), 100) if intensity > 0 else 0)
rand_flicker_sleep()
def green_light():
global green_dc
p = GPIO.PWM(G, 300)
p.start(0)
pwms.append(p)
while True:
p.ChangeDutyCycle(random.randint(5, 10) * math.pow(intensity, 2) if intensity > 0 else 0)
rand_flicker_sleep()
def rand_flicker_sleep():
time.sleep(random.randint(3,10) / 100.0)
def fan_the_flame(_):
global intensity
intensity = min(intensity + 0.25, 1.0)
def light_candle():
threads = [
threading.Thread(target=red_light),
threading.Thread(target=green_light),
## threading.Thread(target=burning_down)
]
for t in threads:
t.daemon = True
t.start()
for t in threads:
t.join()
def startfire():
try:
initialize_gpio()
print("\nPress ^C (control-C) to exit the program.\n")
light_candle()
except KeyboardInterrupt:
pass
finally:
for p in pwms:
p.stop()
def stopfire():
GPIO.cleanup()
#if __name__ == '__main__':
# main()
if button == 1:
startfire()
if button == 2:
stopfire()
Have a common (global variable) that both codes can read, you can put this in a standalone file that both codes can access. So script 1 updates this variable like
if(single press): variable=1
elif(double press): variable=2
then in fire.py you can poll the variable.
if(varaible==1): start/stop fire
elif(variable==2): stop/start fire
else: #throw error
I'm sure there are more efficient ways to do this, but this method should be the easiest to understand.
I am trying to create a program that scrapes a website for Islamic prayer times and then sounds an alarm when one of them is due. I have been successful so far for the coding part, but when it comes to GUI with Tkinter it has been a cumbersome task. My problem is when I am trying to show the times scraped in a simple window. It first lags and sometimes even never shows up and when it does it never shows the text and keeps showing the loading circle. What is the problem here?
#import libraries
from bs4 import BeautifulSoup
from urllib.request import urlopen
from datetime import datetime , timedelta
from os import popen
from time import sleep
from win10toast import ToastNotifier
from tkinter import *
#html parsing
manar = "http://almanar.com.lb/legacy/salat.php" #webpage
page = urlopen(manar)
soup = BeautifulSoup(page,"html.parser")
date_box = soup.find("h2")#("div" ,attrs = {"class":"time full-date"})#attribute needed
#getting times(part1)
today = date_box.text.strip()
#today = today.split(" ")
today = " ".join(today.split())
print(today)
#current time
now = datetime.now()
print("at: " + str(now))
#notifications
toaster = ToastNotifier()
#getting times(part2)
day_parts = ["prayer-time emsak","prayer-time fajer","prayer-time shorook","prayer-time dohor","prayer-time aser","prayer-time moghreb","prayer-time ishaa","prayer-time midnight", ]
prayer = []
for part in day_parts :
day_part = soup.find("div",attrs = {"class":part})
day_part = day_part.text.strip()
day_part = " ".join(day_part.split())
prayer.append(day_part)
prayer_times = []
for pray_time in prayer:
if prayer.index(pray_time) == 1:
pray_time = pray_time.split()[1:3]
prayer_time = ": ".join(pray_time)
elif prayer.index(pray_time) == len(prayer) - 1:
pray_time = pray_time.split()
word = " ".join(pray_time[:2])
prayer_time = word + ": " + pray_time[2]
else:
prayer_time = ": ".join(pray_time.split())
print(prayer_time)
prayer_times.append(prayer_time)
toaster.show_toast("Prayer Time:", prayer_time)
text_prayers = "{}\n{}\n{}\n{}\n{}".format(prayer_times[0],prayer_times[1],prayer_times[2],prayer_times[3],prayer_times[4])
#Sounding Adhan
seconds_hms = [3600, 60, 1]
now_seconds = sum([a*b for a,b in zip(seconds_hms, [now.hour, now.minute, now.second])])
times = []
for pnt in prayer_times:
lpnt = pnt.split()
if len(lpnt) == 3: #because midnight is 2 words
time = lpnt[2]
else:
time = lpnt[1]
times.append(time)
times_in_sec = []
for dpt in times: #dayparttime
adhan_time = [int(n) for n in dpt.split(":")]
dpts = sum([a*b for a,b in zip(seconds_hms,adhan_time)])
times_in_sec.append(dpts)
#msg box
root = Tk()
root.title("prayer times")
frm = Frame(root,bg="yellow")#,height= 20, width=30,)
txt = Text(frm,height= 10, width=20)
txt.insert(INSERT,text_prayers)
txt.pack()
ok = Button(root,text="ok", fg="green",command= root.destroy)
ok.pack(side="bottom")
frm.pack()
root.mainloop()
#main process
if __name__ == "__main__":
while True :
for tis in times_in_sec :
time_diff_seconds = tis - now_seconds
if time_diff_seconds < 0:
continue
elif time_diff_seconds == 0 :
print("praying time!")
popen("c://users//Dell//downloads//adhan.mp3")
toaster.show_toast("next adhan starts in : ","%s" %timedelta(seconds=time_diff_seconds))
elif time_diff_seconds > 0 :
print("next adhan starts in : %s" %timedelta(seconds=time_diff_seconds))
toaster.show_toast("next adhan starts in : ","%s" %timedelta(seconds=time_diff_seconds))
sleep(time_diff_seconds)
popen("c://users//Dell//downloads//adhan.mp3")
else:
print("this is a module")
When you put root.mainloop() in your code, this will control the window until you close it. Then it will continue with the next lines. So, whatever you insert after it won't be runned while the window is open.
You can change the root.mainloop() with these 3 equivalent lines. You can include them in your while True, and you can put them more than once (if you feel it's still laggy):
while True:
root.update()
root.update_idletasks()
Another thing that you should change is the usage of time.sleep(). During this function the window will lag, as it won't be updated with the lines above. You could try using tk.after():
tkinter.after(delay_ms, callback=None, *args)
Requests Tkinter to call function callback with arguments args after a delay of at least delay_ms milliseconds. There is no upper limit to how long it will actually take, but your callback won't be called sooner than you request, and it will be called only once. [archive.org]
So, in conclusion, the important thing in tkinter is to always run the mainloop(), or equivalent. This way your window will never lag.
In the last couple of weeks, I've been trying to make an application that can read EEG data from OpenBCI Cyton (#250Hz) and plot a graph in 'real-time'. What seems to work better here are threads. I applied the tips I found here 1 to communicate the thread with Tkinter, but the application still doesn't work (gives me the error RecursionError: maximum recursion depth exceeded while calling a Python object). Maybe I'm doing something wrong because I'm trying to use multiple .py files? See below the main parts of my code and a few more comments in context:
###FILE main.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from AppWindow import *
window = AppWindow()
window.start()
###FILE AppWindow.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import ttk
from tkinter.scrolledtext import ScrolledText
import scroller as scrl
import logging
import requests
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import random
from pandas import DataFrame
import stream_lsl_eeg as leeg
#Definitions
H = 720
W = 1280
#Color palette>> https://www.color-hex.com/color-palette/92077
bg_color = "#c4ac93"
sc_color = "#bba58e"
tx_color = "#313843"
dt_color = "#987f62"
wn_color = "#6b553b"
class AppWindow:
#Other Functions
def plotGraph(self, x, y):
self.ax.clear()
self.ax.plot(x,y, color = tx_color)
plt.subplots_adjust(bottom=0.31, left=0.136, top=0.9, right=0.99)
plt.ylabel('Magnitude', fontsize = 9, color = tx_color)
plt.xlabel('Freq', fontsize = 9, color = tx_color)
self.figure.canvas.draw()
def __init__(self):
self.root = tk.Tk() #start of application
self.root.wm_title("Hybrid BCI - SSVEP and Eye Tracker")
#Other Graphical Elements
#Button that calls function
self.btn_ReceiveEEG = tk.Button(self.EEG_frame, text = "Receive EEG signal", bg = bg_color, fg = tx_color, state = tk.DISABLED, command = lambda: leeg.getEEGstream(self))
self.btn_ReceiveEEG.place(anchor = 'nw', relx = 0.52, rely = 0.5, width = 196, height = 40)
#Other Graphical Elements
def start(self):
self.root.mainloop() #end of application
### FILE stream_lsl_eeg.py
from pylsl import StreamInlet, resolve_stream
import tkinter as tk
import AppWindow as app
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import threading
import queue
import time
class myThread(threading.Thread):
def __init__(self, name, q, f):
threading.Thread.__init__(self)
self.name = name
self.q = q
self.f = f
def run(self):
print("Starting ", self.name)
pullSamples(self.q, self.f) #place where function is called
def getInlet(app): #this is triggered by another button and it's working fine
global inlet
app.logger.warn('Looking for an EEG strean...')
streams = resolve_stream('type', 'EEG')
inlet = StreamInlet(streams[0])
app.logger.warn('Connected')
app.btn_ReceiveEEG.config(state = tk.NORMAL)
def pullSamples(q):
i = 0
while i<1000:
sample, timestamp = inlet.pull_sample()
threadLock.acquire() #thread locks to put info in the queue
q.put([sample,timestamp]) #data is put in the queue for other threads to access
threadLock.release() #thread unlocks after info is in
i += 1
stopcollecting = 1
print("Exit flag on")
def plotSamples(app, kounter): #Outside Thread
if not stopcollecting: #testing if stream reception stopped
while dataqueue.qsize( ):
try:
kounter += 1
sample, timestamp = dataqueue.get(0)
samples.append(sample[0]) #getting just channel 1 (0)
timestamps.append(timestamp)
show_samples = samples[-250:]
show_timestamps = timestamps[-250:]
app.plotGraph(show_timestamps,show_samples)
print(counter) #this was just a control to count if the right amount of samples was coming out of the queue
except dataqueue.Empty:
pass #still not implemented, but will return to the main application
app.root.after(60, plotSamples(flag,app,kounter)) #60 chosen because plot should update every 15 samples (15/250 = 0,06s)
def getEEGstream(app): #function called by button
app.logger.warn('Starting thread...')
#
kounter = 0
start = time.perf_counter()
thread1.start()
##
plotSamples(flag, app, kounter)
##
thread1.join() #I don't know if I need this...
finish = time.perf_counter()
#
print(f'Sizes: Samples [{len(samples)}, {len(samples[0])}], {len(timestamps)} timestamps')
print(f'Sucessfully streamed in {round(finish-start,3)}s!')
###
threadLock = threading.Lock()
dataqueue = queue.Queue()
stopcollecting = 0
kounter = []
flag = queue.Queue() #secondary queue for flags not used at the moment
flag.put(0)
thread1 = myThread("Thread-1", dataqueue,flag)
samples,timestamps = [],[]
show_samples, show_timestamps = [],[]
As I found here 2, a function should not call itself, but it's basically what here 1 does. Also, I don't think I'm calling root.mainloop() multiple times like done in here 3.
After executing, python gives me the following error/output:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\Users\robotics\Documents\gitDocuments\SSVEP_EyeGaze_py\AppWindow.py", line 109, in <lambda>
self.btn_ReceiveEEG = tk.Button(self.EEG_frame, text = "Receive EEG signal", bg = bg_color, fg = tx_color, state = tk.DISABLED, command = lambda: leeg.getEEGstream(self))
File "C:\Users\robotics\Documents\gitDocuments\SSVEP_EyeGaze_py\stream_lsl_eeg.py", line 118, in getEEGstream
plotSamples(flag, app, kounter)
File "C:\Users\robotics\Documents\gitDocuments\SSVEP_EyeGaze_py\stream_lsl_eeg.py", line 104, in plotSamples
app.root.after(60, plotSamples(flag,app,kounter))
File "C:\Users\robotics\Documents\gitDocuments\SSVEP_EyeGaze_py\stream_lsl_eeg.py", line 104, in plotSamples
app.root.after(60, plotSamples(flag,app,kounter))
File "C:\Users\robotics\Documents\gitDocuments\SSVEP_EyeGaze_py\stream_lsl_eeg.py", line 104, in plotSamples
app.root.after(60, plotSamples(flag,app,kounter))
[Previous line repeated 986 more times]
File "C:\Users\robotics\Documents\gitDocuments\SSVEP_EyeGaze_py\stream_lsl_eeg.py", line 92, in plotSamples
while dataqueue.qsize( ): # if not dataqueue.empty():
File "C:\Users\robotics\AppData\Local\Continuum\anaconda3\envs\psychopy\lib\queue.py", line 87, in qsize
with self.mutex:
RecursionError: maximum recursion depth exceeded while calling a Python object
Exit flag on
This means the thread is being successfully executed, apparently, but the plotSamples() is crashing.
Any advice??
after() (similar to button's command= and bind()) needs function's name without () and without argument - it is called callback - and after sends it to mainloop and mainloop later uses () to run it.
You use function with ()
app.root.after(60, plotSamples(flag,app,kounter))
so it runs it at once (it doesn't send it to mainloop) and this function runs at once again the same function which runs at once the same function, etc. - so you create recursion.
It works like
result = plotSamples(flag,app,kounter) # run at once
app.root.after(60, result)
If you have to use function with arguments then you can do
app.root.after(60, plotSamples, flag, app, kounter)
Eventually you can use lambda to create function without argument
app.root.after(60, lambda:plotSamples(flag,app,kounter) )
I'm trying to make an program for twitch, where the twitch chat can vote by typing a command ("!voteA") for example, and the chatbot-code will count the votes, and show them in a GUI window, I've already gotten pretty far, but my GUI window is not opening and I think it has something to do with the self.after(10, self.get_votes) line, could anyone help me out?
Here's the code: (it has some more tabs like Read, Socket, Initialize, Settings, but I don't think they're relevant for now, if they are I can also post them)
import Tkinter as tk
from Read import getUser, getMessage
from Socket import openSocket, sendMessage
from Initialize import joinRoom
from collections import OrderedDict
class App(tk.Frame): #Toplevel is a frame with a specific use. Unless there is another window, you want a Frame.
def __init__(self):
options = [
"voteA",
"voteB",
"voteC"]
self.s = openSocket()
joinRoom(self.s)
self.readbuffer = ""
tk.Frame.__init__(self)
self['background']='black'
self.pack()
self.master.geometry("+200+200")
# self.master.attributes("-alpha", 0.7)
self.labels = OrderedDict()
for option in options:
label = tk.Label(
self,
bg="black",
fg="white",
font="HouseSlant-Regular 30",
anchor="w")
label.pack()
self.labels[option] = [0, label]
self.update_text()
self.after(10, self.get_votes)
def update_text(self):
for name, data in self.labels.items():
count, label = data
label['text'] = "{} has {} votes".format(name, count)
def get_votes(self):
self.after(10, self.get_votes)
self.readbuffer = self.readbuffer + self.s.recv(1024)
temp = self.readbuffer.split('\n')
self.readbuffer = temp.pop() #save the last (possibly incomplete) line for later
if self.readbuffer == "":
pass #no further messages in the queue
#you should add a sleep time here for the sake of your hot NIC
for line in temp:
print(line)
if "PING" in line:
s.send("PONG :tmi.twitch.tv\r\n".encode())
break
user = getUser(line)
message = getMessage(line)
print "{} typed: {}".format(user, message)
if "!commands" in message:
sendMessage(self.s, " ".join(["!"+option for option in self.labels]))
break
for option in self.labels:
if "!"+option in message:
self.labels[option][0] += 1
print self.labels[option][0]
self.update_text()
app=App()
app.mainloop()
What happens when I run the code, is that the chatbot works; if I type "!commands" or "!voteA" it will respond to that nicely, however, the GUI window isn't opening. I can see in my dock (I'm a mac user) that it's trying to open a window, but it freezes and then I have to force quit it. It's not giving an error in the compiler though. Does anyone have any idea what I've messed up?
I'm using TKinter to draw a GUI for a python program im making, and I have it updating at about 200ms, but when the program queries the data it locks the program because it takes a second to get the data. I tried to write it into multi processing so each query would be its own process and just share the info with global variables because my program is a real time program that uses wmi to get performance data. At least thats what I have so far. Not the end goal just the start. So if you could help me figure out why even with multiprocessing if it queries the info while I'm dragging the app across the screen it will freeze for a second.
import wmi
import time
import Tkinter as tk
from multiprocessing import cpu_count
import Image
from PIL import ImageTk
from Tkinter import Button, Label
import threading
from multiprocessing import Process, Value, Array
window = Tk();
global pct_in_use
global available_mbytes
global utilization
global hours_up
a= 0
b=0
def build_labels(gui, string):
var = StringVar()
label = Label( gui, textvariable=var, relief=RAISED )
var.set(string)
return label
def get_uptime():
global hours_up
c = wmi.WMI()
secs_up = int([uptime.SystemUpTime for uptime in c.Win32_PerfFormattedData_PerfOS_System()][0])
hours_up = secs_up / 3600
return hours_up
def get_cpu():
global utilization
c = wmi.WMI()
utilizations = [cpu.LoadPercentage for cpu in c.Win32_Processor()]
utilization = int(sum(utilizations) / len(utilizations)) # avg all cores/processors
return utilization
def get_mem_mbytes():
global available_mbytes
c = wmi.WMI()
available_mbytes = int([mem.AvailableMBytes for mem in c.Win32_PerfFormattedData_PerfOS_Memory()][0])
return available_mbytes
def get_mem_pct():
global pct_in_use
c = wmi.WMI()
pct_in_use = int([mem.PercentCommittedBytesInUse for mem in c.Win32_PerfFormattedData_PerfOS_Memory()][0])
return pct_in_use
def Draw():
global mem_per_lb
global cpu_lb
global up_time_lb
global mb_used_lb
mem_pct = 0
mem_per_lb = tk.Label(text='Memory % ' + str(mem_pct))
mem_per_lb.place(x=10, y=10)
cpu = 0
cpu_lb = tk.Label(text='CPU % ' + str(cpu))
cpu_lb.place(x=10, y=30)
mem_pct = 0
up_time_lb = tk.Label(text='UP Time % ' + str(mem_pct))
up_time_lb.place(x=10, y=50)
mem_pct = 0
mb_used_lb = tk.Label(text='Memory MB ' + str(mem_pct))
mb_used_lb.place(x=10, y=70)
def Refresher():
global mem_per_lb
global cpu_lb
global up_time_lb
global mb_used_lb
mem_pct = get_mem_pct()
cpu = get_cpu()
up_time = get_uptime()
mbused = get_mem_mbytes()
window.wm_title('Vision' + time.asctime())
mem_per_lb.configure(text='Memory % ' + str(pct_in_use))
cpu_lb.configure(text='CPU ' + str(utilization))
up_time_lb.configure(text='UP Time ' + str(hours_up))
mb_used_lb.configure(text='Memory MB ' + str(available_mbytes))
window.after(200, Refresher) # every second...
def draw_window(): #creates a window
window.geometry('704x528+100+100')
image = Image.open('bg.jpg') #gets image (also changes image size)
image = image.resize((704, 528))
imageFinal = ImageTk.PhotoImage(image)
label = Label(window, image = imageFinal) #creates label for image on window
label.pack()
label.place(x = a, y = b) #sets location of label/image using variables 'a' and 'b'
Draw()
Refresher()
window.mainloop()
up_time_p = Process(target=get_uptime())
cpu_p = Process(target=get_cpu())
mb_p = Process(target=get_mem_mbytes())
pct_p = Process(target=get_mem_pct())
win_p = Process(target=draw_window())
up_time_p.start()
mb_p.start()
pct_p.start()
cpu_p.start()
win_p.start()
up_time_p = Process(target=get_uptime())
cpu_p = Process(target=get_cpu())
mb_p = Process(target=get_mem_mbytes())
pct_p = Process(target=get_mem_pct())
win_p = Process(target=draw_window())
I don't think you're supposed to include parentheses when you supply targets to a process. If you do that, the functions will execute in the main thread, and whatever those functions return will become the target.
up_time_p = Process(target=get_uptime)
cpu_p = Process(target=get_cpu)
mb_p = Process(target=get_mem_mbytes)
pct_p = Process(target=get_mem_pct)
win_p = Process(target=draw_window)
As per Kevin's answer, you're calling the functions when you create each process instance. So they are all actually running in the main process.
However, once you fix that problem your 'global' variables aren't going to work as you expect. When a process is created it takes a COPY of the parent processes memory. Any changes to that memory are not shared between the processes.
To achieve the result you want you'll have to use Python's threading library. Not the multiprocess library.
Threads share the same memory space as the parent process. Which can lead to its own problems. Though in your case the global variables you're changing are just integer constants so it should be okay.
from threading import Thread
data_funcs = (
get_uptime,
get_cpu,
get_mem_mbytes,
get_mem_pct,
draw_window
)
threads = [Thread(target=f) for f in data_funcs]
for t in threads:
t.start()
Is the general pattern you should use. You'll then have to figure out a way of killing those threads when you shut down the main process or it will hang.