Calculator with stack

profileJack Jonshen
framework.zip

framework/.DS_Store

__MACOSX/framework/._.DS_Store

framework/application.css

/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */ .vbox1 { -fx-background-color:rgb(20,64,144); -fx-padding: 20; -fx-font-size: 30; } .button{ -fx-background-color:rgb(174,184,219); } .btnEqual{ -fx-background-color:rgb(61,127,61); -fx-text-fill:white; } .btnClear{ -fx-background-color:rgb(155,56,54); -fx-text-fill:white; } .btnBackspace{ -fx-background-color:rgb(80,80,80); -fx-text-fill:white; } .vbox2 { -fx-background-color:rgb(207,59,62); -fx-padding: 20; -fx-font-size: 20; } .vbox3 { -fx-background-color:rgb(90,207,9); -fx-padding: 20; -fx-font-size: 20; } .style1 { -fx-background-color:rgb(217,144,185); } .style2 { -fx-text-fill:red; } .screen1 { -fx-background-color: #FFFFFF; -fx-min-width: 50; -fx-min-height: 50; } .screen2 { -fx-background-color: #FFFFFF; -fx-text-alignment:left ; }

__MACOSX/framework/._application.css

framework/Calculator.java

framework/Calculator.java

package  application ;

import  javafx . application . Application ;
import  javafx . beans . binding . Bindings ;
import  javafx . beans . property . DoubleProperty ;
import  javafx . beans . property . SimpleDoubleProperty ;
import  javafx . event . ActionEvent ;
import  javafx . event . EventHandler ;
import  javafx . geometry . Pos ;
import  javafx . scene . Scene ;
import  javafx . scene . control . Button ;
import  javafx . scene . control . TextField ;
import  javafx . scene . layout . TilePane ;
import  javafx . scene . layout . VBox ;
import  javafx . scene . text . Font ;
import  javafx . stage . Stage ;
import  javafx . stage . StageStyle ;


/* This is the GUI class that visualize the calculator 
 * 
 * */
public   class   Calculator   extends   Application   {
    
     private   MyStack  stack  =   new   MyStack ();
     private   double  font_size  =   30 ;   //by default the font size on the screen is 30
    
     /*The keyboard key values*/
     private   static   final   String [][]  key_values  =   {
               {   "0" ,   "=" ,   "c" ,   "<"   },
               {   "1" ,   "2" ,   "3" ,   "-"   },
               {   "4" ,   "5" ,   "6" ,   "*"   },
               {   "7" ,   "8" ,   "9" ,   "+"   }
           };
     private   Button  btn [][]   =   new   Button [ 4 ][ 4 ];   //all the key buttons
     TextField  calculator_screen ;    //the calculator screen
    

     
     public   static   void  main ( String []  args )   {  launch ( args );   }

      @ Override   public   void  start ( Stage  stage )   {
          
          /*The outside layout*/
          final   VBox  layout  =   new   VBox ( 30 );   //the size vertically

          /*The inside layout for keys or buttons*/
          TilePane  keypad  =   new   TilePane ();   //even it is called keypad, it is a layout
         keypad . setVgap ( 7 );
         keypad . setHgap ( 7 );   //set the gap between keys
          
          
         /*Create Calculator Screen */
        calculator_screen  =    new   TextField ();
        calculator_screen . getStyleClass (). add ( "screen1" );   //set the style of the screen
        calculator_screen . setAlignment ( Pos . CENTER_RIGHT );   //make the screen in the center of the calculator
        calculator_screen . setEditable ( false );   //make sure the screen cannot be typed in manually
        calculator_screen . setPrefWidth ( 300 );   //set the windth of the screen
        calculator_screen . setPrefHeight ( 30 );
        calculator_screen . setFont ( Font . font ( "Verdana" ,  font_size ));
        
         /*Create Calculator keyboard*/
        keypad . setPrefColumns ( key_values [ 0 ]. length );   //set the preferred number of columns

         for   ( int  i  =   0 ;  i  <   4 ;  i ++ )   {
           for   ( int  j  =   0 ;  j  <   4 ;  j ++ )   {
            btn [ i ][ j ]   =   new   Button ( key_values [ i ][ j ]);
             final   int  a  =  i ;
             final   int  b  =  j ;
            
             /*Add button event*/
            btn [ i ][ j ]. setOnAction ( new   EventHandler < ActionEvent > (){

                @ Override
                 public   void  handle ( ActionEvent  event )   {
                
                     StackNode  node  =   new   StackNode ( key_values [ a ][ b ]);
                    
                    
                     if ( ==   0   &&  b  ==   2 )   //if the key is "c"
                     {
                        stack . clear ();
                        calculator_screen . setFont ( Font . font ( "Verdana" ,   30 ));
                        font_size  =   30 ;
                     }
                     else   if ( ==   0   &&  b  ==   3 )   //if the key is "b"
                        stack . pop ();
                     else   if   ( ==   0   &&  b  ==   1 )   // if the key is "="
                     {
                        stack . computeExp ();
                     }
                     else
                        stack . push ( node );   //otherwise push the key into the list
                    
                     String  math_exp  =  stack . getAllNodeValues ();
                    
                     if ( math_exp . length ()   *  font_size  >   1.2   *  calculator_screen . getPrefWidth ())
                     {
                        font_size  /=   1.2 ;
                        calculator_screen . setFont ( Font . font ( "Verdana" ,  font_size ));
                        
                     }
                    
                    calculator_screen . setText ( math_exp );
                    
                 }
             }
             );   
            
             //Add special style for the "=" button
             if ( ==   0   &&  b  ==   1 )
                btn [ i ][ j ]. getStyleClass (). add ( "btnEqual" );
             else   if ( ==   0   &&  b  ==   2 )
                btn [ i ][ j ]. getStyleClass (). add ( "btnClear" );
             else   if ( ==   0   &&  b  ==   3 )
                btn [ i ][ j ]. getStyleClass (). add ( "btnBackspace" );
            keypad . getChildren (). add ( btn [ i ][ j ]);
          
           }
         }
        
         /*Put the calculator screen and keypad into a VBox layout*/
        layout . setAlignment ( Pos . CENTER );
        layout . getChildren (). addAll ( calculator_screen ,  keypad );
        layout . getStyleClass (). add ( "vbox1" );
        calculator_screen . prefWidthProperty (). bind ( keypad . widthProperty ());
        
        
         /*Show the window*/
        stage . setTitle ( "Calculator" );
        stage . initStyle ( StageStyle . UTILITY );
        stage . setResizable ( false );
         Scene  scene  =   new   Scene ( layout );
        scene . getStylesheets (). add ( getClass (). getResource ( "application.css" ). toExternalForm ());
        
        stage . setScene ( scene );
        stage . show ();
       }
    
}

__MACOSX/framework/._Calculator.java

framework/MyQueue.java

framework/MyQueue.java

package  application ;


public   class   MyQueue < T >   {

     private  T []  arr ;   //used to store data into this array in a queue manner

     private   int  total ;   //the total number of elements in the queue
     private   int  first ;   //the location of the first element in the queue
     private   int  rear ;   //the location of the next available element (last one's next)

     //Default constructor, by default the capacity is two elements of type T 
     public   MyQueue ()
     {
        arr  =   ( T [])   new   Object [ 2 ];
     }

     //Resize the MyQueue to the capacity as the input argument specifies
     private   void  resize ( int  capacity )
     {
        T []  tmp  =   ( T [])   new   Object [ capacity ];

         for   ( int  i  =   0 ;  i  <  total ;  i ++ )
            tmp [ i ]   =  arr [( first  +  i )   %  arr . length ];

        arr  =  tmp ;
        first  =   0 ;
        rear  =  total ;
     }
    
     //Check if the queue is empty: if empty, returns true; otherwise returns false
     public   boolean  isEmpty ()
     {
             //Implementation here...
         return   false ;
     }

     //Add one element "ele" into the queue
     //Attention: (1) if the current queue is full, you need to resize it to twice of the current size.
     //           (2) if the "rear" is already pointing to the end of the queue, but there is available space
         //               in the beginning, you need to "loop" the rear position.
     public   void  enqueue ( T ele )
     {
             //Implementation here...
     }

    
     //Delete the first (oldest) element from the queue and return this element.
     //Below is just an example code, you need to modify it. 
     //Attention: (1) To save space, if the current number of elements is less than or equal to 1/4 of the
         //               the capacity, shrink the capacity to 1/2 (half) of the original size.
         //           (2) If the "first" is pointing to the end of the queue, but there is available space
     //               in the beginning, you need to consider "loop" the first position.
     public  T dequeue ()
     {
             //Implementation here...      
        T ele  =  arr [ 0 ];
         return  ele ;
     }
    
}

__MACOSX/framework/._MyQueue.java

framework/MyStack.java

framework/MyStack.java

package  application ;


/* Basic node element that is used by the linked list*/
class   StackNode   {
     String  data ;   //the node stored value
     StackNode  next ;   //pointing to next node
    
     //Default constructor
     public   StackNode ()
     {
        
     }
    
     //Constructor with data value assigned
     public   StackNode ( String  value )
     {
        data  =  value ;
     }
    

     //Constructor with data value and next node assigned
     public   StackNode ( String  value ,   StackNode  next )
     {
        data  =  value ;
         this . next  =  next ;
     }
    
     //Basic setters and getters
     public   String  getData ()   {
         return  data ;
     }

     public   void  setData ( String  data )   {
         this . data  =  data ;
     }

     public   StackNode  getNext ()   {
         return  next ;
     }

     public   void  setNext ( StackNode  next )   {
         this . next  =  next ;
     }


    
}


/* MyStack class is used to store string into the stack
 * According to the stack logic, you need to implement the function members of MyStack based on the linked list structure
 * */
public   class   MyStack {
      private   StackNode  top_node ;   //pointing to the first node
     

     //Default constructor
      public   MyStack ()
      {
         top_node  =   null ;   //by default, the node is empty.
      }

     //Constructor with the first node
     public   MyStack ( StackNode  node )   {
        top_node  =  node ;
     }
    
     //check if the stack is empty
     public   boolean  isEmpty ()
     {
         if ( top_node  ==   null )
             return   true ;
         else
             return   false ;
     }
    
     //clear the stack
     public   void  clear ()
     {
        top_node  =   null ;
     }
    
    
     //A general push() method for stack
     public   void  pushNode ( StackNode  node )
     {
         if ( top_node  ==   null )
         {
            top_node  =  node ;
         }
         else
         {
            node . setNext ( top_node );
            top_node  =  node ;
         }
     }
    
    
     //a specific push method for this calculator project uses only 
     public   void  push ( StackNode  node )
     {
         //if there is no any element in the stack, the calculator only accepts numbers or "-"
         if ( top_node  ==   null )
         {
             if ( node . getData (). matches ( "^[0-9]+$" )   ||  node . getData (). equals ( "-" ))
                top_node  =  node ;
         }
         else   if ( node . getData (). matches ( "^[0-9]+$" ))   //if the inserted node is a number
         {
            node . setNext ( top_node );
            top_node  =  node ;
         }
         else   //if the inserted node is "+", "-", "*"
         {
             if ( top_node . getData (). matches ( "^[0-9]+$" ))   //if the recently inserted node is a number, then just insert the "node" straight away
             {
                node . setNext ( top_node );
                top_node  =  node ;
             }
             else   //if recently inserted node is an operator, e.g. "+", "-", "*", then replace its value by the "node" value
             {
                 if ( top_node . getNext ()   !=   null   )
                    top_node . setData ( node . getData ());
             }
         }
        
     }
    
     //remove the most recently inserted node
     public   void  pop ()
     {
         if ( top_node  !=   null )
         {
            top_node  =  top_node . getNext ();
         }
         else
         {
             System . out . println ( "The stack is already empty" );
         }
        
     }
    

     //get recently inserted node
     public   StackNode  getTop ()   {
         if ( top_node  ==   null )
         {
             System . out . println ( "The stack is empty" );
         }
         else
         {
             return  top_node ;
         }
        
         return   null ;
     }
    
    
    
     //get and remove the most recently inserted node
     public   StackNode  getTopandPop ()   {
         if ( top_node  ==   null )
         {
             System . out . println ( "The stack is empty" );
         }
         else
         {
             StackNode  temp  =  top_node ;
            top_node  =  top_node . getNext ();
             return  temp ;
         }
        
         return   null ;
     }
    
     //This function will all the stored strings connected and return it as a single string
     public   String  getAllNodeValues ()
     {
         StringBuilder  all_strings  =   new   StringBuilder ();   //used to store all the strings from the stack
    
         int  i  =   0 ;
         StackNode  temp  =  top_node ;
         while ( temp  !=   null )
         {
            all_strings . append ( temp . getData ());
            temp  =  temp . getNext ();
         }
        all_strings . reverse ();
         return  all_strings . toString ();
     }
    
    
     /*This function will to implement the "=" key that process the expression entered by users and calculates a final number. 
      In addition to the calculation, the final number needs to be converted into a string format and output to the display.
      So there are five basic steps involved below. 
      Steps 1, 4, 5 are already completed. Your tasks will focus on Step 2 and Step 3 
      */
     public   void  computeExp ()
     {
         String  exp  =  getAllNodeValues ();   //get the current expression
        
         //Step 1: convert a string into an infix queue
         MyQueue  infix_queue  =  getInfixFromString ( getAllNodeValues ());
        
         //Step 2: convert an infix queue into an postfix queue
         MyQueue  postfix_queue  =  infix2postfix ( infix_queue );
        
         //Step 3: Compute the final value from the postfix queue
         String  final_value  =  processPostfix ( postfix_queue );

         //Step 4: Clear the stack
         this . clear ();
        
         //Step 5: put the final_value into the stack
         for ( int  i  =   0 ;  i  <  final_value . length ();  i ++ )
             this . pushNode ( new   StackNode ( final_value . substring ( i ,  i  +   1 )));
        
     }
    
    
     /* Generate an infix expression according to an input String 
     * The infix expression is stored in a MyQueue variable, which is the returned value of the function */
     private   MyQueue  getInfixFromString ( String  exp )
     {
         //Declare queue to store infix
         MyQueue  infix_queue  =   new   MyQueue ();   //used as a temporary holder that extract operator and operand from exp
        
         //Check if exp has at least one character
         if   ( exp . length ()   <   1 )
             return  infix_queue ;
        
         // Check the first character if it is a negative sign
         int  j  =   0 ;
         if   ( exp . substring ( 0 ,   1 ). equals ( "-" ))   {
            j  =   1 ;
         }

         // Check the last character if it is an operator, just drop it
         if   ( exp . substring ( exp . length ()   -   1 ,  exp . length ()). equals ( "+" )
                 ||  exp . substring ( exp . length ()   -   1 ,  exp . length ()). equals ( "-" )
                 ||  exp . substring ( exp . length ()   -   1 ,  exp . length ()). equals ( "*" ))   {
            exp  =  exp . substring ( 0 ,  exp . length ()   -   1 );
         }

         // Traverse all the characters and push an operand or operator into
         // infix_queue
         for   ( int  i  =  j ;  i  <  exp . length ();  i ++ )   {
            
             String  character  =  exp . substring ( i ,  i  +   1 );

             // If current character is an operator, then just push it to the
             // stack and move to the next one
             if   ( character . equals ( "+" )   ||  character . equals ( "*" )   ||  character . equals ( "-" ))   {
                infix_queue . enqueue ( character );
             }   else   // If the current character is a number, it is an operand
             {
                 StringBuilder  builder  =   new   StringBuilder ();
                 if   ( ==   1   &&  i  ==   1 )
                    builder . append ( "-" );

                builder . append ( character );

                i ++ ;   // let the cursor moves one step forward
                 if   ( >=  exp . length ())   // check whether this move causes out of
                                         // range
                 {
                    infix_queue . enqueue ( builder . toString ());
                     break ;
                 }

                 while   ( exp . substring ( i ,  i  +   1 ). matches ( "^[0-9]+$" ))   {
                    builder . append ( exp . substring ( i ,  i  +   1 ));

                    i ++ ;
                     if   ( >=  exp . length ())   // check whether this move causes out
                                             // of range
                         break ;
                 }
                infix_queue . enqueue ( builder . toString ());
                i -- ;   // let the cursor moves one step back as at the end of the
                         // for-loop i++ automatically
             }
         }
         //insert testing code here
         return  infix_queue ;
     }
    
    
     /*Convert an input infix queue into A postfix queue, which is the output of the function */
     private   MyQueue  infix2postfix ( MyQueue  infix_queue )
     {
         //Implementation here...
         //Below is just a start, you need to fill the values for postfix_queue
        
         //Declare a queue to store postfix 
         MyQueue  postfix_queue  =   new   MyQueue ();  
        
         //insert testing code here
         return   postfix_queue ;
     }
    
    

     /* Process the postfix expression to compute the final value */
     private   String  processPostfix ( MyQueue  postfix )
     {
         //Implementation here...
         //Below is just a start, you need to fill the values for final_value
        
         String  final_value  =   "" ;  
        
         return  final_value ;
     }
    
    
}

__MACOSX/framework/._MyStack.java

__MACOSX/._framework