Я уверен, что это один из худших кодов, которые вы когда-либо видели, но это моя первая объектно-ориентированная программа. Эта программа должна общаться с Arduino для сбора информации о солнечной батарее и некоторых батареях. Он также будет автоматически управлять некоторыми инверторами и так далее. Я удалил большую часть графического интерфейса, чтобы сделать код немного легче читать, но он по-прежнему довольно большой. То, что я пытался скомпоновать, - это то, что после начала последовательной связи я могу изменить параметры в графическом интерфейсе, я попытался реализовать это, открыв новый поток, который работает в фоновом режиме и собирает или отправляет данные. Что на самом деле происходит, так это то, что, как только начинается последовательная связь, GUI замерзает, и через некоторое время все царапины. Я добавил печать внутри потока, чтобы проверить, начинаются ли связи и на самом деле до того, как python chrashes собирает некоторую информацию из последовательного порта.GUI Замедление при открытии темы
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()
вы не можете использовать 'while' цикл, поскольку он блокирует' mainloop' который не everething в Tkinter (и любая другая GUI) - он получает событие ключа/мыши, отправляет его виджеты, изменения данных, виджеты, и перерисовывает виджетов. Вы можете использовать 'root.after (millisecond, function_name)', чтобы периодически запускать некоторую функцию и «имитировать» цикл while. Или вы можете использовать 'root.update()' в своем цикле, чтобы заставить mainloop делать один цикл. – furas
Но почему цикл while блокирует mailnoop, если я поместил его в новый поток? Если бы я правильно понял ваш ответ с вашей командой, я мог бы правильно удалить нить? –
простой пример: [прочитать серийный номер в tkinter] (https://github.com/furas/my-python-codes/blob/master/tkinter/read-serial-port/main.py) – furas