1,105,197 Community Members

GUI Scientific Calculator Homework

Member Avatar
tkpanther
Newbie Poster
19 posts since Feb 2010
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

Hello, it is me once more. I am using Python 2.3, and I must use Zelle's graphics class (and I must agree with many of you. Tkinter is much better). We have been tasked with creating a Graphical Scientific Calculator. In addition to the normal operators, it must contain the following buttons:
log - base 10 of display
ln - base e of display
exp - e to the display power
sin - sine of display in radians
cos - cosine of display in radians
tan - tangent of display in radians
sqrt - square root of display
1/x - reciprocal of display
X**2 - display squared
pi - append pi to display for use in successive calculations
( - append ( to display
) - append ) to display
MC - clear memory
MR - append contents of memory to display
MS - display evaluated and result copied to memory
M+ - display evaluated and result added to memory
OFF - close the calculator

I do not believe that I will have trouble calculating most of it. I am hoping someone will help me with organizing the placement of the keys in a visually pleasing manner. I am also unfamiliar with MC, MR, MS, and M+. If someone would be so kind to explain them to me, it would be appreciated. My professor simply ignored me when I asked him what exactly he meant by MC, MR, MS, M+.

The basic calculator starting code that was provided to us:

from graphics import *
from button import Button
from math import pi, e, sin, cos, tan, log, log10, exp, sqrt

class Calculator:
    # This class implements a simple calculator GUI

    def __init__(self):
        # create the window for the calculator
        win = GraphWin("calculator")
        win.setCoords(0,0,9,13.5)   #from (0,0,6,7)
        win.setBackground("slategray")
        self.win = win
        # Now create the widgets
        self.__createButtons()
        self.__createDisplay()

    def __createButtons(self):
        # create list of buttons
        # start with all the standard sized buttons
        # bSpecs gives center coords and label of buttons
        bSpecs = [(2,1,'0'), (3,1,'.'),
                  (1,2,'1'), (2,2,'2'), (3,2,'3'), (4,2,'+'), (5,2,'-'),
                  (1,3,'4'), (2,3,'5'), (3,3,'6'), (4,3,'*'), (5,3,'/'),
                  (1,4,'7'), (2,4,'8'), (3,4,'9'), (4,4,'<-'),(5,4,'C')]
        self.buttons = []
        for cx,cy,label in bSpecs:
            self.buttons.append(Button(self.win,Point(cx,cy),.75,.75,label))
        # create the larger = button
        self.buttons.append(Button(self.win, Point(4.5,1), 1.75, .75, "="))
        # activate all buttons
        for b in self.buttons:  b.activate()

    def __createDisplay(self):
        bg = Rectangle(Point(.5,12), Point(8.5,13))   #from (.5,5.5), (5.5,6.5)
        bg.setFill('white')
        bg.draw(self.win)
        text = Text(Point(4.5,12.5), "")   #from (3,6)
        text.draw(self.win)
        text.setFace("courier")
        text.setStyle("bold")
        text.setSize(12)
        self.display = text

    def getButton(self):
        # Waits for a button to be clicked and returns the label of
        #    the button that was clicked.
        while True:
            p = self.win.getMouse()
            for b in self.buttons:
                if b.clicked(p):
                    return b.getLabel() # method exit

    def processButton(self, key):
        # Updates the display of the calculator for press of this key
        text = self.display.getText()
        if key == 'C':
            self.display.setText("")
        elif key == '<-':
            # Backspace, slice off the last character.
            self.display.setText(text[:-1])
        elif key == '=':
            # Evaluate the expresssion and display the result.
            # the try...except mechanism "catches" errors in the
            # formula being evaluated.
            try:
                result = eval(text)
            except: result = 'ERROR'
            self.display.setText(str(result))
        else:
            # Normal key press, append it to the end of the display
            self.display.setText(text+key)
        
    def run(self):
        # Infinite 'event loop' to process button clicks.
        while True:
            key = self.getButton()
            self.processButton(key)

