A Simple Calculator


Google site search

ContentsIntroductionBasicIntermediateAdvancedFuturePolicyInfrastructure

1   A Simple Calculator        NEW May 2006

This project follows similar steps to the text widget. Here the GUI (Graphical User Interface) is far more complicated requiring all the buttons that mimic the usual calculator. This are most easily packed into a frame using grid management.

You may give students the opportunity to redesign the calculator from a totally fresh viewpoint. There are other paradigms for the calculator layout such as an abacus style layout of a stack of sliders. Also look at some of the later projects in the advanced section such as the Chu Calculator for possible models.

If this project is being used in conjunction with the integer or fraction projects, then some special functions should be added such as exponential, factorial and greatest common denominator for integers. For the fraction project you may wish to have a toggle button to display the number in (proper fraction form)/(decimal with recurring tail form).

The following code is for a simplest calculator that looks like a simple calculator. Now this code is actually quite complicated and the functionality is limited. But this is likely to be the kind of things that students starting out will write. Checkout this well-coded example. Notice also that this same page has a 2-line calculator. Maybe a discussion as to the efficacy of this solution is appropriate, especially considering it is programmable and has all the maths functions such as pow(3,3)->27 and can store answers in variables. Is this an appropriate solution to the problem?

As you can see, this project is not so much about the programming. Other issues dominate. But notice that these calculators were written by people who wanted to teach themselves how to program in Tcl. It is a common choice of problem because the model is so well understood.

2   Source:        

# calc - A simple calculator for use as a plug-in demo.
# Sydney R. Polk, Sun Microsystems
#
# The global variable state is used to keep track of what the user has
# done. It has several fields: Whether or not the last button was a
# CE, the current value of the expression, the current value of the
# entry window.

proc doClear {} {
    global state

    set state(entry) "0."
    set state(dot) 0
    if {$state(entrystarted) == 0} {
	set state(result) "0."
	set state(operation) ""
    }
    set state(entrystarted) 0
}

proc doDot {} {
    global state

    set state(dot) 1
}

proc doAppend {what} {
    global state

    if {$state(entrystarted) == 0} {
	set state(entry) "0."
    }

    if {[string compare $state(operation) ""] == 0} {
	set state(result) "0."
    }

    if {!($what == 0 && [string compare $state(entry) "0."] == 0)} {
	set state(entrystarted) 1
        if {$state(dot) == 1} {
	    set state(entry) [format "%s%s" $state(entry) $what]
	} else {
	    regexp {([-0123456789]+).} $state(entry) foo integer

	    if {[string compare $integer "0"] == 0} {
		set state(entry) [format "%s." $what]
	    } else {
		set state(entry) [format "%s%s." $integer $what]
	    }
	}
    }    
}    

proc doOperation {what} {
    global state

    if {[string compare $state(operation) ""] != 0} {
	doEqual
    }
    set state(operation) $what
    set state(result) $state(entry)
    set state(entrystarted) 0
    set state(dot) 0
}

proc doEqual {} {
    global state

    if {[string compare $state(operation) ""] != 0} {
	set state(result) \
		[expr "$state(result) $state(operation) $state(entry)"]
    } else {
	set state(result) $state(entry)
    }
    set state(entry) $state(result)
    set state(entrystarted) 0
    set state(operation) ""
    set state(dot) 0
}

proc doSign {} {
    global state

    if {[string compare $state(entry) "0."] != 0} {
	set sign ""
	set abs ""
	regexp {([-]?)([0-9.]+)} $state(entry) foo sign abs
        if {[string compare $sign "-"] == 0} {
	    set state(entry) $abs
	} else {
	    set state(entry) [format "-%s" $abs]
	}
	set state(entrystarted) 1
    }
}

set state(result) "0."
set state(entry) "0."
set state(operation) ""
set state(dot) 0
set state(entrystarted) 0

label .label -textvariable state(entry) -justify right -anchor e

foreach {number} {0 1 2 3 4 5 6 7 8 9} {
    set buttons($number) [button .$number -text $number \
	    -command "doAppend $number"]
}
set buttons(clear) [button .clear -text C/CE -padx 1 -command "doClear"]
foreach {label operation} {div / mult * minus - plus +} {
    set buttons($label) [button .$label -text $operation \
	    -command "doOperation $operation"]
}
set buttons(dot) [button .dot -text . -command "doDot"]
set buttons(sign) [button .sign -text +/- -padx 1 -command "doSign"]
set buttons(equal) [button .equal -text = -command "doEqual"]

grid .label -column 0 -row 0 -columnspan 4 -sticky news
grid $buttons(clear) $buttons(div) $buttons(mult) $buttons(minus) -sticky news
grid $buttons(7) $buttons(8) $buttons(9) -sticky news
grid $buttons(4) $buttons(5) $buttons(6) -sticky news
grid $buttons(1) $buttons(2) $buttons(3) -sticky news
grid $buttons(0) $buttons(dot) $buttons(sign) -sticky news
grid $buttons(plus) -column 3 -row 2 -rowspan 2 -sticky news
grid $buttons(equal) -column 3 -row 4 -rowspan 2 -sticky news

Prev 

©2000 - 2006 WEBSCOOL This page last updated 31 May 2006. All rights reserved - including copying or distribution of any portion of this document in any form or on any medium without authorisation. For more regarding the copyright.