Computer Science 210
Data Structures
Fall 2018, Siena College
RatioListApplet BlueJ Project
Click here to download a BlueJ project for RatioListApplet.
RatioListApplet Source Code
The Java source code for RatioListApplet is below. Click on a file name to download it.
// <applet code='RatioListApplet' width='400' height='450'></applet>
/**
* Example RatioListApplet: a simple Applet to manipulate
* a RatioList - a list of Ratio objects
*
* Run in appletviewer with the provided view.html file
*
* Jim Teresco, The College of Saint Rose, CSC 523, Summer 2014
* Siena College, CSIS 210, Fall 2018
*
* @author Jim Teresco
*/
/* tons of imports for the GUI */
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
public class RatioListApplet extends JApplet implements ActionListener {
// GUI components
private JTextField displayNumerator, displayDenominator;
private JButton insertButton, sumButton, minButton, maxButton, reduceButton, reduceAllButton, showAllButton;
// our RatioList, which is null until the first is inserted
private RatioList ratios;
/**
required init method called when the JApplet is initialized
*/
public void init() {
Container contentPane = getContentPane();
// a bigger font for our display label and text fields
Font biggerFont = new Font("Sans-Serif", Font.BOLD, 24);
Font biggestFont = new Font("Fixed", Font.PLAIN, 48);
// a JPanel for the center that displays the "current" ratio
JPanel currentPanel = new JPanel();
JLabel currentLabel = new JLabel("Display value:");
currentLabel.setFont(biggerFont);
currentPanel.add(currentLabel);
// another JPanel to create the ratio display
JPanel ratioPanel = new JPanel();
ratioPanel.setLayout(new BoxLayout(ratioPanel, BoxLayout.PAGE_AXIS));
displayNumerator = new JTextField("0", 5);
displayNumerator.setFont(biggestFont);
displayNumerator.setHorizontalAlignment(JTextField.CENTER);
ratioPanel.add(displayNumerator);
ratioPanel.add(new JSeparator());
displayDenominator = new JTextField("1", 5);
displayDenominator.setFont(biggestFont);
displayDenominator.setHorizontalAlignment(JTextField.CENTER);
ratioPanel.add(displayDenominator);
currentPanel.add(ratioPanel);
contentPane.add(currentPanel, BorderLayout.CENTER);
// a JPanel for the buttons across the bottom
JPanel buttonPanel = new JPanel(new GridLayout(0, 1));
insertButton = setupButton("Insert Current", buttonPanel);
sumButton = setupButton("Set Current to Sum", buttonPanel);
minButton = setupButton("Set Current to Min", buttonPanel);
maxButton = setupButton("Set Current to Max", buttonPanel);
reduceButton = setupButton("Reduce Current to Lowest Terms", buttonPanel);
reduceAllButton = setupButton("Reduce All to Lowest Terms", buttonPanel);
showAllButton = setupButton("Show All Ratios", buttonPanel);
contentPane.add(buttonPanel, BorderLayout.SOUTH);
contentPane.validate();
}
// a private method to create, insert, and set the listener for our buttons
private JButton setupButton(String label, JPanel addTo) {
JButton me = new JButton(label);
addTo.add(me);
me.addActionListener(this);
return me;
}
/**
Check if the contents of the given JTextField represent a valid
integer value
@param f the JTextField to check
@return true if the text in f successfully can be parsed as an integer
*/
private static boolean isValidInt(JTextField f) {
String text = f.getText();
try {
Integer.parseInt(text);
}
catch (NumberFormatException e) {
return false;
}
return true;
}
// helper method to display a given ratio in the display area
private void displayRatio(Ratio r) {
displayNumerator.setText(""+r.getNumerator());
displayDenominator.setText(""+r.getDenominator());
}
// helper method to get a Ratio based on current contents of the text fields,
// and returns null (after showing error dialog) if the fields are not valid
// to construct a Ratio
private Ratio ratioOfDisplay() {
// we need to take the value on the display and create a new ratio out of it
// we need to verify that the value displayed is valid to use as a ratio
// first, check that the text fields have numbers in them
boolean numValid = isValidInt(displayNumerator);
boolean denValid = isValidInt(displayDenominator);
String message = "";
if (!numValid) {
message += "Could not parse numerator as an integer value!\n";
}
if (!denValid) {
message += "Could not parse denominator as an integer value!\n";
}
if (!numValid || !denValid) {
JOptionPane.showMessageDialog(null, message, "Invalid Entry", JOptionPane.ERROR_MESSAGE);
return null;
}
// we know they're numbers, so let's get them
int num = Integer.parseInt(displayNumerator.getText());
int den = Integer.parseInt(displayDenominator.getText());
// make sure we're not dividing by zero
if (den == 0) {
JOptionPane.showMessageDialog(null, "Denominator cannot be 0", "Invalid Entry", JOptionPane.ERROR_MESSAGE);
return null;
}
// if we get here, things are good, construct and return a Ratio
return new Ratio(num, den);
}
/**
handle all button presses
@param e the ActionEvent describing the action that triggered this event
handler to be called
*/
public void actionPerformed(ActionEvent e) {
if (e.getSource() == insertButton) {
// we need to take the value on the display and create a new ratio out of it
// and add it to our collection
Ratio newOne = ratioOfDisplay();
if (newOne != null) {
// things are valid, so let's construct a Ratio and make it the new
// first entry in our RatioList
ratios = new RatioList(newOne, ratios);
}
}
else if (e.getSource() == showAllButton) {
// we just want to print out all of the ratios in our collection
// so we'll put them up in a dialog box
String message;
if (ratios == null) {
message = "No ratios in list.";
}
else {
message = ratios.toString();
}
JOptionPane.showMessageDialog(null, message);
}
else if (e.getSource() == sumButton) {
// we need to compute the sum and display it
if (ratios == null) {
displayRatio(new Ratio(0,1));
}
else {
displayRatio(ratios.getSum());
}
}
else if (e.getSource() == minButton) {
if (ratios == null) {
JOptionPane.showMessageDialog(null, "No ratios in list.");
}
else{
displayRatio(ratios.getMin());
}
}
else if (e.getSource() == maxButton) {
if (ratios == null) {
JOptionPane.showMessageDialog(null, "No ratios in list.");
}
else {
displayRatio(ratios.getMax());
}
}
else if (e.getSource() == reduceButton) {
// get the Ratio from the display text fields
Ratio displayed = ratioOfDisplay();
if (displayed != null) {
displayed.reduce();
displayRatio(displayed);
}
}
else if (e.getSource() == reduceAllButton) {
if (ratios == null) {
JOptionPane.showMessageDialog(null, "No ratios in list.");
}
else {
ratios.reduceAll();
}
}
}
}
/**
* A recursive data structure (list) of Ratio objects with some
* useful methods to manage such a list
*
* Jim Teresco, The College of Saint Rose, CSC 523, Summer 2014
* Siena College, CSIS 210, Fall 2018
*
* @author Jim Teresco
*/
public class RatioList {
// our instance variables have room for one Ratio, and
// then a list of other ratios -- which is exactly
// the structure we are defining -- so we can define this
// structure *recursively*
private Ratio first;
private RatioList rest;
/**
Construct a RatioList from a Ratio and another RatioList,
which would be null when constructing a brand new RatioList
with its first element
@param first the Ratio to become the first element in the list
@param last the RatioList which will become the rest of the new list
*/
public RatioList(Ratio first, RatioList rest) {
this.first = first;
this.rest = rest;
}
/**
compute the sum of all ratios in the list, recursively
@return a Ratio representing the sum of all Ratios in the list
*/
public Ratio getSum() {
// if there is no rest, the sum is just first
if (rest == null) return first;
// otherwise, we have to compute the sum of the rest (using
// this method) and then add in first, using Ratio's add method
Ratio restSum = rest.getSum();
Ratio answer = first.add(restSum);
return answer;
}
/**
find the minimum ratio, recursively
the minimum is the smaller of first and the minimum of the rest,
which we compute using this method recursively
@return the Ratio in the list with the smallest value
*/
public Ratio getMin() {
// the smallest out of a single ratio is that ratio
if (rest == null) return first;
// otherwise, find the min of the rest and compare to first
Ratio minOfRest = rest.getMin();
if (minOfRest.getDecimalValue() < first.getDecimalValue()) {
return minOfRest;
}
else {
return first;
}
}
/**
find the maximum ratio, recursively
the maximum is the larger of first and the maximum of the rest,
which we compute using this method recursively
@return the Ratio in the list with the largest value
*/
public Ratio getMax() {
// the largest out of a single ratio is that ratio
if (rest == null) return first;
// otherwise, find the max of the rest and compare to first
Ratio maxOfRest = rest.getMax();
if (maxOfRest.getDecimalValue() > first.getDecimalValue()) {
return maxOfRest;
}
else {
return first;
}
}
/**
reduce all Ratios in the list to lowest terms
*/
public void reduceAll() {
// reduce the one Ratio we have
first.reduce();
// and if there are more, reduce recursively
if (rest != null) rest.reduceAll();
}
/**
create a String representation of the Ratios in the list
the toString method is recursive! To print this whole RatioList,
we concatenate the result of first's toString with a recursive
call to this toString method. But only do the latter when rest
is not null (we are not at the end of the list)
@return a String representation of all of the Ratios in the list
*/
public String toString() {
String answer = first.toString();
if (rest != null) {
answer += ", " + rest.toString();
}
return answer;
}
}
/**
* Example Ratios -- the Ratio class
*
* This class encapsulates a numerator and denominator and
* includes the capability to set the numerator or denominator,
* retrieve the numerator or denominator, retrieve the decimal
* equivalent of the ratio, and return a "pretty" String
* representation of the ratio
*
* This version includes a non-destructive method to add another
* ratio to this and return a new ratio that contains the sum
*
* Jim Teresco, The College of Saint Rose, CSC 202, Fall 2012
* CSC 523, Summer 2014, Siena College CSIS 210, Fall 2018
*
* @author Jim Teresco
*/
public class Ratio {
// Instance variables for the two integers, one each for the numerator
// and denominator.
private int numerator;
private int denominator;
// our straightforward constructor
public Ratio(int num, int den) {
numerator = num;
denominator = den;
}
// Mutators for numerator and denominator
public void setNumerator(int num) {
numerator = num;
}
public void setDenominator(int den) {
denominator = den;
}
// And some accessors
public int getNumerator() {
return numerator;
}
public int getDenominator() {
return denominator;
}
public double getDecimalValue() {
return 1.0 * numerator / denominator;
}
// print our simple string representation
public String toString() {
return numerator + "/" + denominator;
}
// a non-destructive add method that adds another ratio to this
// one and returns a new one (leaving this and other unchanged)
public Ratio add(Ratio other) {
return new Ratio(numerator*other.denominator + denominator*other.numerator,
denominator*other.denominator);
}
// a recursive method to compute greatest common divisor using Euclid's method
public static int gcd(int a, int b) {
if (a == 0) return b;
if (a > b) return gcd(b, a); // so below we can assume b>=a
return gcd(b%a, a);
}
// Reduce this ratio to lowest terms. To do so, we find the greatest common
// divisor of the numerator and denominator, then divide both
// numerator and denominator by that value
public void reduce() {
int divideBy = gcd(numerator, denominator);
numerator /= divideBy;
denominator /= divideBy;
}
}