# This runs the program.
if __name__ == '__main__':
    # First create a calculator object
    theCalc = Calculator()
    # Now call the calculator's run method.
    theCalc.run()

Any suggestions would be appreciated.

Member Avatar
SgtMe
Nearly a Posting Virtuoso
1,204 posts since Oct 2009
Reputation Points: 46 [?]
Q&As Helped to Solve: 86 [?]
Skill Endorsements: 0 [?]
Featured
 
0
 

M+ is adding display to the memory
MR is recalling the memory. Ie: You do a sum and get the result 6.3322 and you need this for another sum. So, you press M+ to ad 6.3322 to the memory, then you type in the next sum. When you need 6.3322, you press the MR button, which insterts the current value of the memory (6.3322 in this case) into the display.
MC is obviously deleteing the contents of the memory (set to 0?).
I'm not sure about the difference between M+ and MS though...

Try looking at the system calculator...hope this helps!

Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

M+ does addition to existing contents in memory, MS stores there

M+   =+
MS   =
Member Avatar
tkpanther
Newbie Poster
19 posts since Feb 2010
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

Thank you for that clarification.

Essentially, pressing MS makes the value of memory become the current display? pressing M+ adds the value of the current display to memory? MR returns the current value of memory? and MC sets the value of memory to 0?

Update for the above code:

def __createButtons(self):
        # create list of buttons
        # start with all the standard sized buttons
        # bSpecs gives center coords and label of buttons
        bSpecs = [(2.5,1,'0'), (4,1,'.'), (1,2.5,'1'), (2.5,2.5,'2'), (4,2.5,'3'),
                   (5.5,2.5,'+'), (7,2.5,'-'), (1,4,'4'), (2.5,4,'5'), (4,4,'6'),
                   (5.5,4,'*'), (7,4,'/'), (1,5.5,'7'), (2.5,5.5,'8'), (4,5.5,'9'),
                   (5.5,5.5,'<-'),(7,5.5,'C')]
        bSpecs2 = [(1,1,'OFF'), (2.5,7,'pi'), (4,7,'('), (5.5,7,')'),
                   (7,7,'1/x'), (8.5,1,'ln'), (8.5,2.5,'log'), (8.5,4,'exp'),
                   (8.5,5.5,'sqrt'), (8.5,7,'x**2'), (1,8.5,'M+'), (2.5,8.5,'MS'),
                   (4,8.5,'MR'), (1,7,'MC'), (5.5,8.5,'sin'), (7,8.5,'cos'),
                   (8.5,8.5,'tan')]
        self.buttons = []
        #add to bSpecs
        for cx,cy,label in bSpecs:
            self.buttons.append(Button(self.win,Point(cx,cy),1.5,1.5,label))
        for cx,cy,label in bSpecs2:
            self.buttons.append(Button(self.win,Point(cx,cy),1.5,1.5,label))
        # create the larger = button
        self.buttons.append(Button(self.win,Point(6.25,1),3,1.5,"="))
        # activate all buttons
        for b in self.buttons:  b.activate()

Now, for those of you wondering why I have not placed everything in bSpecs2 inside of bSpecs, it is because I am getting error messages whenever I add anything to bSpecs.

Does anyone have any suggestions about the layout of the buttons? Or the dimensions to change to neaten it up?

Member Avatar
SgtMe
Nearly a Posting Virtuoso
1,204 posts since Oct 2009
Reputation Points: 46 [?]
Q&As Helped to Solve: 86 [?]
Skill Endorsements: 0 [?]
Featured
 
0
 

have a look at the system calculator...or just any sci-calculator

Member Avatar
tkpanther
Newbie Poster
19 posts since Feb 2010
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

OK, I think I have found a design that is 'visually appealing'. I will work on implementing the layout later.

Right now, I am having difficulties figuring out how to implement the the functions of the sin, cos, etc. In the case of sin, cos, and tan, I am getting error messages that the math class does not exist. So, I have taken those out for now.

