【发布时间】:2016-11-24 09:09:44
【问题描述】:
我确信这是你见过的最糟糕的代码之一,但这是我的第一个面向对象的程序。 该程序应与 Arduino 通信以收集有关太阳能电池板和一些电池的信息。它还必须自动管理一些逆变器等。 我已经删除了大部分 GUI 以使代码更易于阅读,但它仍然很大。 我尝试编写的代码是,一旦串行通信开始,我就可以更改 GUI 上的参数,我试图通过打开一个在后台工作并收集或发送数据的新线程来实现这一点。 实际发生的情况是,一旦串行通信启动,GUI 就会冻结,然后一切都会崩溃。 我在线程中添加了一个 print 来检查通信是否开始,并且实际上在 python chrashes 之前从串行端口收集了一些信息。
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在 Tkinter(和任何其他 GUI)中执行任何操作 - 它获取键/鼠标事件,将其发送到小部件,更改数据小部件,并重绘小部件。您可以使用root.after(millisecond, function_name)定期运行某些功能并“模拟”while循环。或者您可以在循环中使用root.update()来强制 mainloop 执行一个循环。 -
但是如果我将它放在一个新线程中,为什么 while 循环会阻塞 mailnoop?如果我从理论上理解您的命令的答案,我可以删除线程吗?
标签: python multithreading user-interface arduino serial-communication