PySimpleGui (Python GUI) で基底変換(2進数、8進数、10進数、16進数)アプリ作成

Python

はじめに

PySimpleGUIは、Python用のGUIライブラリです

これを使用して、16ビットの基底(2進数、8進数、10進数、16進数)を変換するアプリを作成しました。

インストールと実行方法

ダウンロード

ソースは、https://github.com/tostos5963/PySimpleGUI-BaseConverter で公開していますので以下のどちらかの手順でダウンロードしてください。

git clone

git clone https://github.com/tostos5963/PySimpleGUI-BaseConverter.git

URL部は github のサイトで、①[Code]押下 → ②URL コピー を押下したらクリップボードにコピーできます。

ZIPファイル

①[Code]押下 → ② [Download ZIP]押下で、ZIPファイルをダウンロードできます。ダウンロードしたら任意のフォルダに展開してください。

Windowsの場合

pip install pysimplegui
python BaseConverter.py

Linux (ubuntu)の場合

pip3 install pysimplegui
python3 Sliding15Puzzle.py

以下のエラーが出た場合

ModuleNotFoundError: No module named 'tkinter'

python3-tk をインストールしてください

sudo apt-get install python3-tk

Macの場合

すみません。動作すると思いますがMacを所持していないため確認できていません。

使用方法

  1. 10進数を入力できます。[+]押下で+1、[-]押下で-1 します。
  2. 2進数を表示します。
  3. 8進数を表示します。
  4. 16進数を表示します。
  5. 2進数を変更できます。押下すると[0]~[1]が順に変化します。
  6. 8進数を変更できます。押下すると[0]~[7]が順に変化します。
  7. 16進数を変更できます。押下すると[0]~[F]が順に変化します。

ソースコード

主な処理の説明です。

初期処理

    def __init__(self):
        self.dec_value = 0

        # 正規表現 (Regular expression):[+][-] button KEY
        self.sign_btn_pattern = re.compile(r'dec-(?P<SIGN>plus|minus)')

        # 正規表現 (Regular expression):numeric button KEY
        self.value_btn_pattern = re.compile(r'^(btn|inp)-(?P<BASE>bin|oct|hex|dec)-(?P<POS>\d+)')

        bit_frame_list = []
        bit_frame_list.append(sg.Frame("BIT", [
                        [sg.Text("BIN:")],
                        [sg.Text("OCT:")],
                        [sg.Text("HEX:")]], title_location=sg.TITLE_LOCATION_TOP))

        # 数値 button を作成
        oct_idx = 5     # OCT 6桁 = 5 4 3 2 1 0
        hex_idx = 3     # HEX 4桁 = 3 2 1 0
        for bit in reversed(range(16)):
            # BIN button : 1 bit
            btn_bit = sg.Button('0', size=(1,1), key="btn-bin-{:d}".format(bit), enable_events=True, button_color=('#000000','#ffffff'))

            if (bit % 3) == 0:
                # OCT button : 3 bits 毎に作成
                btn_oct = sg.Button('0', size=(1,1), key="btn-oct-{:d}".format(oct_idx), button_color=('#000000','#ffffff'))
                oct_idx = oct_idx - 1
            else:
                # OCT button が不要なビット位置にも無効 button を作成(無いとFrame()内の button 位置がビット毎にずれる)
                btn_oct = sg.Button(' ', size=(1,1), key="oct{:d}".format(bit), disabled=True, button_color="#64778d")

            if (bit % 4) == 0:
                # HEX button : 4 bits 毎に作成
                btn_hex = sg.Button('0', size=(1,1), key="btn-hex-{:d}".format(hex_idx), button_color=('#000000','#ffffff'))
                hex_idx = hex_idx - 1
            else:
                # HEX button が不要なビット位置にも無効 button を作成(無いとフレーム()内の button 位置がビット毎にずれる)
                btn_hex = sg.Button(' ', size=(1,1), key="hex{:d}".format(bit), disabled=True, button_color="#64778d")

            # Frame(1bit : BIN, OCT, HEX) を作成
            bit_frame_list.append(sg.Frame("{:>2d}".format(bit), [[btn_bit], [btn_oct], [btn_hex]],
                title_location=sg.TITLE_LOCATION_TOP, element_justification='center'))

        # DEC: テキストフィールドの変更イベントが必要なので Spin ではなく Input を使用
        #      Spin → (Input, [+], [-])  (need to fire the text field change event)
        self.layout = [[sg.Text("DEC:"), sg.Input('', size=(7, 1), key="inp-dec-0", enable_events=True),
                        sg.Button('+', key="dec-plus"), sg.Button('-', key="dec-minus")],
                       [sg.Text("BIN:"), sg.Text('', key="disp-bin")],
                       [sg.Text("OCT:"), sg.Text('', key="disp-oct")],
                       [sg.Text("HEX:"), sg.Text('', key="disp-hex")],
                       bit_frame_list,
                       [sg.Button('Exit')] ]

        self.window = sg.Window('BaseConverter', self.layout)

dec_value は入力された数値を保持する変数です。

sign_btn_pattern は10進数の[+][-]のどちらを押下されたか判断するための正規表現です。

