0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LCD1602をraspberry pi picoで使ってみる 〜クラス解説編〜

Last updated at Posted at 2024-02-04

Hi!! 元気してるか!!?

私は!
今日も!!

元気だーーーーー!!!!

最近、お小遣いの中から raspberry pi pico の入門セット買ったから
色々思いついたものを作っている訳よ。
もう通勤時間プログラミングが楽しくて楽しくて、、、

→ それはさておき、
今日はそんな制作過程で出来上がった
pythonクラスのご紹介!!
いってみよー!

文字列だけでメニュー画面ってな話

それでは早速コード紹介

ちょっとイキってgithub使ってます。
使い方合ってんのか知らんけど

注目は、ViewContents.py

中身は下記の二つのクラス。
まず、ハードの設定やLCD1602の公式モジュールの拡張を担うのがコチラ

ViewContents.lcdControl
from LCD1602 import LCD
import machine


class lcdControl(LCD):
    def __init__(self):
        super().__init__()
        
        self.KEY_SELECT = machine.Pin(8)
        self.KEY_ENTER = machine.Pin(9)
        self._msg = ''
        
    def update(self,PageModel):
        if self.message != PageModel['ShowContents']['text']:
            self.message = PageModel['ShowContents']['text']
        else:
            self.message = self._msg
        
    @property
    def message(self):
        return self._msg
        
    @message.setter
    def message(self, text):
        self.clear()
        super().message(text)
        self._msg = text
        
    def Clicked_Select(self):
        # 継承先でオーバーライドするので空き
        pass
        
    def Clicked_Enter(self):
        # 継承先でオーバーライドするので空き
        pass

Clicked_Select Clicked_Enterは継承先でオーバーライドするので空白

lcdControl について

def __init__

ボタンのPin位置などのLCD1602以外で利用しているハードウェアの設定をまとめている。
タクトスイッチをSelect Button, Enter Button として使うのでカキカキ...

"LCD1602"の表示器の設定は、継承したLCDクラスのコンストラクタへ記載あるため
super().__init__()を用いて親クラスLCD内のdef __init__を呼び出しているから
カキカキは必要ナッスィング

def updateでは

LCD1602へ表示する文字列情報PAGEMODELを更新する。

def messageでは

@propertyで関数をプロパティ化。
そもそもは、親クラスのLCD1602.LCDで定義された関数で
LCD1602へ表示する為の関数だが
ここでオーバーライドして、表示内容を変数self._msgにも反映させるようにした。
こうする事で今表示されている文字列を知りたいときに
.message でプロパティを参照すれば取得できるのだ。
まぁなんでそんな事をするかと言うと
ViewContentsが動きやすくする為とだけ言っておこう。

view_contents について

(長いので読みたい人は拡げて下さい)
ViewContents.view_contents

