The learning goals for this assignment are:
In this homework, we'll create a custom Swing component that can display a single photo and any annotations associated with that photo. A single one of these PhotoComponents will be displayed at any given time, and will serve as the content area of the photo album application. The basic idea is that this component can display a single photo, and also provide a way to store and render annotations including text and drawn strokes: You can "flip the photo over" to annotate on it using either mouse strokes or text.
There are a number of specific requirements for this assignment:
So that the component looks good in cases where the window is larger than the photo itself, you should render some nice-looking background behind the photo, which will be visible when the photo doesn't cover the entire extend of the component. This can be as simple as a solid color, or some pattern such as graph paper. You'd create this effect by simply doing some drawing in your paintComponent() method before drawing the image.
If the user shrinks the window so that the component cannot display the entire photograph, it should be scrollable so that the user can pan around the image. The easiest way to do this is to simply insert your PhotoComponent into a JScrollPane, and then insert that JScrollPane into the container area in your application. There are settings on JScrollPane that determine whether the scrollbars are always displayed, or just when they are needed (it's fine if the scrollbars are always displayed). Remember that the way JScrollPane works is that it allows its child to be any size it wants, but clips and positions it so that the correct part is shown under the visible region. This is why you want to make sure your component has a size and preferred size. If you reload a photo and change the size, you will probably want to call revalidate() on your PhotoComponent so that the scroll pane "notices" that its size has been updated.
If you want, you might also like to display some graphical "frame" around the picture, such as a while border or "scrapbook corners," although this is not required.
Hint: Your paintComponent method will have two paths through it, depending on the setting of this boolean. In the default path, it will draw the background and then the image. In the flipped path, it will draw the background, draw the white surface, and then draw the annotations (see below)
Hint: Remember that you'll need to redraw all of these same strokes anytime the Swing repaint pipeline tells you that you need to paint your component. So, the classic way to do this is to add strokes to a display list that contains the things to be rendered, and then in your paint code you simply iterate through the items to be painted, rendering them to the screen.Hint: Painted strokes will look much better if you use Java2D's anti-aliasing mechanism. Look at the setRenderingHints() method on Graphics2D.
Here's how text entry should work. First, the user selects the TEXT annotation mode (from Homework 1), then mouses out a rectangular region into which the text will go. This region should have a distinct appearance, such as a yellow post-it note. Next, when the user begins typing, the text should appear in the post-it, starting inside the top left, and fill out to the edge of the box. Once a line of text hits the edge, the system should word-wrap to the next line. If the user types more text than can fit in the post-it vertically, the post-it should expand vertically to accommodate the additional text.
While you don't have to do any especially fancy text processing (no ligatures or custom fonts or anything like that), you should make the basics work correctly. For this assignment, the basics are:
You do not have to implement more complicated features (although you're welcome to for extra credit). For example, you do not have to implement:
Hint: While you could perhaps build off the JTextArea component as a way to implement the post-it notes, please do not do that for this assignment. My goal is for you to learn how to do low-level text processing code from scratch. This approach also gives you more control over the text and its appearance.Hint: While all the word wrapping and repainting stuff may seem difficult, it's possible to architect the code in a way that makes it pretty straightforward. The key is to remember that, like with stokes above, you'll need to keep a data structure containing the text that will be rendered by your component. So one way to architect things is to simply create a new object (called TextRegion perhaps) whenever the user draws the post-it; at a minimum, this object needs to remember the X and width of the post-it, and the set of characters that are associated with it. Whenever characters are typed they are simply added to the string in the current TextRegion object. The job of your paint code, then, is simply to iterate over the list of TextRegions in your display list and draw them to the screen, wrapping as you draw based on the width of the region. In other words, rather than precomputing and saving the positions of every substring, you just figure it out each time when you paint.
Important Note: my recommendation is to not use full-size digital images when testing your application. Images take a lot of memory, and without additional configuration settings when you run Java, your Java Virtual Machine may run out of memory (this will especially be a problem when we start handling multiple photos in the next assignment.) So, to make your life easier, you may want to scale down your photos to 640x480 or some such.
When your application starts up, it should contain no photos, and hence no PhotoComponents.
Selecting Import should prompt the user for a photo file (via the JFileChooser), and create a new PhotoComponent containing the selected photo and display it in the content area.
NOTE that for this assignment, we'll only be dealing with a single photo at a time. So you don't need to worry about being able to select a folder and importing a bunch of photos... it's ok if your program just pops up an error message or ignores any selection that's not a single file. In later homework assignments, we'll build a container component that will display multiple PhotoComponents at the same time.
The currently displayed PhotoComponent should be used in the central content area of your application, should resize properly when the window is resized, etc., as described above. (You don't have to worry about doing fancy stuff like scaling photos.)
Selecting Delete Photo should delete the current PhotoComponent, meaning that the application should just show an empty content area.
Selecting Previous and Next will do nothing, since there's only ever zero or one photos in this version of the homework.
Changing any of the View Modes will do nothing, since we're currently only ever displaying zero or one photos.
See here for instructions on how to submit your homework. These instructions will be the same for each assignment.