value_btn_pattern は、2進数、8進数、16進数のどのボタンを押下されたか、または10進数の数値が変更されたかを判断するための正規表現です。

layout はウィンドウに表示する エレメント(ウィジェット)のリストです。

window は、PySimpleGUIのWindow です。タイトル名とlayoutを設定しています。

値更新とボタン表示更新(2進数)

    # BIN: Text と button を更新
    def update_bin(self):
        # BIN Text 更新
        self.window['disp-bin'].Update("{:>b}".format(self.dec_value))

        # BIN の各 button 更新
        mask = 0x0001
        for bit in range(16):
            key = "btn-bin-{:d}".format(bit)

            if (self.dec_value & mask) == 0:
                bit_str = "0"
            else:
                bit_str = "1"

            if self.window[key].ButtonText != bit_str:
                self.window[key].Update(bit_str)

            mask = mask << 1

保持している値 (dec_value)を2進数(テキスト/ボタン)に反映します。

同様に、update_oct()は8進数、update_hex()は16進数、update_dec()は10進数のテキスト/ボタンに反映します。

2進数のボタンを押下したときの処理

    def onclick_bin(self, pos):
        # BIN button (0 → 1)(1 → 0)
        key = "btn-bin-{:d}".format(pos)
        if self.window[key].ButtonText == '0':
            self.window[key].Update("1")
        else:
            self.window[key].Update("0")

        # BIN buttons → number (ボタンの0/1 を並べて BIN 文字列を作成)
        num_str = ""
        for bit in reversed(range(16)):
            key = "btn-bin-{:d}".format(bit)
            num_str = num_str + self.window[key].ButtonText

        self.dec_value = int(num_str, 2)

        self.window['disp-bin'].Update("{:>b}".format(self.dec_value))

        self.update_oct()
        self.update_dec()
        self.update_hex()

引数の pos は何番目のボタンを押下されたかを表します。一番右が0で一番左が15です。

押下されたボタンの数字が[0]であれば[1]に、[1]であれば[0]にします。

2進数のボタンから2進数の文字列を作成しint()で数値変換したものを dec_value に設定します。

2進数(テキスト)を更新し、他の基底(8進数、10進数、16進数)の更新処理(update_oct(), update_dec(), update_hex() )を呼び出します。

同様に、onclik_oct()は8進数、onclik_hex()は16進数のボタンが押下された時の処理、onchange_dec()は 10進数の値が変更されたときの処理です。

10進数の [+] または [-] が押下された時の処理

    # DEC [+] or [-]
    def onchange_plus_minus(self, dec_num_str, sign):
        try:
            d_val = int(dec_num_str)
            if sign == 'plus':
                # [+] button = 10進数を + 1
                d_val = d_val + 1
                if (d_val > 0xFFFF):
                    d_val = 0xFFFF
            else:
                # [-] button = 10進数を - 1
                d_val = d_val - 1
                if (d_val < 0):
                    d_val = 0
        except:
            d_val = self.dec_value

        # DEC 表示
        if (dec_num_str != str(d_val)):
            self.window["inp-dec-0"].Update(str(d_val))

        if self.dec_value != d_val:
            self.dec_value = d_val
            self.update_bin()
            self.update_oct()
            self.update_hex()

引数 dec_num_str は10進数テキスト、sign は符号([+]=’plus’, [-]=’minus’)です。

dec_num_str を数値変換し、sign が ‘plus’ の場合は +1、’minus’ の場合は -1 します。+1したときに 0xFFFFを超えた場合は 0xFFFF に、-1したときに0未満になった場合は 0 にします。

値が変更されたら10進数のテキスト部更新、変更後の値を dec_value に保持し、 他の基底(8進数、10進数、16進数)の更新処理(update_oct(), update_dec(), update_hex() )を呼び出します。

メインループ

    def main_loop(self):
        while True:
            event, values = self.window.read()
            if event in (sg.WIN_CLOSED, 'Exit'):
                break

            # [+][-] button ?
            m = self.sign_btn_pattern.match(event)
            if m:
                self.onchange_plus_minus(values["inp-dec-0"], m.group('SIGN'))
                continue

            # numeric button ?
            m = self.value_btn_pattern.match(event)
            if m:
                base_type = m.group('BASE')     # 基底
                pos = int(m.group('POS'))       # button 位置

                if base_type == 'dec':
                    self.onchange_dec(values[event])

                elif base_type == 'bin':
                    self.onclick_bin(pos)

                elif base_type == 'oct':
                    self.onclick_oct(pos)

                elif base_type == 'hex':
                    self.onclick_hex(pos)

        self.window.close()

イベントの内容により各処理を呼び出します。

Exitボタン押下 : 終了

[+][-]ボタン押下 : onchange_plus_minus()

10進数テキスト変更 : onchange_dec()

2進数ボタン押下: onclick_bin()

8進数ボタン 押下: onclick_oct()

16進数ボタン 押下: onclick_hex()

まとめ

今回は、PySimpleGUIを使って、基底変換アプリを作成しました。

コメント

タイトルとURLをコピーしました