MR, MS, MC, and M+ are also giving me trouble, but right now, I think it is just because I am drawing a blank on how to deal with memory. I will worry about them later, as the more pressing matter is getting the functions to properly process everything.

I am able to process everything else, but I can only get the display to read "ERROR". This is good for when trying to find the reciprocal of 0, square root of a negative, log of a negative, ln of a negative, or e to a large power.

The following is the code that I have so far. It only includes what I have changed from what I have posted above. I see no point in reposting the entire thing over and over again.

def processButton(self, key):
        '''        elif key == 'MS':
            self.memory == eval(text)
        elif key == 'M+':
            self.memory += eval(text)
        elif key == 'MR':
            self.display.setText(text+str(self.memory))
        elif key == 'MC':
            self.memory == 0'''   
        # Updates the display of the calculator for press of this key
        text = self.display.getText()
        if key == 'C':
            self.display.setText("")
        elif key == '<-':
            # Backspace, slice off the last character.
            self.display.setText(text[:-1])
        elif key == '=':
            # Evaluate the expresssion and display the result.
            # the try...except mechanism "catches" errors in the
            # formula being evaluated.
            if 'pi' in text:
                replace(text, pi, math.pi)
            try:
                result = eval(text)
            except:
                result = 'ERROR'
            self.display.setText(str(result))
        elif key == 'log':
            try:
                result = math.log10(eval(text))
            except:
                result = 'ERROR'
            self.display.setText(str(result))
        elif key == 'ln':
            try:
                result = math.log(eval(text))
            except:
                result = 'ERROR'
            self.display.setText(str(result))
        elif key == '1/x':
            try:
                result = 1/(eval(text))
            except:
                result = 'ERROR'
            self.display.setText(str(result))
        elif key == 'sin':
            result = math.sin(eval(text))*(180/math.pi)
            self.display.setText(str(result))
        elif key == 'cos':
            result = math.cos(eval(text))*(180/math.pi)
            self.display.setText(str(result))
        elif key == 'tan':
            result = math.tan(eval(text))*(180/math.pi)
            self.display.setText(str(result))
        elif key == 'sqrt':
            result = math.sqrt(eval(text))
            self.display.setText(str(result))
        elif key == 'exp':
            result = math.e**(eval(text))
            self.display.setText(str(result))
        elif key == 'x**2':
            result = eval(text)**2
            self.display.setText(str(result))
        elif key == 'OFF':
            self.win.close()
        else:
            # Normal key press, append it to the end of the display
            self.display.setText(text+key)

Can anyone point out just what I am screwing up that results in the display always being "ERROR"?

Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

Can't help as I have no module button and don't know how to find such.

Member Avatar
tkpanther
Newbie Poster
19 posts since Feb 2010
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

My apologies for not including the button class. Here it is:

# button.py
#    A simple Button widget.

from graphics import *

class Button:

    """A button is a labeled rectangle in a window.
    It is activated or deactivated with the activate()
    and deactivate() methods. The clicked(p) method
    returns true if the button is active and p is inside it."""

    def __init__(self, win, center, width, height, label):
        """ Creates a rectangular button, eg:
        qb = Button(myWin, Point(30,25), 20, 10, 'Quit') """ 

        w,h = width/2.0, height/2.0
        x,y = center.getX(), center.getY()
        self.xmax, self.xmin = x+w, x-w
        self.ymax, self.ymin = y+h, y-h
        p1 = Point(self.xmin, self.ymin)
        p2 = Point(self.xmax, self.ymax)
        self.rect = Rectangle(p1,p2)
        self.rect.setFill('lightgray')
        self.rect.draw(win)
        self.label = Text(center, label)
        self.label.draw(win)
        self.deactivate()

    def clicked(self, p):
        "Returns true if button active and p is inside"
        return self.active and \
               self.xmin <= p.getX() <= self.xmax and \
               self.ymin <= p.getY() <= self.ymax

    def getLabel(self):
        "Returns the label string of this button."
        return self.label.getText()

    def activate(self):
        "Sets this button to 'active'."
        self.label.setFill('black')
        self.rect.setWidth(2)
        self.active = True

    def deactivate(self):
        "Sets this button to 'inactive'."
        self.label.setFill('darkgrey')
        self.rect.setWidth(1)
        self.active = False
Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

