import javax.swing.*; import javax.swing.table.*; import java.awt.*; import java.awt.event.*; import java.util.Vector; import java.text.*; import StudentPkg.*; /** This application reads in course grades stored in the file * and presents them in a GUI table * * Written by: Stuart Hansen * Date: October 7, 2001 * Revised: January 13, 2002 - to work with new StudentPkg * Revised: February 21, 2002 - cleaned it up a bit **/ public class StudentTable extends JFrame { StudentGrades course; // the studentGrades object being displayed StudentDataFile stfile; // a file of students String filename = ""; // the name of the file containing the grades CourseViewer courseView; // the Viewer the controls the presentation of // of the grades JTable table; // table of student data JScrollPane scrollPane; // a scrollPane for the table JButton load; // a button to load a file JButton save; // a button to save the file boolean needsSaving; // a flag to signal that the file needs saving // An array of column labels for the table String [] columnNames = {"Name", "Exam 1", "Exam 2", "Exam 3", "Average"}; // The constructor creates all the objects and ties them together // after which all interaction is via the GUI public StudentTable() { // Create the window super("Course Grades"); // The course viewer ties the table to the data courseView = new CourseViewer(); // Create a new table and add it to the application table = new JTable(courseView); table.setPreferredScrollableViewportSize(new Dimension(500, 200)); // the table is empty, so nothing needs saving needsSaving = false; // The contentPane is where we add all the components Container c = getContentPane(); c.setLayout(new FlowLayout()); //Create the scroll pane and add the table to it. scrollPane = new JScrollPane(table); c.add(scrollPane); // Add a button to load a file load = new JButton("Load"); c.add(load); load.addActionListener(new fileLoadController()); // Add a button to save our edits save = new JButton("Save"); c.add(save); save.addActionListener(new fileSaveController()); // Code to allow the X to close the application setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); addWindowListener(new StudentTableWindowHandler ()); // Set the size of the window an display it setSize(550, 300); validate(); setVisible(true); } // We simply new up one object in the main public static void main(String[] args) { new StudentTable(); } // This inner class is used to determine how to present the data class CourseViewer extends AbstractTableModel { // The constructor simply news up a new studentGrades object public CourseViewer (String filename) { stfile = new StudentDataFile(filename); course = new StudentGrades(); while (stfile.hasNext()) { course.add(stfile.readStudent()); } } // The null constructor public CourseViewer () { course = new StudentGrades (); } // Returns the labels for the columns public String getColumnName(int col) { return columnNames[col]; } // Get the appropriate size for the table public int getRowCount() { return course.getStudentCount()+1; } public int getColumnCount() { return columnNames.length; } // Gets the values to put into the table. // Tightly coupled with both the table and the StudentGrades object public Object getValueAt(int row, int col) { // Get information associated with a particular student if (row < course.getStudentCount()) { Student s = course.getStudent(row); if (col == 0) return s.getName(); else if (col ==1) return new Integer(s.getExam1()); else if (col ==2) return new Integer(s.getExam2()); else if (col ==3) return new Integer(s.getExam3()); else if (col ==4) { NumberFormat form = NumberFormat.getInstance(); form.setMaximumFractionDigits(2); form.setMinimumFractionDigits(2); return form.format(s.getAverage()); } else return "Error " + row + " or " + col + " out of range!"; } // Get information associated with the exam averages else if (row == course.getStudentCount()) if (col == 0) return "Average"; else if (col < columnNames.length-1) { NumberFormat form = NumberFormat.getInstance(); form.setMaximumFractionDigits(2); form.setMinimumFractionDigits(2); return form.format(course.getExamAverage(col)); } else { NumberFormat form = NumberFormat.getInstance(); form.setMaximumFractionDigits(2); form.setMinimumFractionDigits(2); return form.format(course.getAverage()); } else return new Integer (0); } // Returns whether a cell may be editted or not // Averages may not be editted in our application public boolean isCellEditable(int row, int col) { if (col == columnNames.length-1 || row == course.getStudentCount()) return false; else return true; } // This method sets the name or score and updates the averages public void setValueAt(Object value, int row, int col) { if (((String)value).equals("")) return; if (row < course.getStudentCount()) { needsSaving = true; Student s = course.getStudent(row); if (col == 0) s.setName((String)value); else if (col ==1) s.setExam1(Integer.parseInt((String)value)); else if (col ==2) s.setExam2(Integer.parseInt((String)value)); else if (col ==3) s.setExam3(Integer.parseInt((String)value)); // Changing a cell changes multiple averages fireTableCellUpdated(row, 4); fireTableCellUpdated(course.getStudentCount()+1, col); } } } // This controller handles saving data to a file class fileSaveController extends AbstractAction { public void actionPerformed(ActionEvent event) { try { course.printStudentsToFile(filename); needsSaving = false; } catch (Exception e) { JOptionPane.showMessageDialog(null, "Unable to save file! " + e); } } } // This controller handles loading data from a file class fileLoadController extends AbstractAction { public void actionPerformed(ActionEvent event) { // if the current file doesn't need saving, load a new one if (!needsSaving) { loadFile(); } // if there are changes to the current file, ask about changing it else { int option = JOptionPane.showConfirmDialog(null, "Save current file?"); if (option == JOptionPane.CANCEL_OPTION) { // do nothing if operation is cancelled } else if (option == JOptionPane.NO_OPTION) { loadFile(); } else if (option == JOptionPane.YES_OPTION) { try { course.printStudentsToFile(filename); JOptionPane.showMessageDialog(null, filename + " saved."); } catch (Exception e) { JOptionPane.showMessageDialog(null, "Unable to save file! " + e); } loadFile(); } } } public void loadFile () { // Choose the data file to open JFileChooser chooser = new JFileChooser("."); chooser.setDialogTitle ("Choose file to Load"); int returnVal = chooser.showOpenDialog(null); if(returnVal == JFileChooser.APPROVE_OPTION) { // Open the file filename = chooser.getSelectedFile().getAbsolutePath(); stfile = new StudentDataFile(filename); // Read from the file into StudentGrades course = new StudentGrades(); int i = 0; while (stfile.hasNext()) { course.add(stfile.readStudent()); courseView.fireTableRowsInserted(i, i); i++; } needsSaving = false; setTitle(filename); } else JOptionPane.showMessageDialog(null, "No file chosen"); } } // This class takes care of closing the window appropriately class StudentTableWindowHandler extends WindowAdapter { public void windowClosing(WindowEvent we) { if (!needsSaving) { System.exit(0); } // If changes have been made to the data, we query whether they should be saved else { int option = JOptionPane.showConfirmDialog(null, "Save file before exiting?"); if (option == JOptionPane.CANCEL_OPTION) { // do nothing if operation is cancelled } else if (option == JOptionPane.NO_OPTION) { System.exit(0); } else if (option == JOptionPane.YES_OPTION) { try { course.printStudentsToFile(filename); JOptionPane.showMessageDialog(null, filename + " saved."); } catch (Exception e) { JOptionPane.showMessageDialog(null, "Unable to save file! " + e); } System.exit(0); } } } } }