class view_contents():
    # horizontal displays viewer
    class select_item_card():
        def __init__(self, source, max_length=-1, before_dot=True):
            self.source = source
            self._slctd = False
            self._before_dot = bool(before_dot)
            if max_length >= 1:
                self._max_len = int(max_length)
            else:
                self._max_len = 1
            self._txt = self.__ftext(self.source, self._max_len, self._before_dot)
            
    class num_counter_card():
        end_behavior_modelist =('cut', 'round')
        
        def __init__(self, def_num=0,start_num=None, end_num=None, end_behavior='cut'):
            if start_num == None:
                self.start_num = def_num
            else:
                self.start_num = start_num
            
            self.end_num = end_num
            self.end_behavior = end_behavior
            if isinstance(def_num, (int, float)):
                self.def_num = int(def_num)
            self._cnt = self.def_num
            
    _type_list = ['list', 'dict']
    
    def __init__(self, content, spliter=' ', title=''):
        self.spliter = spliter
        self.sel_obj = []
        self.cnt_obj = {}
        self.title = title
        self.__contents = content
        self._obj_grps = {}
        self._text = ''
        self.modal = False
        self.mode = None
        self._max_len = 16
        self.max_row = 2
        self.type = view_contents._type_list[0]
        
    def __str__(self):
        return str(self._content)
        
    @property
    def max_len(self):
        return self._max_len
        
    @max_len.setter
    def max_len(self, max_len):
        self.modal = False
        self._max_len = max_len
        
    @property
    def __contents(self):
        return self._content
        
    @__contents.setter
    def __contents(self, cont):
        if isinstance(cont, (list, tuple)):
            self._content = cont
        elif isinstance(cont, str) and self.spliter != '':
            self._content = cont.split(self.spliter)
        else:
            self._content = str(cont)
        
    @property
    def select_objects(self):
        if self.mode == 3 or self.mode == 4 or self.mode == 5:
            return self.sel_obj
        else:
            raise TypeError('please set mode-(3, 4, 5) before acsess to select_objects')
        
    @select_objects.setter
    def select_objects(self, sel_obj):
        if isinstance(sel_obj, self.select_item_card):
            self.sel_obj.append(sel_obj)
        else:
            raise TypeError('Must pass the type of select_item_card to this function')
        
    @property
    def __object_group(self):
        return self._obj_grps
        
    @__object_group.setter
    def __object_group(self, obj_no):
        _title = self.title
        if isinstance(obj_no, int):
            if obj_no == 1:
                self.mode = 1
                self._obj_grps = self.long_sentence_indence(_title)
            elif obj_no == 2:
                self.mode = 2
                self._obj_grps = self.split_sentence_indence(_title)
            elif obj_no == 3:
                self.mode = 3
                self._obj_grps = self.selection_sentence_indence(_title)
            elif obj_no == 4:
                self.mode = 4
                self._obj_grps = self.yes_no_sentence(_title)
            elif obj_no == 5:
                self.mode = 5
                self._obj_grps = self.timepicker_sentence(_title)
            else:
                self.mode = 0
                self.modal = False
                self._obj_grps = {'title': None, 'contents': [None]}
        
    def long_sentence_indence(self, title='', type='dict'):
        # title   sentssentss
        #         entssents
        if not (self.modal):
            n = self.spliter.join(self._content)
            sents = []
            sents_append = sents.append
            for i in range(0, len(n), self._max_len * self.max_row):
                s = n[i:]
                sents_append(
                        [
                                s[
                                        i:i+self._max_len
                                ] for i in range(
                                        0,
                                        self._max_len*self.max_row,
                                        self._max_len
                                        )
                        ]
                )
            if type == 'list':
                # debug used
                lsi = sents
            elif type == 'dict':
                lsi = {'title': title, 'contents': sents}
            return lsi
        
    def split_sentence_indence(self, title='', type='dict'):
        # title   sents
        #         sents
        #
        #
        if not (self.modal):
            cont = self._content
            sents = []
            xxx = []
            xxx_append = xxx.append
            for x in cont:
                if len(x) <= self.max_len:
                    xxx_append(x)
                else:
                    xxx_append(x[:self.max_len])
                    xxx_append(x[self.max_len:])
            sents = [xxx[i:i+self.max_row] for i in range(0, len(xxx), self.max_row)]
            if type == 'list':
                # debug used
                splt_si = sents
            elif type == 'dict':
                splt_si = {'title': title, 'contents': sents}
            return splt_si
        
    def selection_sentence_indence(self, title='', type='dict'):
        # title   •sl_1 •sl_2
        #         •sl_3 •sl_4
        
        if not (self.modal):
            self.sel_obj = []
            tc = []
            card_len = int(self._max_len / 2)
            
            for x in self._content:
                self.select_objects = self.select_item_card(x, card_len, True)
        gg = ''.join(
                [
                        f'{g.text}\n' if i % 2 == 1 and i + 1 != len(self.sel_obj) else f'{g.text}'
                        for i, g
                        in enumerate(self.sel_obj)
                ]
        )
        tc = gg.split('\n')
        selects = [tc[i:i+2] for i in range(0, len(tc), 2)]
        if type == 'list':
            # debug used
            slct_si = selects
        elif type == 'dict':
            slct_si = {'title': title, 'contents': selects}
        return slct_si
        
    def yes_no_sentence(self, title='', type='dict'):
        # title   •yes •no
        con = self.spliter.join(self._content)
        if not (self.modal):
            y = 'yes'
            n = 'no'
            self.sel_obj = []
            if self.max_row <= 1:
                card_len = 1
            else:
                card_len = int(self._max_len / 2)
            y_card = self.select_item_card(y, card_len, False)
            n_card = self.select_item_card(n, card_len, False)
            self.select_objects = y_card
            self.select_objects = n_card
        selects = []
        selects_append = selects.append
        x = []
        x_append = x.append
        
        if len(title) >= self.max_len:
            x_append(f'{con[:self.max_len - 1]}')
        else:
            x_append(f'{con[:self.max_len]}')
        
        gg = ''.join(
                [
                        f'{g.text}' for g in self.sel_obj
                ]
        )
        
        x_append(f'{gg: >{self.max_len}}')
        selects_append(x)
        
        if type == 'list':
            # debug used
            slct_si = selects
        elif type == 'dict':
            slct_si = {'title': title, 'contents': selects}
        return slct_si
        
    def timepicker_sentence(self, title='', type='dict'):
        # title  Time hh:mm
        #            u/d/nx
        #
        if not (self.modal):
            self.cnt_obj = {}
            self.cnt_obj['tp_h'] = (
                    self.num_counter_card(
                            def_num=0,
                            start_num=0,
                            end_num=24,
                            end_behavior='round'
                    )
            )
            self.cnt_obj['tp_m'] = (
                    self.num_counter_card(
                            def_num=0,
                            start_num=0,
                            end_num=60,
                            end_behavior='round'
                    )
            )
            self.sel_obj = []
            u_card = self.select_item_card('u', 1, False)
            d_card = self.select_item_card('d', 1, False)
            E_card = self.select_item_card('E', 1, False)
            self.select_objects = u_card
            self.select_objects = d_card
            self.select_objects = E_card
        
        __X = lambda tl, hr, mn: f'{tl} {hr}:{mn:0>2}'
        selects = []
        selects_append = selects.append
        x = []
        x_append = x.append
        x_append(
                __X(
                        'Time',
                        self.cnt_obj['tp_h'].text,
                        self.cnt_obj['tp_m'].text
                )
        )
        
        x_append(
                ''.join(
                        [
                                f'{g.text}' for g in self.select_objects
                        ]
                )
        )
        
        selects_append(x)
        
        if type == 'list':
            # debug used
            slct_si = selects
        elif type == 'dict':
            slct_si = {'title': title, 'contents': selects}
        return slct_si
        
    def fstr(self, modal, mode, page=0):
        _title = ''
        _page_num = page
        self.modal = modal
        if isinstance(mode, int):
            self.mode = mode
            self.__object_group = self.mode
            
            con1 = self.__object_group
            con2 = '\n'.join(con1['contents'][_page_num])
            con = con2
            if con1['title'] != '':
                _title = con1['title'] + ('\n' * self.max_row)
            padding = ' '
            ln = self._max_len
            self._text = f'{con:{padding}>{ln}}'
        else:
            raise ValueError(f'mode requires a raw integer\n"{mode}"')
        
        return {'title': _title, 'text': self._text}


スクロールご苦労様です。

細かいところは省きますが
このクラスで表示したい内容を生成していきます。

パターンはそんなに多くありませんが
自分でやりたい内容は最低限実装したつもりです!

キリナイケドネ!!!

勤め先では、残業時間の入力シートや社用車の利用時間表など
時間を記録する業務が何かと多いので
打刻システム用のCUIを作る事を想定して実装進めています。

項目選択するView要素にはselect_item_cardオブジェクト
数値をカウントするView要素にはnum_counter_card

あとは、文字列を改行含めて
長文の省略・改行・項目化・YesNoメッセージ化など
ある程度の描画テンプレートが盛り込んであります。

これらの内部クラスを使用して

  • 時刻の選択ページ
  • 四択から選択ページ
  • 保存の確認(YesNo)ページ

などなど、簡単なCUI実装を助けます。

次回!!

CUI実装編へ続く、、、!!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?