Computer Science 210
Data Structures
Fall 2019, 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; } }