![]() | Design and implement a Graphical User Interface (GUI) using Java Swing classes |
![]() | implement inheritance and polymorphism on classes that extend an abstract class |
![]() | implement handling of events generated by a graphical user interface |
![]() | implement exception handling in an application to react to error conditions |
![]() | implement file I/O read and write files in various formats |
In this assignment, you will implement the handleColorCommand(), handleFileSaveCommand(), and handleFileLoadCommand() methods of the DrawingProgramApp class (see the UML class diagram from the previous lab). The handleColorCommand(), handleFileSaveCommand() and handleFileLoadCommand() methods are already in the DrawingProgramApp class, although they are empty.
The handleColorCommand() method is called by the menu action listener when the user selects the Options/Pen Color... or Options/Background Color... commands. In response to these events, the handleColorCommand() method is called with a String argument indicating which menu item was selected. In either case, in handleColorCommand(), you are to post a JColorChooser dialog, and (only if the user chooses a color and presses OK) set the penColor or backgroundColor attribute appropriately. Be careful in implementing this; in the case where the user presses the cancel button, no color will be selected!
The purpose of the
handleFileSaveCommand() and handleFileLoadCommand() methods is described in the comments
above the empty method bodies; that is, they post the JFileChooser
dialogs that prompt the user for the files to save or load. After
obtaining the file names from the user, these two methods call the
saveTextImage(), saveBinaryImage(), saveObjectImage(), loadTextImage(),
loadBinaryImage(), and loadObjectImage() methods
where the actual File I/O is done. You'll have to create these methods -
be sure to follow the method signatures found in the UML class diagram.
The saveTextImage(), saveBinaryImage(), and saveObjectImage() methods save each created shape contained in
the List of shapes in one of three different formats, depending on the specified
file extension of the filename you specify. For example, if the specified
filename is "image.txt" (ending with the "txt" extension), you are to save the
individual shapes in a human-readable text file format using saveTextImage(). If the filename is "image.bin"
(extension is "bin"), then the individual shapes are to be stored in binary
format by saveBinaryImage(). Finally, if the filename is "image.obj", the serialization functions
provided by Java are to be used to store the shapes in object format with
saveObjectImage(). The exact formats
are described in the section below.
Similarly, the loadTextImage(), loadBinaryImage(), and loadObjectImage() methods read in files of previously-saved shapes (in the various formats), replacing any existing shape collection with the shapes found in the specified file. Before replacing any existing shape collection, be sure the image loading operations completed successfully (without generating any exceptions). That is, don't replace an existing image unless you are successful!
Any exceptions encountered either loading or saving files must be
presented to the user (using JOptionPane dialogs) without
crashing the application or causing loss of data (shapes). Your program must not
crash or allow exceptions to propagate out to the JVM!
Catch the exceptions in the handleFileSave() and handleFileLoad() methods -
not in the saveXXX() or loadXXX() methods.
Here is a UML Sequence diagram showing the flow of method calls for the File Load and File Save sequences (for the case where a text file is specified):
In a text file (ending with "txt"), each record in the file specifies a single shape. The example below illustrates a text file containing two shapes. Your text file must be able to store any number of shapes (including none at all), using this exact format:
![]() |
The 1st token in a record specifies the shape type; the value is
equivalent to one of the static final ints defined within the
AbstractShape class (e.g. a Line is represented by a 0, a Rectangle
is represented by a 1, etc).
|
![]() |
The 2nd and 3rd tokens specify the starting x and y locations of the
shape.
|
![]() |
The 4th and 5th tokens specify the ending x and y locations of the
shape.
|
![]() | The last three tokens specify, respectively, the Red, Green, and Blue color values of the shape; each value may be between 0-255. |
Following this specification, the first record below specifies a Line (shape type 0), starting at coordinates (18,40), ending at coordinates (95,196), and white in color (Red, Green and Blue are all 255). The second record specifies a blue Ellipse.
0 18 40 95 196 255 255 255 2 104 38 167 158 0 0 255
The easiest way to output a shape's text representation is by writing the result returned by the shape's toString() method.
When reading shapes from a file, you have to read the first token in each record to determine the shape type, then use the remaining information in that record to create that shape.
In a binary file (ending with "bin"), raw integer values are stored
rather than the characters representing the digits of those values. Binary
files don't contain explicit records either, so the files will just be
continuous sequences of bytes that represent the integer values of the
shapes' parameters. For each shape stored, the file will contain 32 bytes
representing eight 4-byte integers, in the following order:
<shape type><starting x><starting y><ending x><ending y><red
component><green component><blue component>
The binary file must be able to store any number of
shapes (including none at all).
In an object file (ending with "obj"), shapes will be stored using Java's built-in serialization capability. Rather than serializing each individual shape, however, you'll serialize the entire ArrayList of shapes. Thus, you only need to write or read the ArrayList and everything contained within that collection will be automatically serialized (this is one of the benefits of Java's serialization feature). You of course need to ensure that the shapes all implement the serialization interface in order for this to work correctly - you do this by making the AbstractShape class itself serializable.
Test your program to verify that it works correctly: Create various shapes of different colors, save the shapes to files in different formats, and exit the program. Restart the program, and add some new shapes. Then open the files containing the previously-saved shapes; those shapes should replace the new shapes you just created. Be sure that the shapes restored from the file have the same positions and colors as they had when you had saved them.
Use the following three files to validate that your program can correctly load images of each format:
![]() | test.txt |
![]() | test.bin |
![]() | An object file cannot be supplied due to the fact that the information serialized into the file contains the complete package name of the classes being serialized. In your individual implementations, your classes each have packages names that are specific to your MSOE email name. Thus, when you load a previously-saved object file, the Java deserialization algorithm will require that the shapes that it's deserializing will contain your package names. |
These files when loaded both should result in the following image:
Your grade will be based on the following criteria:
![]() | Meeting requirements; your program must compile and
run, and produce well-formed, explicit error messages. If you have trouble, you must come to see me. If you don't and you
submit a program that does not compile or produce detailed meaningful results will
receive a grade of no higher than 50, even after reworking your program. |
![]() | Technical quality of your program. Technical quality consists of formatting, commenting, and
following coding style guidelines. |
![]() | Spelling and grammar. |
![]() | Timeliness of submission as stated in the course policies. |