これはあなたが見たことのある最悪のコードの1つだと確信していますが、これが私の最初のオブジェクト指向プログラムです。 このプログラムは、Arduinoと通信して、ソーラーアレイとバッテリに関する情報を収集する必要があります。また、いくつかのインバータなどを自動的に管理する必要があります。 私はコードを少し読みやすくするためにGUIの大部分を削除しましたが、それはまだかなり大きいです。 私がコードしようとしたことは、シリアル通信が開始されてからGUIのパラメータを変更できるようにすることです。バックグラウンドで動作し、データを収集または送信する新しいスレッドを開くことでこれを実現しようとしました。 実際には、シリアル通信が開始されるとすぐにGUIがフリーズし、しばらくしてからすべてが狂ってしまいます。 スレッド内に印刷を追加して、通信が開始されているかどうか、実際にはPythonがシリアルポートから情報を収集する前に確認します。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()
- それは、キー/マウスイベントを取得し、ウィジェットに送信し、ウィジェットの変更データを、ウィジェットを再描画します。 'root.after(millisecond、function_name)'を使って定期的にいくつかの関数を実行し、 'while'ループを"シミュレート "することができます。あるいは、ループで 'root.update()'を使ってmainloopに1つのループを強制することもできます。 – furas
しかし、私が新しいスレッドに配置した場合、なぜwhileループがmailnoopをブロックするのですか? 理論上のあなたのコマンドであなたの答えを理解できたら、スレッドを正しく取り除くことができましたか? –
簡単な例:[シリアルをtkinterで読む](https://github.com/furas/my-python-codes/blob/master/tkinter/read-serial-port/main.py) – furas