ちょっとだけGUIを書こうと。。
COMポートを読んで来て、表示させるだけなんですが。。 表示とCOM取得を同時に並列で動かさないと。。コマンドラインにprintするだけなら。。だーっと表示できるものが、GUIだと。。それぞれマルチスレッドで動かさないとだめなんですね(笑)当たり前だけど。。
import threading
って入っているコードがあって。。やっと気づいた(笑)
でも。。
import concurrent.futures
というのもあって。。どっちなのかな?と。。
Threading
https://docs.python.org/ja/3/library/threading.html
こちらは、Threadingを使う方法。。stackoverflowで見つけた回答を動くように改変。コムポートなどの設定と、ser.writeやreadでUTF-8 を asciiと変えてます。
https://stackoverflow.com/questions/65887942/button-problem-in-multi-threading-python-tkinter-serial-monitor
コード自体 赤字のところが threadingに関係するところ
import threading from tkinter import * import tkinter as tk import serial root = tk.Tk() COM = "COM4" ser = serial.Serial(port=COM, baudrate=57600, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, timeout=2) ser.isOpen() msg = "" # read Serial def ReadSerial(): global msg msg = "" msg = ser.readline()[:-2].decode("ascii") if msg != "": print(msg) return msg # write Serial def WriteSerial(sendmsg): print("send") ser.write(bytes(sendmsg, 'ascii')) ReadSerial() # Tkinter root.title("WIP NAME") root.geometry("650x400") inputData = Entry(root, text="<Slave1&p>") # input for enter the message to write entrymsg = inputData.get() # get the massage buttonMsg = Button(root, text="send", command = lambda: WriteSerial(inputData.get())) # create a send button for send the message readData = Label(root, text=msg) # show message in Tkinter ReadSerial() # show items inputData.grid() readData.grid() buttonMsg.grid() # GUI thread def TkinterGui(): while 1==1: global msg entrymsg = inputData.get() # Serial thread def SerialProgram(): global msg while 1==1: ReadSerial() readData["text"]=msg readData.update_idletasks() x = threading.Thread(target=TkinterGui, args=()) y = threading.Thread(target=SerialProgram, args=()) x.start() y.start() root.mainloop()
どうやら・・ 関数を定義して、TkinterGuiの関数と、SerialProgramを、スレッドですよって宣言して、それらをスタートさせると、それぞれが同時に動くって感じですね。
Tkinter に作った Labelに受信した値を表示させるってことなんですが、こういう風にしないとTkinter(画面)に反映されないんですよね。。
わかりやすい。
他の例も。。
Concurrent.futures
どうも。。これは、非同期実行ができるようです。順番にするというより、同時に動いている感じですかね?表現方法違いかも? よくわかってないけど。。 受信と送信を別プロセスで動かす感じです。
https://docs.python.org/ja/3/library/concurrent.futures.html
コードの例は、こちらから。。
import serial import time import concurrent.futures ser = serial.Serial('COM4',57600,timeout=None) def func1(): while True: line = ser.readline() print(line) def func2(): while True: flag=bytes(input(),'utf-8') ser.write(flag) if(flag==bytes('a','utf-8')): break; time.sleep(1) ser.close() if __name__ == "__main__": executor = concurrent.futures.ThreadPoolExecutor(max_workers=2) executor.submit(func1) executor.submit(func2)
こちらも使い方は同じような感じですね。
Afterを使ってるのもある。
こんなのもありますね。
インターバルを自分自身で用意して、1秒に一回づつしか通信しないようにしてます。
なるほど。。って。。この場合、Tkinter部分のループと同時に動いているってことかな?
https://www.texio.co.jp/uploads/WebExpo/Study/Study_0001/python0001.html
並行処理と並列処理
ここに綺麗にまとまっているのがありました。
https://zenn.dev/ryo_kawamata/articles/python-concurrent-thread
https://srbrnote.work/archives/5776
thread(時分割) と Process(CPU並列) を同じような感じで使えるようにしたのが、concurrent.futures って感じですかね。
TkinterとSerialを同時に使うって、めんどくさいな(笑) どっちもループで動いているので処理の受け渡しが必要ってことですね。
昔のVB6.0とかでやってた時ってこんな処理してたっけ??(笑) ってやってたような気がする(笑) 通信しだすと、ボタン受け付けな~いって。。そういえば。。って思い出した(笑)
コメントを残していただけるとありがたいです