Hi!! 元気してるか!!?
私は!
今日も!!
元気だーーーーー!!!!
最近、お小遣いの中から raspberry pi pico の入門セット買ったから
色々思いついたものを作っている訳よ。
もう通勤時間プログラミングが楽しくて楽しくて、、、
→ それはさておき、
今日はそんな制作過程で出来上がった
pythonクラスのご紹介!!
いってみよー!
文字列だけでメニュー画面ってな話
それでは早速コード紹介
ちょっとイキってgithub使ってます。
使い方合ってんのか知らんけど
注目は、ViewContents.py
中身は下記の二つのクラス。
まず、ハードの設定やLCD1602の公式モジュールの拡張を担うのがコチラ
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
について
(長いので読みたい人は拡げて下さい)
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実装を助けます。