700 likes | 842 Views
Object-Oriented Programming (Java), Unit 23. Kirk Scott. Serializability, File Choosers, and Multiple Frames. 23.1 Serializability 23.2 File Choosers 23.3 Multiple Frames. African Scops Owl (cryptic coloration). Red Lory. Sunbittern ( deimatic coloration). Calliope Hummingbird.
E N D
Object-Oriented Programming (Java), Unit 23 Kirk Scott
Serializability, File Choosers, and Multiple Frames • 23.1 Serializability • 23.2 File Choosers • 23.3 Multiple Frames
ClickSave • This example program adds two more menu options to the example • One triggers a listener to save the current state of the cups in the application • The other triggers a listener to reload them. • Saving and loading will involve the concept of serializability. • A screenshot of the application, showing the menu, is given on the next overhead.
The Serializable interface • Serializability is the term used to describe tools in the Java API that make it possible to save objects in files. • To be serializable, a class has to implement the Serializable interface. • If a class implements the interface, it is possible to save and load complete objects of a class. • It is not necessary to take them apart and save their instance variable values one at a time, for example.
This interface does not require the implementation of any methods. • In other words, it is a marker interface, kind of like Cloneable was a marker interface. • Certain requirements have to be met in order for a class to successfully implement the interface. • In particular, if a class is to be serializable, every object that it contains also has to be serializable.
The Cup and Seed classes: • The SeedCup class implements the Serializable interface. • The SeedCup class has a Rectangle instance variable. • The Rectangle class in the Java API implements the Serializable interface.
It is worth noting that the Rectangle2D.Double class in the Java API does not implement the interface. • This provides a concrete example of something that you could not include in a serializable class of your own. • The SeedCup class would not be serializable if it were based on Rectangle2D.Double instead of Rectangle.
The SeedCup class contains an ArrayList that will hold instances of the Seed class. • In order for the SeedCup class to be serializable, it will also be necessary for the Seed class to be serializable. • It is, and that will be discussed next.
Because every object that an instance of a SeedCup class could contain is serializable, the SeedCup class is serializable. • All that has to be done, and the only change from the previous version of the SeedCup class, is to declare it serializable. • public class SeedCup implements Serializable
The Seed class also implements the Serializable interface. • Unlike with the rectangle classes, none of the system supplied ellipse classes implement the Serializable interface. • This accounts for one of the important design characteristics of the Seed class which was already built in earlier, without giving a full explanation of why.
Seeds do not have instances of ellipses as instance variables. • The application code uses elliptical dots to represent seeds, but they are generated and displayed as part of the code of the drawSeed() method. • The dots are not persistent. • They are only transient visual representations of seeds.
This is a design point worth noting. • The application would not support serializability if the dots (ellipses) were instance variables of the Seed class. • All that has to be done, and the only change from the previous version of the Seed class, is to declare it serializable. • public class Seed implements Serializable
The SaveListener: • The SaveListener is built around the concept of serializability. • It is possible to open an output stream to a file which is designed to handle the saving of serializable objects. • The user is prompted for the name of a file.
An ObjectOutputStream is constructed. • Then, one after the other, references to the objects comprising the state of the application are acquired by calling get methods. • As they are acquired, they are saved by calling the write() method on the output stream.
The SaveListener has to deal both with the cups and the text area. • The getText() method returns a String, which is also an object. • This method contains the logic for acquiring the text for the action record area.
You may or may not be familiar with file I/O in Java. • Notice that I/O operations have to occur in a try/catch block. • File I/O operations are a classic example of exception handling in Java.
An I/O error might occur that is not the program’s fault • The exception handling mechanism makes it possible for the program to handle the error gracefully, assuming the programmer wants to go to the trouble of writing the code to do so. • The code for the SaveListener is given on the following overheads.
private class SaveListener implements ActionListener • { • public void actionPerformed(ActionEvent event) • { • String inputString; • inputString = JOptionPane.showInputDialog("Enter file path name for saving.");
try • { • ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream(inputString)); • objOut.writeObject(myPanel.getMyCupA()); • objOut.writeObject(myPanel.getMyCupB()); • objOut.writeObject(myPanel.getWhichCupIsActive()); • objOut.writeObject(myPanel.getText()); • objOut.writeObject(myPanel.getMoveCount()); • } • catch(IOException e) • { • System.out.println("Problem making or writing to an output stream."); • System.out.println(e); • } • } • }
Notice that a type of “auto-boxing” occurs on the moveCount value. • The system automatically wraps the integer value in an instance of the Integer class. • It’s automatic when saving. • It turns out that it will have to be dealt with directly when loading.
The LoadListener: • The LoadListener is analogous to the SaveListener. • It is also built around the concept of serializability. • It is possible to open an input stream to a file which is designed to handle the reading of serializable objects which were previously saved in the file.
In the LoadListener the user is prompted for the name of a file. • The current state of the application is disposed of by removing the current panel. • A new panel is created and added to the content pane.
The ObjectInputStream is constructed. • The file containing the SeedCup objects is read from the beginning. • The objects are retrieved in the order in which they were saved. • This is done using the readObject() method. • Notice that an Object reference is returned, and this has to be cast to the class expected.
The retrieved objects are put into the application panel. • This is done using set methods in the application. • The application deals with cups and text. • To set the text area with text retrieved with the load operation, call setText() with the String that is returned from the file.
Reading is also a file I/O operation, so it also has to occur in a try/catch block. • It is worth repeating that the order of the logic for retrieving objects is the same as for saving them. • Do not get the mistaken idea that something odd happens, like the order is reversed, for example.
private class LoadListener implements ActionListener • { • public void actionPerformed(ActionEvent event) • { • String inputString; • inputString = JOptionPane.showInputDialog("Enter file path name for loading.");
try • { • Container contentPane = getContentPane(); • contentPane.remove(myPanel); • myPanel = new ClickSavePanel(); • contentPane.add(myPanel, "Center"); • ObjectInputStreamobjIn = new ObjectInputStream( • new FileInputStream(inputString)); • myPanel.setMyCupA((SeedCup) objIn.readObject()); • myPanel.setMyCupB((SeedCup) objIn.readObject()); • myPanel.setWhichCupIsActive((SeedCup) objIn.readObject()); myPanel.setText((String) objIn.readObject()); • Integer localMoveCountObject = (Integer) objIn.readObject(); • intlocalMoveCount = localMoveCountObject.intValue(); • myPanel.setMoveCount(localMoveCount); • setVisible(true); • } catch(IOException e)…
catch(IOException e)… • Notice that on reading, another exception is thrown and also has to be caught: • catch(ClassNotFoundExceptione)…
ClickChooser • This example program makes use of a JFileChooser in the SaveListener and the LoadListener. • The screenshot on the next overhead shows what appears if the Save option is taken in the menu. • It should be apparent that the Java API makes available useful tools for creating a graphical file I/O interface.
The lines of code given below appear in the ClickChooserFrame class and its constructor, respectively. • This is where the chooser is created that the menu item listeners make use of. • JFileChoosermyChooser; • … • myChooser = new JFileChooser();
The SaveListener and the LoadListener: • Inside the actionPerformed() method of the save and load listeners the following will be found: • The call to setCurrentDirectory() will cause the chooser to open the home directory of the running application. • The call to showSaveDialog() causes the chooser to be displayed. • The call to getSelectedFile().getPath() obtains the full path name of the file which the user selects or enters.
Only key parts of the code are shown for this new version of the application. • Most of the code remains the same as in the previous version. • Parts of the save listener and the load listener are given on the following overheads.
Key parts of the SaveListener: • private class SaveListener implements ActionListener • { • public void actionPerformed(ActionEvent event) • { • /* • One way or another this has to be accomplished: • JFileChoosermyChooser = new JFileChooser(); • */ • myChooser.setCurrentDirectory(new File(".")); • myChooser.showSaveDialog(ClickChooserFrame.this); • fileName = myChooser.getSelectedFile().getPath(); • try • { • ObjectOutputStreamobjOut = new ObjectOutputStream(new FileOutputStream(fileName)); • …
Key parts of the LoadListener: • private class LoadListener implements ActionListener • { • public void actionPerformed(ActionEvent event) • { • /* • One way or another this has to be accomplished: • JFileChoosermyChooser = new JFileChooser(); • */ • myChooser.setCurrentDirectory(new File(".")); • myChooser.showOpenDialog(ClickChooserFrame.this); • fileName = myChooser.getSelectedFile().getPath(); • try • { • ObjectInputStreamobjIn = new ObjectInputStream(new FileInputStream(fileName)); • …
Slow construction of instances of JFileChooser • There is an unpleasant potential interaction between at least some versions of the Windows operating system and instances of JFileChooser in Java. • The construction of a JFileChooser may take a very long time if there are any zipped folders on the desktop of the machine you are running on.
In order to get reasonable performance of the Java code, move any zipped folders into another, unzipped folder. • This is very strange, and it's enough to make you cry, but at least there is an easy solution that doesn't involve elaborate changes to your code.
ClickMany • This program makes it possible to open up more than one frame with cups in it. • The menu for the main frame allows you to open up the new frames or exit the application overall. • The menu for a subframe allows you to restart or close that frame—without exiting the application. • Screenshots of the main frame and a subframe, and their menu options, are given on the following overheads.