Few observations:

math module is not imported so that's why errors from functions.

Memory is not initialized and ERROR should also have value if you use eval for evaluation. That does free you from processing yourself the braces and basic arithmetic with arithmetic logic.

However I do not think it this very friendly user interface:

7/3=
2 wrong result
25 5 key added after result
0 1/x pushed
0pi pi pushed

Key beside C is understandable.

Still some way to go.

Attachments calc.gif 10.07KB
Member Avatar
SgtMe
Nearly a Posting Virtuoso
1,204 posts since Oct 2009
Reputation Points: 46 [?]
Q&As Helped to Solve: 86 [?]
Skill Endorsements: 0 [?]
Featured
 
0
 

may I recommend that, on the design side, you seperate the buttons into blocks...it just looks a bit neater.
Good work so far and good luck!

Member Avatar
tkpanther
Newbie Poster
19 posts since Feb 2010
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

may I recommend that, on the design side, you seperate the buttons into blocks...it just looks a bit neater.
Good work so far and good luck!

I plant on doing that. I was just going to focus on making it work first. It really does not matter how pretty the calculator works if it doesn't work.

I will get back to work on this problem after my first class. I have about an hour break until my next class then...

Member Avatar
tkpanther
Newbie Poster
19 posts since Feb 2010
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

Here is my entire code to date. For whatever reason, the only value I can get for MC or M+ is 0. No matter what. I have tried a couple of different methods to initialize memory, but I only get 0 or an error message in python saying that Memory or Result is referenced before assignment. I have contacted my professor regarding this, but he has been, like before, less than helpful. He spoke about the calculator looking ugly and how I must only import the math functions I use, instead of explaining to me what I am doing wrong concerning memory. I understand that the calculator does not look pretty, but my focus right now is to have the calculator work, not have it look pretty.

We are not required to force floating point values. We are using Python calculations. If Python says that 7/3 = 2, then it is true. My professor says that this is to make this easier on us and not have to deal with String formatting.

Once I have the memory part done, I can begin working on the memory in use light.

from graphics import *
from button import Button
import math

