Уважаемые продвинутые python программисты,
Я новичок Python, но мне пришлось разработать GUI для научных c измерений. Я решил использовать старый добрый tkinter, так как он мне показался простым по сравнению с QT. Основная программа, которую я публикую ниже, используется для создания кнопок. Кнопки Pu sh открывают внешние сценарии python, выполняющие измерения с помощью «subprocess.Popen». Измерения отправляются обратно через сокеты. Я также использовал некоторые потоки для обновления sh показаний измерений.
Моя программа работает довольно хорошо, но она слишком жадная для моего Raspberry 3B +. Когда я запускаю его, он использует 130% процессора. Мое окно tkinter зависнет (но измерения все еще работают), если я дважды нажму sh кнопки «профиля». Как я уже говорил, я новичок, и в моей программе может быть много fl aws для эксперта. Я был бы признателен за помощь в оптимизации моего кода без переписывания всего.
Если бы кто-то мог указать, что использует много ЦП, я был бы очень признателен. При кодировании я обнаружил некоторые проблемы:
-Я могу перезапустить слишком много потоков в каждой операции, и ни один из них никогда не завершается. Любая идея, чтобы помочь мне закончить потоки?
-Я вызываю много модулей, и некоторые из них жадные (например, модуль «запросов»)
-Tk - это oldi sh, и я должен изучить Qt но это займет время, и я сделаю это позже, когда этот проект будет запущен.
Вот мой код, я прошу прощения, если он очень длинный:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created 11/12/19
@author: Lionel
"""
import tkinter as tk
from tkinter import *
import threading
import tk_tools
import subprocess
import socket
from PIL import ImageTk, Image
import requests
import re
from tkinter import messagebox
import time
global status
speed=0
current=0
depth=0
argdepth=0
newdepth=0
bgcolor=str("light gray")
"""-------------------------DECLARATIONS PORTS UDP GUI-------------------------"""
UDP_IP_ADDRESS = "192.168.203.28"
UDP_PORT_CURRENT = 9001
UDP_PORT_POS = 9002
UDP_PORT_DEPTH = 9003
UDP_PORT_MESG = 9004
UDP_PORT_SPEED = 9005
serverSockCurrent = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSockCurrent.bind((UDP_IP_ADDRESS, UDP_PORT_CURRENT))
serverSockPosition = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSockPosition.bind((UDP_IP_ADDRESS, UDP_PORT_POS))
serverSockDepth = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSockDepth.bind((UDP_IP_ADDRESS, UDP_PORT_DEPTH))
serverSockMessage = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSockMessage.bind((UDP_IP_ADDRESS, UDP_PORT_MESG))
serverSockSpeed = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
serverSockSpeed.bind((UDP_IP_ADDRESS, UDP_PORT_SPEED))
def readrelay():
#récupérer état
r = requests.get('http://192.168.203.129/stateFull.xml?&noReply=0')
string = r.text
subStr = re.findall(r'relaystate>(.+?)</relaystate',string)
global status
global relaystatus
status=int(', '.join(subStr))
if status ==1:
relaystatus="POWER IS ON"
print("relay is on")
measurements()
read = subprocess.Popen(['/usr/bin/python3','/home/pi/read.py'], shell=False)
time.sleep(2)
read.terminate()
elif status ==0:
relaystatus="POWER IS OFF"
print("relay is off")
else:
print("relay status undefined, no network")
relaystatus="UNDEFINED"
def toggle():
if var1.get() == "POWER IS ON":
status=1
print("relay on...")
print("status=", status)
try:
requests.get('http://192.168.203.129/state.xml?relayState=1&noReply=0')
except requests.exceptions.ConnectionError as err:
if "BadStatusLine" in repr(err):
pass
else:
status=0
try:
requests.get('http://192.168.203.129/state.xml?relayState=0&noReply=0')
except requests.exceptions.ConnectionError as err:
if "BadStatusLine" in repr(err):
pass
print("relay off...")
print("status=", status)
def scaler():
scale = Scale(MyWindow, from_=0, to_=40, length=350,tickinterval=5, bg="SkyBlue2", troughcolor = "dodger blue", bd =0, state="active")
scale.place(x=825, y=30)
while True:
scale.set(newdepth)
def run_scaler():
tscaler=threading.Thread(target=scaler)
tscaler.start()
def measurements():
run_position()
run_depth()
run_message()
run_current()
run_speed()
run_scaler()
"""-------------------------Méthode lancement profil auto---------------------"""
def profil():
argdepth=arg1.get()
sub=arg2.get()
speed=arg3.get()
global pyprofil
pyprofil=subprocess.Popen(['/usr/bin/python3','/home/pi/profilspeed.py',argdepth,sub,speed], shell=False)
def run_profil():
readrelay()
print("status on start=", status)
if status ==1:
profil()
measurements()
elif status==0:
root = Tk()
root.withdraw()
messagebox.showwarning("Warning","POWER IS OFF")
root.destroy()
else:
root = Tk()
root.withdraw()
messagebox.showwarning("Warning","NO NETWORK")
root.destroy()
def run_stop():
global pystop
pystop =subprocess.Popen(['/usr/bin/python3','/home/pi/stop.py'],shell=False)
pyprofil.terminate()
measurements()
pystop.terminate()
def rescue():
global pyrescue
pyprofil.terminate()
pyrescue=subprocess.Popen(['/usr/bin/python3', '/home/pi/rescueblackout.py'], shell=False)
def run_rescue():
rescue()
measurements()
def emergency():
subprocess.run("python3 emergency.py", shell=True)
def run_emergency():
emergency()
measurements()
def run_quit():
MyWindow.destroy()
exit()
"""-------------------------Méthode lecture courant----------------------------"""
def refreshcurrent():
while True:
datacurrent, addr = serverSockCurrent.recvfrom(1024)
global current
current = datacurrent.decode('utf-8').strip()
def run_current():
tcurrent = threading.Thread(target=refreshcurrent)
tcurrent.start()
"""-------------------------Méthode lecture position----------------------------"""
def refreshposition():
while True:
datapos, addr = serverSockPosition.recvfrom(1024)
global pos
pos = datapos.decode('utf-8').strip()
textpos.configure(text = str(pos))
def run_position():
tpos = threading.Thread(target=refreshposition)
tpos.start()
"""-------------------------Méthode lecture depth----------------------------"""
def refreshdepth():
while True:
datadepth, addr = serverSockDepth.recvfrom(1024)
global depth, newdepth
depth = datadepth.decode('utf-8').strip()
#print("depth=",speth)
textdepth.configure(text = str(depth))
if float(depth) < 0:
newdepth = 0
else:
newdepth=int(100*float(depth))
def run_depth():
tdepth = threading.Thread(target=refreshdepth)
tdepth.start()
"""-------------------------Méthode lecture messages----------------------------"""
def refreshmessage():
while True:
datamesg, addr = serverSockMessage.recvfrom(1024)
mesg = datamesg.decode('utf-8').strip()
strmesg = str(mesg)
if strmesg.find("END") != -1:
print ("LE PROFIL EST FINI!")
pyprofil.terminate()
# if tprofil.is_alive():
# print ("LE THREAD PROFIL EST TOUJOURS VIVANT!")
#print("depth=",speth)
textmesg.configure(text = strmesg)
def run_message():
tmessage=threading.Thread(target=refreshmessage)
tmessage.start()
"""-------------------------Méthode lecture vitesse----------------------------"""
def refreshspeed():
while True:
dataspeed, addr = serverSockSpeed.recvfrom(1024)
speed = dataspeed.decode('utf-8').strip()
speed = int(speed) / 5000
if speed < 0 and speed > -0.0005 :
speed=0
speed = round(speed,2)
#print("speed=",speed)
textspeed.configure(text = str(speed))
def run_speed():
tspeed=threading.Thread(target=refreshspeed)
tspeed.start()
"""-----------------------------GUI--------------------------------------------"""
# Fenêtre principale
MyWindow = Tk()
MyWindow.title("CTD AUTO PROFILING CRANE")
MyWindow.geometry("900x400")
MyWindow.configure(background=bgcolor)
#Création d'un widget Entry depth (Champ de saisie)
zone_texte1=Label(text="Max depth:")
zone_texte1.place(x=170,y=62)
zone_texte1.config(font="courier 15 bold",fg="DodgerBlue3", bg=bgcolor)
zone_texte1u=Label(text="(m)")
zone_texte1u.place(x=260,y=82)
zone_texte1u.config(font="courier 10 bold",fg="DodgerBlue3", bg=bgcolor)
arg1= tk.StringVar()
arg1.set(0.3)
Champ1 = Entry(MyWindow, textvariable= arg1, font = "courier 15 bold", bg ="white", fg="DodgerBlue3", width="4", bd=3)
Champ1.place(x=300,y=60)
#Création d'un widget Entry subsurface depth (Champ de saisie)
zone_texte2=Label(text="Subsurface:")
zone_texte2.place(x=390,y=62)
zone_texte2.config(font="courier 15 bold",fg="DodgerBlue3", bg=bgcolor)
zone_texte2u=Label(text="(m)")
zone_texte2u.place(x=490,y=82)
zone_texte2u.config(font="courier 10 bold",fg="DodgerBlue3", bg=bgcolor)
arg2= tk.StringVar()
arg2.set(0.15)
Champ2 = Entry(MyWindow, textvariable= arg2, font = "courier 15 bold", bg ="white", fg="DodgerBlue3", width="4", bd=3)
Champ2.place(x=530,y=60)
#Création d'un widget Entry speed (Champ de saisie)
zone_texte3=Label(text="Speed:")
zone_texte3.place(x=640,y=62)
zone_texte3.config(font="courier 15 bold",fg="DodgerBlue3", bg=bgcolor)
zone_texte3u=Label(text="(m/s)")
zone_texte3u.place(x=668,y=82)
zone_texte3u.config(font="courier 10 bold",fg="DodgerBlue3", bg=bgcolor)
arg3= tk.StringVar()
arg3.set(0.1)
Champ3 = Entry(MyWindow, textvariable= arg3, font = "courier 15 bold", bg ="white", fg="DodgerBlue3", width="4", bd=3)
Champ3.place(x=720,y=60)
# Création d'un bouton profil
Buttonprofil = Button(MyWindow, text ="Profil", command = run_profil)
Buttonprofil.config(text='PROFILE', fg='black', bg='dodger blue', activebackground='DodgerBlue3', activeforeground='white', bd=4)
Buttonprofil.config(font=('courier', 15, 'bold'))
Buttonprofil.place(x=10,y=60)
# Création d'un bouton STOP
Buttonstop = Button(MyWindow, text ="STOP", command = run_stop)
Buttonstop.config(text='STOP', fg='white', bg='red', activebackground='red3', activeforeground='black', bd=4)
Buttonstop.config(font=('courier', 15, 'bold'))
Buttonstop.place(x=10,y=120)
# Création d'un bouton Rescue
Buttonrescue = Button(MyWindow, text ="RETRIEVE", command = run_rescue)
Buttonrescue.config(text='RETRIEVE', fg='black', bg='DarkOrange1', activebackground='DarkOrange3',activeforeground='white', bd=4)
Buttonrescue.config(font=('courier', 15, 'bold'))
Buttonrescue.place(x=10,y=180)
# Création d'un bouton EMERGENCY
Buttonemergency = Button(MyWindow, text ="EMERGENCY", command= run_emergency)
Buttonemergency.config(text='EMERGENCY', fg='red', bg='white', activebackground='red', activeforeground='white', bd=4)
Buttonemergency.config(font=('courier', 15, 'bold'))
Buttonemergency.place(x=10,y=240)
#Création d'un bouton Exit
ButtonExit = Button(MyWindow, text ="QUIT", font = "courier 15 bold", command = run_quit, bd=4)
ButtonExit.place (x=10, y=340)
#Création zone de texte courant
zone_texte4=Label(text="Current:", font="courier 15 bold", bg=bgcolor)
zone_texte4.place(x=170,y=230)
zone_texte4u=Label(text="(mA)")
zone_texte4u.place(x=230,y=250)
zone_texte4u.config(font="courier 10 bold",fg="black", bg=bgcolor)
#gauge courant
my_gauge = tk_tools.Gauge(MyWindow, height = 110, width = 200,
min_value=-200,
max_value=2600,
divisions=13,
yellow_low=10,
label='Current',
unit='mA',
bg=bgcolor)
my_gauge.place(x=300, y=180)
def update_gauge():
my_gauge.set_value(current)
MyWindow.after(200, update_gauge)
MyWindow.after(50, update_gauge)
#Création zone de texte position
zone_texte5=Label(text="Position:", font="courier 15 bold", bg=bgcolor, fg="black")
zone_texte5.place(x=350,y=125)
zone_texte5u=Label(text="(ticks)")
zone_texte5u.place(x=396,y=145)
zone_texte5u.config(font="courier 10 bold",fg="black", bg=bgcolor)
textpos= Label(MyWindow,font = "courier 15 bold", bg ="black", fg="green2", width="10", bd=4)
textpos.place(x=470,y=125)
#Création zone de texte depth
zone_texte6=Label(text="Depth:", font="courier 15 bold", bg=bgcolor, fg="black")
zone_texte6.place(x=170,y=125)
zone_texte6u=Label(text="(m)")
zone_texte6u.place(x=210,y=145)
zone_texte6u.config(font="courier 10 bold",fg="black", bg=bgcolor)
textdepth= Label(MyWindow,font = "courier 15 bold", bg ="black", fg="green2", width="6", bd =4)
textdepth.place(x=250,y=125)
#Création zone de texte messages
zone_texte7=Label(text="STATUS:", font="courier 15 bold", bg=bgcolor)
zone_texte7.place(x=170,y=315)
textmesg= Label(MyWindow,font = "courier 15 bold", bg ="black", fg="DeepPink2", width="52", anchor="w", bd=4)
textmesg.place(x=170,y=345)
#Création zone de texte speed
zone_texte8=Label(text="Speed:", font="courier 15 bold", bg=bgcolor)
zone_texte8.place(x=620,y=125)
zone_texte8u=Label(text="(m/s)")
zone_texte8u.place(x=648,y=145)
zone_texte8u.config(font="courier 9 bold",fg="black", bg=bgcolor)
#print(type(textcurrent))
textspeed= Label(MyWindow,font = "courier 15 bold", bg ="black", fg="green2", width="6", bd=4)
textspeed.place(x=700,y=125)
#LOGO DT INSU
img1 = ImageTk.PhotoImage(Image.open("logodtm.png"))
imglabel = Label(MyWindow, image=img1)
imglabel.place(x=700, y=190)
imglabel.config(bg=bgcolor)
#LOGO LIENS
img2 = ImageTk.PhotoImage(Image.open("liens.png"))
imglabel = Label(MyWindow, image=img2)
imglabel.place(x=600, y=210)
imglabel.config(bg=bgcolor)
scaleinit = Scale(MyWindow, from_=0, to_=40, length=350,tickinterval=5, bg="SkyBlue2", troughcolor = "dodger blue", bd =0, state="active")
scaleinit.place(x=825, y=30)
readrelay()
var1 = tk.StringVar()
toggle = Checkbutton(MyWindow, onvalue="POWER IS ON", offvalue="POWER IS OFF", width=13,
indicatoron=False,
background="red",activebackground="red",selectcolor="chartreuse2",
variable=var1, textvariable=var1,
bd=4, command=toggle)
var1.set(relaystatus)
print("status=", status)
if status ==1:
toggle.select()
toggle.place(x=380,y=10)
toggle.config(font="courier 15 bold")
MyWindow.mainloop()