ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Prototyping Desktop Applications
Pages: 1, 2, 3

Making Technical Decisions

During development, I had to solve a few technical problems and I made several technical decisions. The following code fragments are explained only briefly here, but they will be detailed in my future articles. The important thing is to understand the role of a prototype. Use your prototypes to find solutions to technical problems, to test less-used APIs, and to make sure that your application's performance is good.



Using Multi-Layered Panels

Building a graphic application such as Windows Paint is not a very complicated task. You have to handle mouse events and draw lines, rectangles, and ellipses. Transforming such a basic application into a professional graphic editor that lets you move, resize, reorder, delete, copy, cut, and paste the graphic objects requires more work, but can be done in a reasonable amount of time. You might also want to include text boxes that support editing, resizing, word wrapping, etc. Building your own styled-text editor is not necessary since Swing already provides a few text components.

How would you integrate one of the Swing's text editors with your own painting component? I can think of two solutions. One is to implement a mechanism similar to the JTextField cell editors used by JTable, but things are a bit trickier if you want to be able to resize and move the text boxes. The other solution is to use JDesktopPane, placing the text components within JInternalFrame instances.

With the second solution, the resizing and moving are already provided by Swing, but the next question is: how do you paint the source image under the internal frames, which contain the text notes? And how can you draw the other primitives such as lines, rectangles, and ellipses on the JDesktopPane? Fortunately, there is an easy solution, because JDesktopPane is actually a multi-layered panel. The prototype's MainPanel class, which extends JDesktopPane, has two layers. One of them contains the PaintView custom component that lets you draw graphic primitives. The other layer contains the text notes. Of course, this solution would be useless if the annotated image cannot be captured programmatically. The getAnnotatedImage() method of MainPanel does this with the following code:

BufferedImage image = new BufferedImage(
     width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
printAll(g);
g.dispose();

Painting Outside of paint()

The painting of the Swing components is normally done within paint() or within methods called by paint(). When drawing an object on screen with the mouse, however, you don't want to repaint any components, because this can significantly slow down the application. For example, when the user plays with the pencil, the application draws a small line for each mouse event. There can be hundreds of MOUSE_DRAGGED events between MOUSE_PRESSED and MOUSE_RELEASED.

Repainting the PaintView component a few hundred times when the user just draws something on screen is not acceptable. Note that PaintView handles most of the drawing operations and a single repaint requires the redrawing of all annotations including the text notes, which are painted over the PaintView component. The right solution is to obtain a graphic context outside of paint() with getGraphics() when each mouse event is handled:

protected void toolAction(MouseEvent e) {
    e.consume();
    Graphics2D g2 = (Graphics2D) getGraphics();
    float zoomFactor = model.getZoomFactor();
    g2.scale(zoomFactor, zoomFactor);
    float x = e.getX() / zoomFactor;
    float y = e.getY() / zoomFactor;
    currentTool.action(e.getID(), x, y, g2);
    g2.dispose();
}

The PaintView component uses mouse listeners to handle the mouse events. The above method is called for each event, delegating the painting to the currentTool object. When the mouse is released, the repaint() method is called to request the refreshing of the whole component. Therefore, paint() is called only once after the user has finished the drawing of the graphic object. Here is the code that registers the mouse listeners:

protected void registerListeners() {
    addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e)) {
                 requestFocus();
                 currentTool = model.createTool(
                      AbstractTool.DRAW_STYLE);
                 toolAction(e);
            }
        }
 
        public void mouseReleased(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e)) {
                 toolAction(e);
                 model.setLastTool(currentTool);
                 currentTool = null;
                 repaint();
            }
        }
    });
 
    addMouseMotionListener(new MouseMotionAdapter() {
        public void mouseDragged(MouseEvent e) {
            if (SwingUtilities.isLeftMouseButton(e))
                 toolAction(e);
        }
    });
 
    ...
}

The entire code of the PaintView class will be explained in a future article. The above code fragments are included here only to show how a prototype can be used to make technical decisions. The development of a professional graphic editor would not be possible without the ability to paint outside of paint().

Summary

Prototypes have an important role during the application development process, allowing you to test your ideas and to get user feedback very early. I do not view a prototype as a piece of code that you can throw away when the "real" development starts. Instead, the prototype should be the foundation of your product or application. This means that you should code it carefully, even if some of your classes or methods will be rewritten later. In the later articles of this series, I'll continue to present the source code of the JImaging prototype.

Source Code

Download the source code of the JImaging prototype.

Andrei Cioroianu is the founder of Devsphere and an author of many Java articles published by ONJava, JavaWorld, and Java Developer's Journal.


Return to ONJava.com.