class Calculator:
    # This class implements a simple calculator GUI

    def __init__(self):
        # create the window for the calculator
        win = GraphWin("calculator")
        win.setCoords(0,0,9,13.5)   #from (0,0,6,7)
        win.setBackground("slategray")
        self.win = win
        # Now create the widgets
        self.__createButtons()
        self.__createDisplay()
        self.memory = 0

    def __createButtons(self):
        # create list of buttons
        # start with all the standard sized buttons
        # bSpecs gives center coords and label of buttons
        bSpecs = [(2.5,1,'0'), (4,1,'.'), (1,2.5,'1'), (2.5,2.5,'2'), (4,2.5,'3'),
                   (5.5,2.5,'+'), (7,2.5,'-'), (1,4,'4'), (2.5,4,'5'), (4,4,'6'),
                   (5.5,4,'*'), (7,4,'/'), (1,5.5,'7'), (2.5,5.5,'8'), (4,5.5,'9'),
                   (5.5,5.5,'<-'),(7,5.5,'C'),(1,1,'OFF'), (2.5,7,'pi'), (4,7,'('), (5.5,7,')'),
                   (7,7,'1/x'), (8.5,1,'ln'), (8.5,2.5,'log'), (8.5,4,'exp'),
                   (8.5,5.5,'sqrt'), (8.5,7,'x**2'), (1,8.5,'M+'), (2.5,8.5,'MS'),
                   (4,8.5,'MR'), (1,7,'MC'), (5.5,8.5,'sin'), (7,8.5,'cos'),
                   (8.5,8.5,'tan')]
        self.buttons = []
        #add to bSpecs
        for cx,cy,label in bSpecs:
            self.buttons.append(Button(self.win,Point(cx,cy),1.5,1.25,label))
        # create the larger = button
        self.buttons.append(Button(self.win,Point(6.25,1),3,1.25,"="))
        # activate all buttons
        for b in self.buttons:  b.activate()

    def __createDisplay(self):
        bg = Rectangle(Point(.5,12), Point(8.5,13))   #from (.5,5.5), (5.5,6.5)
        bg.setFill('white')
        bg.draw(self.win)
        text = Text(Point(4.5,12.5), "")   #from (3,6)
        text.draw(self.win)
        text.setFace("courier")
        text.setStyle("bold")
        text.setSize(12)
        self.display = text

    def getButton(self):
        # Waits for a button to be clicked and returns the label of
        #    the button that was clicked.
        while True:
            p = self.win.getMouse()
            for b in self.buttons:
                if b.clicked(p):
                    return b.getLabel() # method exit

    def processButton(self, key):
        # Updates the display of the calculator for press of this key
        text = self.display.getText()
        result = 0
        memory = 0
        if key == 'C':
            self.display.setText("")
        elif key == '<-':
            # Backspace, slice off the last character.
            self.display.setText(text[:-1])
        elif key == '=':
            # Evaluate the expresssion and display the result.
            # the try...except mechanism "catches" errors in the
            # formula being evaluated.
            if 'pi' in text:
                replace(text, pi, math.pi)
            try:
                result = eval(text)
            except:
                result = 'ERROR'
            self.display.setText(str(result))
            
        elif key == 'log':
            try:
                result = math.log10(eval(text))
            except:
                result = 'ERROR'
            self.display.setText(str(result))
        elif key == 'ln':
            try:
                result = math.log(eval(text))
            except:
                result = 'ERROR'
            self.display.setText(str(result))
        elif key == '1/x':
            try:
                result = 1/(eval(text))
            except:
                result = 'ERROR'
            self.display.setText(str(result))
            
        elif key == 'sin':
            result = math.sin(eval(text))*(180/math.pi)
            self.display.setText(str(result))
        elif key == 'cos':
            result = math.cos(eval(text))*(180/math.pi)
            self.display.setText(str(result))
        elif key == 'tan':
            result = math.tan(eval(text))*(180/math.pi)
            self.display.setText(str(result))
            
        elif key == 'sqrt':
            result = math.sqrt(eval(text))
            self.display.setText(str(result))
        elif key == 'exp':
            result = math.e**(eval(text))
            self.display.setText(str(result))
        elif key == 'x**2':
            result = eval(text)**2
            self.display.setText(str(result))
            
        elif key == 'MR':
            self.memory = result
        elif key == 'MC':
            self.memory = 0
        elif key == 'MS':
            self.display.setText(str(result+self.memory))
        elif key == 'M+':
            result += memory
            self.display.setText(str(result+self.memory))
            
        elif key == 'OFF':
            self.win.close()
        else:
            # Normal key press, append it to the end of the display
            self.display.setText(text+key)     

    def run(self):
        # Infinite 'event loop' to process button clicks.
        while True:
            key = self.getButton()
            self.processButton(key)

# This runs the program.
if __name__ == '__main__':
    # First create a calculator object
    theCalc = Calculator()
    # Now call the calculator's run method.
    theCalc.run()
Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

OK, let's help you little with the memory.

from graphics import *
from button import Button
import math

