目次
Kivy と Python で電卓を作る:概要
Kivy と Python で電卓を作る:方針
Kivy と Python で電卓を作る:基本部分の作成←イマココ
Kivy と Python で電卓を作る:電卓機能の追加
3. ボタンと表示部分の実装
今回から実装.
- 必要なボタン類の作成
- 数字や記号の入力ができる
- 表示が更新される
完成したらこんなふうになります.
3-1. ファイル構成
Kivy_Calculator
|- Documents:原稿入れ
|- Layout:レイアウト関連のファイル
| |- Calculator.kv
| `- CalculatorMain.py
|- Params:数値の設定ファイル
| `- CalcParams.py
|- Button.py
`- CalculatorApp.py:電卓メイン App
レイアウトと数値の設定は別ファイルに分ける.
数値を直書き(マジックナンバーね)しないようにすると後々の修正が楽にできる.
3-3. CalculatorApp.py
電卓アプリ起動に使うファイル.
CalculatorMain.py と分けたのは, 初期起動時に色々設定したい! となったときに分けた方がシンプルになるため.
つまり, 今回は分ける意味はそこまででもない.
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from Layout.CalculatorMain import CalculatorMain
Window.size = (500, 900)
Builder.load_file('Layout/Calculator.kv')
class CalculatorApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
return CalculatorMain()
if __name__ == '__main__':
CalculatorApp().run()
3-3. Calculator.kv
レイアウトを決定する kivy ファイル.
数字を表示する DisplayArea と ButtonArea を分けてみた.
分けた方がコードの見た目は良くなるのだが, 別 class となるため実装が少し面倒になる.
#:kivy 1.2.0
#:import MainParam Params.CalcParams.MainParam
#:import ButtonAreaParams Params.CalcParams.ButtonAreaParams
#:import NumberButton Button.NumberButton
#:import Operator Params.CalcParams.Operator
<CalculatorMain>:
canvas.before:
Color:
rgba: MainParam.background_color
Rectangle:
pos: self.pos
size: self.size
CalculatorLayout:
orientation: 'vertical'
size_hint: MainParam.calc_size_hint
DisplayArea:
id: display_area
size_hint: MainParam.display_area_size_hint
Label:
id: display_num
text: self.parent.display_num
ButtonArea:
id: button_area
size_hint: MainParam.button_area_size_hint
<ButtonArea>:
padding: ButtonAreaParams.outer_padding
GridLayout:
size_hint: ButtonAreaParams.button_upper_area_size_hint
cols: 4
rows: 5
ACButton:
text: 'AC'
on_press: root.reset_number()
PlusMinusButton:
text: '±'
on_press: root.reverse_number()
DeleteButton:
text: 'del'
on_press: root.delete_number()
OperatorButton:
text: '+'
on_press: root.set_operator(Operator.PLUS)
NumberButton:
text: '7'
on_press: root.add_number(self.text)
NumberButton:
text: '8'
on_press: root.add_number(self.text)
NumberButton:
text: '9'
on_press: root.add_number(self.text)
OperatorButton:
text: '-'
on_press: root.set_operator(Operator.MINUS)
NumberButton:
text: '4'
on_press: root.add_number(self.text)
NumberButton:
text: '5'
on_press: root.add_number(self.text)
NumberButton:
text: '6'
on_press: root.add_number(self.text)
OperatorButton:
text: '×'
on_press: root.set_operator(Operator.MULTIPLICATION)
NumberButton:
text: '1'
on_press: root.add_number(self.text)
NumberButton:
text: '2'
on_press: root.add_number(self.text)
NumberButton:
text: '3'
on_press: root.add_number(self.text)
OperatorButton:
text: '÷'
on_press: root.set_operator(Operator.DIVISION)
NumberButton:
text: '0'
on_press: root.add_number(self.text)
DecimalSeparatorButton:
text: '.'
on_press: root.add_decimal_separator()
OperatorButton:
text: '='
3-4. CalculatorMain.py
レイアウト関連は, Calculator.kv に記載し, 処理はこっちに書く.
from kivy.logger import Logger
from kivy.properties import StringProperty
from kivy.uix.screenmanager import Screen
from kivy.uix.boxlayout import BoxLayout
from Params.CalcParams import MainParam
class CalculatorMain(Screen):
pass
class CalculatorLayout(BoxLayout):
"""電卓のメイン部分.
"""
pass
class DisplayArea(BoxLayout):
"""電卓の表示部分.
"""
first_num = 0
second_num = 0
display_num = StringProperty('')
is_number_decimal = False
is_plus = True
def __init__(self, **kwargs):
super().__init__(**kwargs)
def add_number(self, num):
"""数値を入力する処理.
Args:
num (str): 入力された数値
"""
# 桁数を制限する処理
if len(self.display_num) < MainParam.max_digits:
# display_num が 0 で 0 が入力された場合への対処
if self.display_num == '0' and num != 0:
self.display_num = num
else:
self.display_num += num
def add_decimal_separator(self):
"""小数点を入力する処理.
"""
# 小数点が複数入力されないようにする処理
if not self.is_number_decimal:
self.display_num += '.'
self.is_number_decimal = True
def delete_number(self):
"""数値を削除する処理.
"""
# 数値が全て削除された時に 0 を表示する処理
if len(self.display_num) == 2 and self.display_num[0] == '-':
self.display_num = '0'
elif len(self.display_num) != 1:
self.display_num = self.display_num[:-1]
else:
self.display_num = '0'
def reset_number(self):
"""数値を 0 にリセットする処理.
"""
self.display_num = '0'
def reverse_number(self):
"""数値のプラスとマイナスを反転する処理.
"""
if self.is_plus:
self.is_plus = False
self.display_num = '-' + self.display_num
else:
self.is_plus = True
self.display_num = self.display_num[1:]
def set_operator(self, operator):
"""演算子を設定する処理.
Args:
operator (Enum): 演算子の種類を示す.
"""
Logger.info("Operator {} Pressed".format(operator))
class ButtonArea(BoxLayout):
"""電卓の入力・計算ボタン部分.
"""
def add_number(self, text):
"""数字の入力処理.
"""
Logger.info("Number Button {} Pressed".format(text))
self.parent.children[1].add_number(text)
def add_decimal_separator(self):
"""小数点の追加処理.
"""
Logger.info("Decimal Separator Button Pressed")
self.parent.children[1].add_decimal_separator()
def delete_number(self):
"""削除ボタン.
"""
Logger.info("Delete Button Pressed")
self.parent.children[1].delete_number()
def reset_number(self):
"""数字のリセット処理.
"""
Logger.info("AC Button Pressed")
self.parent.children[1].reset_number()
def reverse_number(self):
"""プラス・マイナスの反転処理.
"""
Logger.info("Reverse Button Pressed")
self.parent.children[1].reverse_number()
def set_operator(self, operator):
"""演算子の設定処理.
Args:
operator (Enum): 演算子
"""
Logger.info("Operator Button Pressed")
self.parent.children[1].set_operator(operator)
self.parent.children[1]
は, self (ButtonArea) の親 (CalculatorLayout) の2番目の子供 (DisplayArea) という意味.
この辺りの関係は, 素人がpython(kivy)でブロック崩しを作ってみた話②を参考にした.
Button.py に各処理を記載しても良いのだが, 入れ子構造が増えるので, self.parent.parent.parent と繋がってダサくなってしまう.
上手い書き方をご存じの方がいましたらコメントお願いします.
3-5. Button.py
Button クラスを継承して数字を入力する NumberButton と 小数点を入力する DecimalSeparatorButton を作る.
from kivy.uix.button import Button
class NumberButton(Button):
"""数字の入力ボタン."""
pass
class DecimalSeparatorButton(Button):
"""小数点の入力ボタン."""
pass
class DeleteButton(Button):
"""削除ボタン."""
pass
class ACButton(Button):
"""電源ボタン."""
pass
class PlusMinusButton(Button):
"""プラスマイナス反転ボタン."""
pass
class OperatorButton(Button):
"""演算子を設定するボタン."""
pass
3-6. CalcParams.py
設定値を記載しているだけのファイル. フォントサイズや色をまとめて書いておくと, 後々変更する時に一括で変更できて楽.
from kivy.metrics import dp
from enum import Enum
class MainParam:
# 電卓の全体に適用される設定
calc_size_hint = (1., 1.)
display_area_size_hint = (1., 280. / 900)
button_area_size_hint = (1., 620. / 900)
background_color = (58. / 255, 64. / 255, 71./ 255, 1.)
max_digits = 10
class ButtonAreaParams:
# 電卓のボタンに関する設定
outer_padding = (dp(20), dp(20), dp(20), dp(20))
button_upper_area_size_hint = (1., 500. / 620.)
button_lower_area_size_hint = (1., 120. / 620.)
class Operator(Enum):
NONE = 0
PLUS = 1
MINUS = 2
MULTIPLICATION = 3
DIVISION = 4
outer_padding = (dp(20), dp(20), dp(20), dp(20))
としているのは「20px padding してね!」と書いてもディスプレイの解像度によって padding が 20px にならないことがあるため.
4. 実行結果
5. 次回予告
次回はいよいよ, 計算処理と状態遷移を追加してゆきます.
前回:Kivy と Python で電卓を作る2:設計
次回: