1
3

[Python]tkinter バーコードリーダーアプリ

Last updated at Posted at 2024-08-25

目的

Pythonでバーコードリーダーアプリを作りたいと思った。
GUIとして画面が欲しいので、tkinterでバーコード読み取り結果を画面表示するアプリを考えた。

環境

・Windows11
・WSL2(Ubuntu-22.04)
・python 3.10.12
・usbipd
・バーコードリーダー(Tera HW0002)
 公式サイト : https://tera-digital.com/products/2d-barcode-scanner-hw0002-o
 Amazon : https://www.amazon.co.jp/dp/B07T9J9Q99

ポイント

・バーコードリーダー
 仮想COM設定にする。
 設定方法は公式サイトのマニュアルを参照。
・BarcodeScannerクラス
 インスタンス生成時に受信スレッドが立つ。
 データ受信時にRecieveDataHandlerを発火させる。
 RecieveDataHandlerはイベントを実行する。
・Windowクラス
 変数はtk.StringVar()で宣言する。
 宣言した変数をWidgets(Label等)に紐づける。
 変数へのアクセスはset(), get()メソッドを使う。
 変数の値を更新する関数を用意し、データ受信時にcallbackしてもらうようにイベントに追加する。

課題

・Eventクラスは改良の余地あり

ソースコード

main.py
#!/usr/bin/env python3
import serial
import tkinter as tk
import BarcodeScanner as bs

class Window:
    def __init__(self) -> None:
        root = tk.Tk()
        root.wm_title("BarcodeScanner")

        self.frame = tk.Frame(root)
        self.frame.pack(padx=150, pady=0)

        self.lName = tk.Label(text="Scan Data:")
        self.lName.pack(side="left", padx=0, pady=20)

        self.lScanData = tk.Label()
        self.lScanData.pack(side="left", padx=0, pady=20)

        self.vScanData = tk.StringVar()
        self.vScanData.set("Wait for Read")

        self.lScanData["textvariable"] = self.vScanData

    def DisplayScanData(self, data):
        self.vScanData.set(data)
        print(f"input:{self.vScanData.get()}")
        

if __name__ == "__main__":

    path = "/dev/ttyUSB0" # change value by environment
    bcs = bs.BarcodeScanner(path,
            9600,
            serial.EIGHTBITS,
            serial.PARITY_EVEN,
            serial.STOPBITS_ONE,
            3)
    
    myapp = Window()

    bcs.rEvent.AddEvent(myapp.DisplayScanData)

    myapp.frame.mainloop()
BarcodeScanner.py
import serial
import threading
import Event as ev

class BarcodeScanner:

    def __init__(self, path, br, bs, pr, sb, to):
        self.rBuffer = self.Buffer()
        self.rEvent = ev.Event()
        self.Open(path, br, bs, pr, sb, to)

    def Open(self, path, br, bs, pr, sb, to):
        self.ser = serial.Serial(path)
        self.ser.baudrate = br
        self.ser.bytesize = bs
        self.ser.parity = pr
        self.ser.stopbits = sb
        self.ser.timeout = to # sec
        self.th_rd = threading.Thread(target=self.RecieveData, daemon=True)
        self.th_rd.start()
    
    def Close(self):
        self.ser.close()
    
    def SendData(self, sd):
        self.ser.write(sd)

    def RecieveData(self):
        while True:
            if self.ser.in_waiting > 0:
                rd = self.ser.read(self.ser.in_waiting)
                self.RecieveDataHandler(rd)

    def RecieveDataHandler(self, indata:bytes):
        self.rBuffer.In(indata)
        buf = self.rBuffer.Read()
        if b'\x0D\x0A' in buf: # CRLF
            self.rEvent.ExecuteEvents(self.rBuffer.Out(endbyte=b'\x0D\x0A'))
        elif b'\x0D' in buf: # CR
            self.rEvent.ExecuteEvents(self.rBuffer.Out(endbyte=b'\x0D'))
        elif b'\x0A' in buf: # LF
            self.rEvent.ExecuteEvents(self.rBuffer.Out(endbyte=b'\x0A'))

    class Buffer:

        def __init__(self) -> None:
            self.buffer = None

        def In(self, data:bytes):
            if self.buffer is None:
                self.buffer = data
            else:
                self.buffer += data

        def Out(self, endbyte) -> bytes:
            if self.buffer is None:
                return None
            else:
                data, endbyte, over = self.buffer.partition(endbyte)
                self.Clear()
                return data
        
        def Read(self) -> bytes:
            return self.buffer

        def Clear(self):
            self.buffer = None
Event.py
class Event:

    def __init__(self):
        self.events = []
    
    def ExecuteEvents(self, data):
        if len(self.events) > 0:
            for e in self.events:
                e(data)

    def AddEvent(self, func):
        self.events.append(func)

参考

・tkinter --- Tcl/Tk の Python インターフェース — Python 3.12.5 ドキュメント : https://docs.python.org/ja/3/library/tkinter.html

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3