とゆーわけで、まぁ、そこそこのあたりに安定したと思われる
のをアップしときます。
前回と違い、クラスで作ったので、まぁ前よりはマシかと思われ
ますが、グローバルフィールドで式評価するなど、相変わらず
デンジャラスなことを一部行っております。
ホントはもう少し機能をつけるつもりだったのですが、現在は
コレが精一杯(特に16進表示に手間取りすぎた・・・)
--^ rpn_v09.py
"""
逆ポーランド式計算機 ver. 0.9
<仕様>
+-*/ 四則演算
Enter スタックプッシュ
Delete 入力行クリア
BS 入力行1文字削除
Home 内部スタック及び入力行全クリア
End 計算機プログラム終了
↑ 入力行とスタックトップの交換(swap)
← 整数切り捨て
→ 小数点2位
↓ 16進法表示(値は捨てられる)
L 常用対数(log10)
P power(べき乗)
R 平方根
"""
tempValue = 0
posX = 450
posY = 50
numchar="0123456789abcdefxABCDEFX."
class CalcData: # 保存内部データの殆ど
def __init__(self):
self.stack = []
self.inputStr = ""
self.tempValue = 0
self.newLine = 0
# スタック関連のメソッド
# スタックプッシュ
def push(self,str=None):
if str==None:
if self.inputStr == "":
self.stack.append("0")
else:
self.stack.append(self.entryLineDisplay())
else:
self.stack.append(str)
return self
# スタックポップ
def pop(self):
if self.stack.__len__():
return self.stack.pop()
else:
return "0"
# スタックの長さ
def len(self):
return self.stack.__len__()
# スタックアイテムの参照
def __getitem__(self,key):
return self.stack[key]
# スタックアイテムの代入
def __setitem__(self,key,value):
self.stack[key] = value
# スタックトップと入力行の入れ替え
def swap(self):
if self.len():
self[-1] , self.inputStr = self.inputStr , self[-1]
def clearStack(self):
self.stack = []
return self
def str(self,txt=None):
if txt==None:
return self.inputStr
else:
self.inputStr = txt
return self
def flag(self,n=None):
if n == None:
return self.newLine
else:
self.newLine = n
def str_empty(self):
if self.str() == "" or self.str() =="0":
return 1
else:
return 0
def backDelete(self):
if self.inputStr:
self.inputStr = self.inputStr[:-1]
def clearLine(self):
self.inputStr = ""
return self
def addChar(self,c):
self.inputStr = self.inputStr + c
return self
def entryLineDisplay(self):
if self.str() == "":
return "0"
else:
return cd.str()
cd = CalcData()
import Tkinter as tk
import sys,math
class DisplayView:
def setText(self,txt,x,y):
txtId = self.canvas.create_text(
x,y,text=txt,
fill = "green",
anchor = tk.NE,
font = "Helvetica 15 bold"
)
return txtId
def alert(self,txt):
self.canvas.create_text(
10,10,text=txt,
fill = "red",
anchor = tk.NW,
font = "Helvetica 15 bold"
)
def show(self):
self.canvas.delete(tk.ALL)
if cd.len() > 3:
self.setText(cd[-4],posX,posY)
else:
self.setText("0",posX,posY)
if cd.len() > 2:
self.setText(cd[-3],posX,(posY * 2))
else:
self.setText("0",posX,(posY * 2))
if cd.len() > 1:
self.setText(cd[-2],posX,(posY * 3))
else:
self.setText("0",posX,(posY * 3))
if cd.len() > 0:
self.setText(cd[-1],posX,(posY * 4))
else:
self.setText("0",posX,(posY * 4))
self.canvas.create_line(
10,230,470,230,fill="green"
)
self.setText(
cd.entryLineDisplay(),
posX,
(posY * 5)
)
def allClear(self,event):
cd.clearStack().clearLine()
self.show()
def enterValue(self,event):
cd.push()
cd.flag(2)
self.show()
def calc(self,opr):
if cd.str_empty() and opr=="/":
self.alert("ZERO DIVIDE!")
else:
e = "tempValue=0.0+" + cd.pop() + opr + cd.entryLineDisplay()
exec e
cd.str(str(tempValue))
cd.flag(1)
self.show()
def backSpace(self,event):
cd.backDelete()
self.show()
def deleteKey(self,event):
cd.clearLine()
self.show()
def swap(self,event):
cd.swap()
cd.flag(1)
self.show()
def math_ex(self,action):# 数学拡張(LISP?)
cd.str(
str(
action(
float(
cd.entryLineDisplay()
)
)
)
)
cd.flag(1)
self.show()
def math_ex2(self,action):# 数学拡張(2項)
cd.str(
str(
action(
float(
cd.pop()
),
float(
cd.entryLineDisplay()
)
)
)
)
cd.flag(1)
self.show()
def format_ex(self,format):
cd.str(
str(
format % float(
cd.entryLineDisplay()
)
)
)
cd.flag(1)
self.show()
def intform(self,event):
self.format_ex("%i")
def f2form(self,event):
self.format_ex("%.2f")
def hexform(self,event):
self.format_ex("%x")
cd.clearLine()
# 数値や四則・論理演算子の処理
def inputCharacter(self,event):
if event.char in numchar:
if cd.flag():
if cd.flag()==1:
if not cd.str_empty():
cd.push()
cd.clearLine()
cd.flag(0)
cd.addChar(event.char)
self.show()
elif event.char in "+-*/":
self.calc(event.char)
elif event.char=="l":
self.mathex(math.log10)
elif event.char=="r":
self.mathex(math.sqrt)
elif event.char=="p":
self.mathex2(pow)
else:
self.alert("BAD KEY!")
def __init__(self,master): # キー割り当て
self.canvas = tk.Canvas(
master,width = 480,height=360,bg="black"
)
self.canvas.bind("<Home>",self.allClear)
self.canvas.bind("<Return>",self.enterValue)
self.canvas.bind("<BackSpace>",self.backSpace)
self.canvas.bind("<Delete>",self.deleteKey)
self.canvas.bind("<Up>",self.swap)
self.canvas.bind("<Left>",self.intform)
self.canvas.bind("<Right>",self.f2form)
self.canvas.bind("<Down>",self.hexform)
self.canvas.bind("<Key>",self.inputCharacter)
self.canvas.bind("<End>",sys.exit)
self.canvas.pack()
self.show()
self.canvas.focus_set()
# プログラム開始
root = tk.Tk()
dv = DisplayView(root)
root.mainloop()
--$
模範的なコードかどうかは疑問ですが、まぁ、出来る限り
見やすいように書いたつもりです。
画面書き換えやキーイベントバインドのパターンをいくつも
使ってますので、Tkinterはよーわからん、という方には、
もしかしたら参考になるかも、と考えています。
機械伯爵