Je suis sûr que c'est l'un des pires codes que vous avez jamais vu, mais c'est mon premier programme orienté objet. Ce programme devrait communiquer avec un Arduino pour collecter des informations sur un générateur solaire et certaines batteries. Il faudra aussi gérer automatiquement certains onduleurs et ainsi de suite. J'ai enlevé la plus grande partie de l'interface graphique pour rendre le code un peu plus facile à lire mais il reste assez gros. Ce que j'ai essayé de coder est quelque chose qui une fois que la communication série commence à changer les paramètres sur l'interface graphique, j'ai essayé de le réaliser en ouvrant un nouveau thread qui fonctionne en arrière-plan et recueille ou envoie les données. Ce qui se passe en réalité, c'est que dès que la communication série commence, l'interface graphique se bloque et après un certain temps, tout se produit. J'ai ajouté une impression à l'intérieur du thread pour vérifier si les communications commençaient et en fait, avant que les python chrashes, certaines informations soient collectées à partir du port série.Freez GUI lors de l'ouverture d'un fil
import Tkinter
import tkMessageBox
import ttk
import serial
import sys
import glob
import threading
from time import sleep
class PaginaPrincipale(Tkinter.Tk, threading.Thread):
dati_in = None
dati_out = None
def __init__(self, parent):
Tkinter.Tk.__init__(self, parent)
self.parent = parent
si1 = Tkinter.IntVar()
au1 = Tkinter.IntVar()
si2 = Tkinter.IntVar()
au2 = Tkinter.IntVar()
self.grid()
# those classes will manage the auto function
def manuale(variable):
if variable == 1:
print(si1.get())
if variable == 2:
print(si2.get())
def automatico(variable):
if variable == 1:
print(au1.get())
if variable == 2:
print(au2.get())
# this class manages the serial connection, it scans for the available ports
# and when the user select the desired one it should open it and start a thread
# I still haven't implemented the update of the GUI
def connetti():
# Here I extract the clicked value on the listbox
def selezione(evt):
w = evt.widget
index = int(w.curselection()[0])
value = w.get(index)
scelta_box.config(text=value)
# Here I try to open the selected port and to start a new thread which keeps exchanging
# information with the microcontroller (Arduino)
def avvia_seriale(porta):
try:
print(porta)
pagina_connessione.destroy()
threading.Thread(target=comunicazione(porta))
except:
# Here PiCharm gives me a warning: too broad exception clause
tkMessageBox.showerror('Serial port', 'Can''t open the selected serial port')
pass
# here I will place all the serial communication statements
def comunicazione(porta):
porta_seriale = serial.Serial(porta)
while porta_seriale.isOpen():
porta_seriale.write(1)
sleep(.1)
self.dati_in = porta_seriale.readline()
sleep(.1)
print self.dati_in
pass
# Here I scan for available ports and I put them inside the listbox
if sys.platform.startswith('win'):
ports = ['COM%s' % (i + 1) for i in range(256)]
elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
# this excludes your current terminal "/dev/tty"
ports = glob.glob('/dev/tty[A-Za-z]*')
elif sys.platform.startswith('darwin'):
ports = glob.glob('/dev/tty.*')
else:
raise EnvironmentError('Unsupported platform')
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port) # il metodo append() aggiunge alla lista result l'ultimo termine trovato
except (OSError, serial.SerialException):
pass
# I open a new toplevel so that when I choose and open the serial port I close it and nothing remains
# on the main page
pagina_connessione = Tkinter.Toplevel()
pagina_connessione.title('Gestione connessione')
descrizione_scelte = Tkinter.Label(pagina_connessione, text='Lista scelte:', justify='left')
descrizione_scelte.grid(column=0, row=0, sticky='W')
lista_scelte = Tkinter.Listbox(pagina_connessione, height=len(result), selectmode='single')
contatore = len(result)
for item in result:
lista_scelte.insert(contatore, item)
contatore += 1
if contatore == 0:
lista_scelte.insert(0, 'Nessuna porta seriale')
lista_scelte.grid(column=0, row=1)
lista_scelte.bind('<<ListboxSelect>>', selezione)
bottone_connessione = Tkinter.Button(pagina_connessione, text='Connetti!',
command=lambda: avvia_seriale(scelta_box.cget("text")))
bottone_connessione.grid(column=1, row=1)
scelta_box = Tkinter.Label(pagina_connessione, width=15, height=1, borderwidth=3, background='blue')
scelta_box.grid(column=0, row=2)
pagina_connessione.mainloop()
#
#
# This is the main GUI
#
#
frame_batteria1 = Tkinter.Frame(self, borderwidth=2, bg="black")
frame_batteria1.grid(column=0, row=0, sticky='news')
self.descrittore_v_b_1 = Tkinter.Label(frame_batteria1, text="V Batteria 1", font=("Helvetica", 8),
justify='center')
self.descrittore_v_b_1.grid(column=0, row=0, sticky='news')
self.descrittore_i_b_1 = Tkinter.Label(frame_batteria1, text="I Batteria 1", font=("Helvetica", 8),
justify='center')
self.descrittore_i_b_1.grid(column=1, row=0, sticky='NEWS')
self.vbatteria1 = Tkinter.Scale(frame_batteria1, bd=4, troughcolor='blue', resolution=0.1, state='disabled',
from_=15, to=0)
self.vbatteria1.grid(column=0, row=1, sticky='NEWS')
self.ibatteria1 = Tkinter.Scale(frame_batteria1, bd=4, troughcolor='blue', resolution=0.1, state='disabled',
from_=10, to=0)
self.ibatteria1.grid(column=1, row=1, sticky='NEWS')
self.descrittore_inverter1 = Tkinter.Label(self, text="Inverter 1", font=("Helvetica", 8), justify='left')
self.descrittore_inverter1.grid(column=0, row=3, sticky='NEWS')
self.scelte_manuali_inverter1 = Tkinter.Radiobutton(self, text="Acceso", variable=si1, value=1,
command=lambda: manuale(1))
self.scelte_manuali_inverter1.grid(column=0, row=4, sticky='NEWS')
self.scelte_manuali_inverter1 = Tkinter.Radiobutton(self, text="Spento", variable=si1, value=0,
command=lambda: manuale(1))
self.scelte_manuali_inverter1.grid(column=0, row=5, sticky='NEWS')
self.scelta_automatica_inverter1 = Tkinter.Checkbutton(self, text="Automatico", variable=au1, onvalue=1,
offvalue=0, command=lambda: automatico(1))
self.scelta_automatica_inverter1.grid(column=2, row=4, sticky='NEWS')
#
#
# separators
#
#
ttk.Separator(self, orient='horizontal').grid(row=6, columnspan=8, sticky='EW')
ttk.Separator(self, orient='vertical').grid(row=2, column=3, rowspan=4, sticky='NS')
self.gestisci_connessione = Tkinter.Button(self, text="Connetti!", command=connetti)
self.gestisci_connessione.grid(row=7, column=6, sticky='EW')
if __name__ == "__main__":
applicazione = PaginaPrincipale(None)
applicazione.title('Pannello di controllo')
applicazione.mainloop()
vous ne pouvez pas utiliser la boucle 'while' car il bloque' mainloop' qui n'everething dans Tkinter (et tout autre GUI) - il devient événement clé/souris, envoie aux widgets, les données de changements dans les widgets, et redessine les widgets. Vous pouvez utiliser 'root.after (millisecond, function_name)' pour exécuter une fonction périodiquement et "simuler" 'while' en boucle. Ou vous pouvez utiliser 'root.update()' dans votre boucle pour obliger mainloop à faire une boucle. – furas
Mais pourquoi la boucle while bloque le mailnoop si je l'ai placé dans un nouveau thread? Si j'ai compris votre réponse avec votre commande en théorie, je pourrais supprimer le fil droit? –
exemple simple: [lecture série dans tkinter] (https://github.com/furas/my-python-codes/blob/master/tkinter/read-serial-port/main.py) – furas