class Calculator:
    # This class implements a simple calculator GUI

    def __init__(self):
        # create the window for the calculator
        win = GraphWin("calculator")
        win.setCoords(0,0,9,13.5)   #from (0,0,6,7)
        win.setBackground("slategray")
        self.win = win
        # Now create the widgets
        self.__createButtons()
        self.__createDisplay()
        self.__createM()  ## memory has value indicator
        self.memory = "0"

    def __createButtons(self):
        # create list of buttons
        # start with all the standard sized buttons
        # bSpecs gives center coords and label of buttons
        bSpecs = [(2.5,1,'0'), (4,1,'.'), (1,2.5,'1'), (2.5,2.5,'2'), (4,2.5,'3'),
                   (5.5,2.5,'+'), (7,2.5,'-'), (1,4,'4'), (2.5,4,'5'), (4,4,'6'),
                   (5.5,4,'*'), (7,4,'/'), (1,5.5,'7'), (2.5,5.5,'8'), (4,5.5,'9'),
                   (5.5,5.5,'<-'),(7,5.5,'C'),(1,1,'OFF'), (2.5,7,'pi'), (4,7,'('), (5.5,7,')'),
                   (7,7,'1/x'), (8.5,1,'ln'), (8.5,2.5,'log'), (8.5,4,'exp'),
                   (8.5,5.5,'sqrt'), (8.5,7,'x**2'), (1,8.5,'M+'), (2.5,8.5,'MS'),
                   (4,8.5,'MR'), (1,7,'MC'), (5.5,8.5,'sin'), (7,8.5,'cos'),
                   (8.5,8.5,'tan')]
        self.buttons = []
        #add to bSpecs
        for cx,cy,label in bSpecs:
            self.buttons.append(Button(self.win,Point(cx,cy),1.5,1.25,label))
        # create the larger = button
        self.buttons.append(Button(self.win,Point(6.25,1),3,1.25,"="))
        # activate all buttons
        for b in self.buttons:  b.activate()

    def __createM(self):
        ## memory indicator
        bg = Rectangle(Point(0.5,12), Point(1.5,13))   #from (.5,5.5), (5.5,6.5)
        bg.setFill('white')
        bg.draw(self.win)
        text = Text(Point(1,12.5), "")   #from (3,6)
        text.draw(self.win)
        text.setFace("courier")
        text.setStyle("bold")
        text.setSize(10)
        self.M = text
        self.eqflag = False

    def __createDisplay(self):
        bg = Rectangle(Point(.5,12), Point(8.5,13))   #from (.5,5.5), (5.5,6.5)
        bg.setFill('white')
        bg.draw(self.win)
        text = Text(Point(4.5,12.5), "")   #from (3,6)
        text.draw(self.win)
        text.setFace("courier")
        text.setStyle("bold")
        text.setSize(10)
        self.display = text

    def getButton(self):
        # Waits for a button to be clicked and returns the label of
        #    the button that was clicked.
        while True:
            p = self.win.getMouse()
            for b in self.buttons:
                if b.clicked(p):
                    return b.getLabel() # method exit

    def processButton(self, key):
        # Updates the display of the calculator for press of this key
        text = self.display.getText()
        innumber=text and text[-1].isdigit() ## last char of display is number
        result = 0
##        memory = 0
        print key,
        if key == 'C':
            self.display.setText("0")
            self.eqflag=True
            return
        elif key == '<-':
            # Backspace, slice off the last character.
            self.display.setText(text[:-1])
            return
        elif key == '=':
            # Evaluate the expresssion and display the result.
            # the try...except mechanism "catches" errors in the
            # formula being evaluated.
            try:
                result = eval(text)
            except:
                result = 'ERROR'
            self.display.setText(str(result))
            print 'Result',result
            self.eqflag=True  ## result in screen must clear before continue
            return

        if key == 'MR':
            if not innumber:
                self.display.setText(text+self.memory)
            else: self.display.setText(self.memory)
            
        elif key == 'MC':
            self.memory = "0"
            self.M.setText('')
        elif key == 'MS':
            self.memory = text or '0'
            if self.memory != '0':
                self.M.setText('M')
        elif key == 'M+':
            self.memory = str(eval(text+'+'+str(self.memory)))
            if self.memory != '0':
                self.M.setText('M')
                
        elif key == 'OFF':
            self.win.close()

        elif key == 'pi':
                if innumber:
                    self.display.setText(text+'*'+str(math.pi))
                else:
                    self.display.setText(text+str(math.pi))
                
        elif key == 'log':
            try:
                result = math.log10(eval(text))
            except:
                result = 'ERROR'
            self.display.setText(str(result))
        elif key == 'ln':
            try:
                result = math.log(eval(text))
            except:
                result = 'ERROR'
            self.display.setText(str(result))
        elif key == '1/x':
            try:
                result = 1/(eval(text))
            except:
                result = 'ERROR'
            self.display.setText(str(result))
            
        elif key == 'sin':
            result = math.sin(eval(text))*(180/math.pi)
            self.display.setText(str(result))
        elif key == 'cos':
            result = math.cos(eval(text))*(180/math.pi)
            self.display.setText(str(result))
        elif key == 'tan':
            result = math.tan(eval(text))*(180/math.pi)
            self.display.setText(str(result))
            
        elif key == 'sqrt':
            result = (eval(text))**0.5
            self.display.setText(str(result))
        elif key == 'exp':
            result = math.e**(eval(text))
            self.display.setText(str(result))
        elif key == 'x**2':
            result = eval(text)**2
            self.display.setText(str(result))
        else:
            # Normal key press, append it to the end of the display
            if not self.eqflag or not key.isdigit():
                self.display.setText(text+key)
            else:
                self.display.setText(key)
            self.eqflag=False

    def run(self):
        # Infinite 'event loop' to process button clicks.
        while True:
            key = self.getButton()
            self.processButton(key)

