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 ( a == 0 && b == 2 ) //if the key is "c"
{
stack . clear ();
calculator_screen . setFont ( Font . font ( "Verdana" , 30 ));
font_size = 30 ;
}
else if ( a == 0 && b == 3 ) //if the key is "b"
stack . pop ();
else if ( a == 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 ( a == 0 && b == 1 )
btn [ i ][ j ]. getStyleClass (). add ( "btnEqual" );
else if ( a == 0 && b == 2 )
btn [ i ][ j ]. getStyleClass (). add ( "btnClear" );
else if ( a == 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 );