作者: 機械伯爵
日時: 2002/5/23(16:41)
 え〜採点中の機械です。

 バケガクの計算なんかでは、RPN電卓が非常に使いやすいのですが、
私はHP200LXのRPN計算機モードなので、携帯には便利なのですが、
大量計算するには、やっぱキーがちょっと小さい・・・

 ということで、Tkinterの習作として、簡単なRPNを作ってしまいま
した。

--^ rpn_v01
# RPN Calculator ver 0.1
# グローバル変数を多用する、非常に汚いコード
# クラスにして、対処する予定

stack=[]
inputStr=""
tempValue=0
newLine=0

def push(str):
  stack.append(str)

def pop():
  if not stack.__len__():
    return "0"
  else:
    return stack.pop()

from Tkinter import *

root = Tk()
root.title("RPN Calculator")
canvas = Canvas(root,width=480,height=360,bg="black")

def setText(txt,x,y):
  canvas.create_text(x,y,text=txt,
    fill="white",
    anchor=NE,
    font = "Helvetica 15 bold"
  )

def alert(txt): # 不正入力に対する警告
  canvas.create_text(
    10,10,text=txt,
    fill="RED",
    anchor=NW,
    font = "Helvetica 15 bold"
  )

def showDisplay():
  canvas.delete(ALL)
  if stack.__len__() > 3:
    setText(stack[-4],450,50)
  else:
    setText("0",450,50)

  if stack.__len__() > 2:
    setText(stack[-3],450,100)
  else:
    setText("0",450,100)

  if stack.__len__() > 1:
    setText(stack[-2],450,150)
  else:
    setText("0",450,150)

  if stack.__len__() > 0:
    setText(stack[-1],450,200)
  else:
    setText("0",450,200)
  canvas.create_line(10,230,470,230,fill="white")
  if inputStr=="":
    setText("0",450,250)
  else:
    setText(inputStr,450,250)

def allClear(event): # スタック内部をクリア
  global stack
  global inputStr
  stack = []
  inputStr = ""
  showDisplay()


def enterValue(event): # Enterキーによるスタック積み
  global newLine
  push(inputStr)
  newLine = 2
  showDisplay()


def calc(opr): # 演算キーの処理
  global inputStr
  global newLine
  if not (((inputStr == "") or (inputStr == "0")) and opr =="/"):
    e = "tempValue=" + pop() + opr + inputStr
    exec e
    inputStr = str(tempValue)
    newLine = 1
    showDisplay()
  else:
    alert("ZERO DIVIDE!")

def backSpace(event): # 入力文字の1文字消去
  global inputStr
  if inputStr:
    inputStr = inputStr[:-1]
    showDisplay()

def deleteKey(event): # 入力行の消去
  global inputStr
  inputStr = ""
  showDisplay()

def change(event): # Zキーによる、Entry行とTOSの交換
  global newLine
  global inputStr
  stack[-1],inputStr = inputStr,stack[-1]
  newLine = 1
  showDisplay()

def inputCharacter(event): # キー入力ルーチン
  global newLine
  global inputStr
  if event.char in "0123456789xXabcdefABCDEF.":
    if newLine:
      if newLine == 1:
        if inputStr <> "":
          push(inputStr)
      inputStr = ""
      newLine = 0
    inputStr = inputStr + event.char
    showDisplay()
  elif event.char in "+-*/":
    calc(event.char)
  else :
    alert()

canvas.bind("<Escape>",allClear)
canvas.bind("<Return>",enterValue)
canvas.bind("<BackSpace>",backSpace)
canvas.bind("<Delete>",deleteKey)
canvas.bind("<z>",change)
canvas.bind("<Key>",inputCharacter)
import sys
canvas.bind("<Home>",sys.exit)
canvas.pack()
showDisplay()
canvas.focus_set()
root.mainloop()
--$

 はっきり言えば、まだ「なんとか動く」段階で、挙動不審に陥る
バグも残ってますが、やっつけスクリプトなんてこんなもん
でしょう。

 書き出してから気がついたのは、globalキーワードを多用すること。

 これはもう、典型的な「ヤバいスクリプト」なので、採点が終わり
次第、クラスベースの全面改訂版を作ってみようと思います。

※450とかのマジックナンバーもなんとかしたいですね

 あと、スクリプトらしい面白いトコといえば、計算をexec文で行
っているので、16進法だろうが8進法だろうが、省略浮動小数点表記
だろうが(.5を0.5として評価されるなんて、知らなかった・・・)
結構ファジーに計算できることです。

 ・・・今のところ結果は全て10進法ですが・・・

 採点からの逃避で作り出した(をい)スクリプトですが、手を入れて
いじっていくと結構面白いかもしれません。

 ・・・んでも、採点はちっともすすまん・・・

   「今夜は徹夜か?(泣)」機械伯爵