# This runs the program.
if __name__ == '__main__':
    # First create a calculator object
    theCalc = Calculator()
    # Now call the calculator's run method.
    theCalc.run()
Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

There is bug in pi part, it adds * when there is zero on screen, should replace the screen text with value of pi, easy to fix.

Also first C (or 0) and MS does not clear the M indicator, even it does same as MC.

BTW if you add if innumber: text=text+'.' ## use float value allways at beginning of handling the '=', the calculator does right the 1/3=0.3333333

Next job I left for you is to make sin etc to set the result flag, so entering number after them will clear the screen automatically.

With this implementation, you can not count for example sin(1+45/23) directly only 1+45/23=sin.

This program also crashes if you do C <- sin.

Happy hacking!

Tony

Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

Sorry that adding point to end of integer mixes the real float numbers so do not use that trick.

Tony

Member Avatar
tkpanther
Newbie Poster
19 posts since Feb 2010
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

Thank you, tonyjv, that has helped me out a lot. Strangely, though, I came up with a very similar solution to my Memory problem during my morning commute. All I needed for a memory indicator was a "light" that turned red while in use, and was dark while not in use. All that is really left for me right now is properly importing the math class (I can only import what I use), figuring out how to fix pi, and organizing the layout of the calculator. I'll mull over it throughout the rest of the day and I should have a nice solution by the time I get home.

Again, tonyjv, thank you for your help. It really did clear a lot of things up for me.

Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

Prove little how my solution works. I like especially the pi part that you can put 2 pi and get value of two pi. Also be sure to have zero on screen before writing numbers and clear before as user types something also before typing number after result. It is to type 2+5=, get 7, start to type 1+2= and get 73, even it would be possible to push C after reading the result. This is how normal calculator does any way.

Member Avatar
tkpanther
Newbie Poster
19 posts since Feb 2010
Reputation Points: 0 [?]
Q&As Helped to Solve: 0 [?]
Skill Endorsements: 0 [?]
 
0
 

For this assignment, I do not believe that matters that much, especially since the basic calculator code we were initially provided did not do that. My calculator does what he asked and I am within the the line limit (Maximum of 300 lines if you were curious. My professor was able to complete it in under 140 lines, or so he says).

Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

Maybe must try to do it in less than 100 ;-)

Tony

Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

Maybe must try to do it in less than 100 ;-)

Tony

I tried it with Tkinter, but I did not want to take out all empty lines etc.
So it is not under 100 lines.

It does have arcusfunction and hyperfunctions. You can also use scientific notation e.g. 1e9. You can type anything from keyboard, so this is little unsafe. (unprotected eval)

Here could include the number checking routine I posted resently, but it would need to expand to take acount for the allowed functions.

Memory and hyp indicator not implemented.

Put included keyboard images to same directory with the code.

from Tkinter import *
from math import *
from random import random

hyps=arc=''
mem=0
resflag=False ## for clearing the display after result automatically without CE

fact=factorial

def calc(s):
    global resflag
    brackc = display.get().count('(') - display.get().count(')')
    try:    display.set(eval('1.0*'+display.get()+')'*brackc)) ## try to fix bracket unbalance
    except: display.set('Error')
    number.icursor('end')
    resflag=True

def push_key(e):
    global resflag
    if 38<=e.x<=202 and 110<=e.y<=236:
        x,y = (e.x-38,e.y-110)
        x,y = (x/32,y/31)
        if isinstance(keys[y][x],basestring):
            if resflag: clear(e)
            resflag=False
            display.set(display.get()+keys[y][x])
            number.icursor('end')
        else: keys[y][x](e)
            
    if 34<=e.x<=201 and 28<=e.y<=101:
        x,y = (e.x-34, e.y-28)
        x,y = (int(x/27.8),int(y/24.3))
        if isinstance(fkeys[y][x],basestring):
            if fkeys[y][x] in ('sin','cos','tan'):
                display.set(hyp(fkeys[y][x])+display.get())
            else:
                if (fkeys[y][x][:2]=='**') or (fkeys[y][x][0] in '()'):
                    display.set(display.get()+fkeys[y][x])
                else:   display.set(fkeys[y][x]+display.get())
            number.icursor('end')
        else: fkeys[y][x](e)
            
def clear(e): display.set('')

def ac(e):
    global mem
    clear(e)
    mem=0

def mp(e):
    global mem
    mem=eval(str(mem)+'+'+display.get())

def Min(e):
    global mem
    mem=eval(display.get())

def MR(e):
    global mem
    display.set(display.get()+str(mem))
    
def ln(x): return log(x,e)

def hyptoggle(e):
    global hyps
    if hyps:    hyps = ''
    else:       hyps = 'h'
    
def shifttoggle(e):
    global arc,fkeys
    if arc:
        arc =  ''
        panel1.config(image=image1)
        fkeys=bfkeys
    else:
        arc = 'a'
        panel1.config(image=image2)
        fkeys=afkeys       

def hyp(trig): return arc+trig+hyps+'('

def sign(e):
    display.set('-'+display.get())
    calc(e)

def bs(e): display.set(display.get()[:-1])

def xtox(e): display.set(str(display.get())+'**'+str(display.get()))

bfkeys=(('1/(','**0.5','**2','log10(','ln(','**'),
       (shifttoggle,'pi',hyptoggle,'sin','cos','tan'),
       (sign, bs, '(',')',Min,MR))

afkeys=(('fact(','sqrt(',xtox,'10**','e**','**(1/'),
       (shifttoggle,'random()',hyptoggle,'sin','cos','tan'), ## sin,cos,tan by function
       (sign, bs, '(',')',Min,MR))

fkeys=bfkeys

keys=(('7','8','9',clear,ac),
      ('4','5','6','*','/'),
      ('1','2','3','+','-'),
      ('0','.','e',calc,mp))

root=Tk()
display = StringVar()
number=Entry(root,textvariable=display, justify='center')
number.pack(side='top', fill='x', expand='no')
image1 = PhotoImage(file="calc.gif")
image2 = PhotoImage(file="calc2.gif")
w,h = image1.width(), image1.height()
root.title('SimplistiCalc')
root.geometry ="%dx%d+0+0" % (w, h)
panel1 = Label(root, image=image1)
panel1.pack(side='top', fill='both', expand='yes')
number.focus()
number.bind('<Return>',calc)
number.bind('<Escape>',clear)
root.bind('<Button-1>',push_key)
root.mainloop()
Attachments calc2.gif 35.55KB calc.gif 36.02KB
You
This question has already been solved: Start a new discussion instead
Post:
Start New Discussion
View similar articles that have also been tagged: