Informatik 1 – Schmiedecke

Lab X5 – Scribble (Mouse Drawing)

Swapped with X4 - Nodenet

 


In this lab, you will be programming a (primitive) visual drawing device. You will do so without using any special libraries, not even cs101, but. Rely on  the java standard library only.

Finally, you will add this lab to your workshop result (the "Divelog" application)

Objectives: GUIs and GUI event handling.

 

Directly related to: Lectures 11a and 11b; less directly: Chapters 15 and 16

 


Intro:  java.awt.Graphics:

 

Begin with trying Scribble: scribble.jar 

In order to draw into a GUI, we need the class java.awt.Graphics. A Graphics object attached to a component administers its pixel matrix. For a Container Component, that is just an empty area with a white background. A Component inside this Container has its own Grahics object describing its shape, color etc. The Component method
paint() displays the component onto the screen. It is called by the VM whenever a redrawing is required (e.g. after resizing or being covered by a popup window).

 

Here is a small list of the most important Graphics drawing methods that can be used to add elements to a Component’s appearance – open the API documentation for Graphics and Component while reading these notes!

 

public void drawLine(int x1, int y1, int x2, int y2);  // line of current color

public void drawRect(int x, int y, int width, int height);  // rectangle

public void drawOval(int x, int y, int width, int height);  // ellipse within rectangle positions

public void drawString(String text, int y, int y); // String starting at x,y, current color & font

 

public void clearRect(int x, int y, int width, int height);  // clear given rectangular area

publicvoid fillRect(int x, int y, int width, int height);  // fill rectangle area w. current color

public void fillOval(int x, int y, int width, int height);

 

public void setColor(Color color); // set current color

public void setFont(Font font); // set current font

 

Typically, you use drawing inside of containers, because they offer a blank background that can be used as a drawing area. You can use drawing shapes to define new widgets, if you want, e.g. elliptical buttons – then you will need to trace mouse coordinates in order to find out whether your component was clicked.

In order to make permanent drawings, you have to override the container’s
paint() method, which is called by the VM whenever a redrawing is required. The VM passes the container’s current Graphics object as a parameter, and you apply your drawing methods to this object. You cannot call paint()  yourself, but you can call the parameterless method repaint()  which triggers the VM to call paint()in order to make your drawings visible.

 

public void paint(Graphics g);

 

In Scribble, however, we need to draw as reaction to runtime events. Overwriting paint()  does not work in this case, because we would have to know the shapes to be drawn at programming time. Rather, we need to do the drawing in the event handling methods. But where do they get a Graphics object from? Every component defines a method

getGraphics()


which yields the currently used copy of the Graphics object. Use that one for drawing as a response to mouse events. The drawback of this Graphics object is that it is of limited validity: It is discarded with the next call of
paint().This means that calling  repaint()  can be used to clear the drawing area… Careful: getGraphics() yields null until the component is displayed for the first time.

 

Here is a little list of typical traps when working with Graphics:

 

1.    (0,0) denotes the top left corner of the component (not of the surrounding main window).

2.    All drawing shapes are positioned using their top left corner. But for text, the bottom left corner is used.

3.    If the coordinates of a drawing lie outside the drawing area, it is invisible (no error message). So for text, always use a y value of at least 5.

4.    Use repaint carefully: It erases all non-permanent drawings, i.e. everything that is not programmed in paint().

5.    If you use getGraphics(), catch NullPointerExceptions because they are not unlikely to occur.

 

 

Prep Questions:

 

Scribble consists of a drawing area with two widgets: a clear button, and a combo box for choosing drawing colors. Lines dragged with the mouse are displayed in the chosen color.

 

1.    How many active objects (threads) are needed?

2.    Are you going to call drawLine in the paint method or elsewhere?

3.    Will your drawings survive repaint calls?

4.    How will your drawings react to window resizing? Will they grow and shrink accordingly?

5.    Do you expect the opening of the combo box to cause any problems?

6.    How will you implement the clear button handler, i.e. what does the actionPerformed method do?

 

Lab experiments:

            Voluntary quick pre-lab: Japanese Flag – or Diver Flag, if you like that better J

Write a program that draws a Japanese flag, i.e. e white rectangle with a red circle in it:

1.    Extend JFrame and set its size in the constructor.

2.    Override paint, drawing a white rectangle and a red circle.

3.    In the main method, instantiate your class.

 

Scribble Program Setup:

Define two classes:

1.    ScribbleFrame is a JFrame and contains exactly one JPanel in ist center: ScribblePanel.

2.    ScribblePanel is a Jpanel and implements MouseListener and MouseMotionListener.

 

Drawing:

1.    drawLine has 4 Parameters, 2 sets of coordinates. Define 4 int attributes to store the corresponding mouse coordinates.

2.    Now write the event handler methods MousePressed() and MouseDragged().Use  MousePressed()  to store the coordinates as the start coordinates of a line, and MouseDragged() to draw a line and update the start coordinates. Remember that you can get a Graphics object using the getGraphics method of your container – in this case ScribblePanel.

3.    What about the other handler methods?

4.    Test your first scribbler. You can erase your drawing by resizing your window.
.

Erase button:

1.    Implement and test an erase Button, using an anonymous Handler. Calling repaint()will erase your drawings.

2.    Remember to either change the Layout or add the button to the NORTH part of your panel.

 

Color choice:

1.    Implement and test a color combo box. Add a new attribute currentColor to your ScribblePanel.

2.    As the user cannot change the color in the middle of a line, check the combo box in  MousePressed() and call setColor() to define the line color.

3.    Test your Color choice.

4.    Which color is used after erasing?  Is that the expected behaviour? If not, modify your program accordingly.

You should get this far in the lab.

    

           Now take this result and integrate it as a further tab into your "Divelog" application from the weekend workshop. Feel free to invent a fanciful title for this tab, e.g. "subaqua art"...

 

            Extra work:

 

ComboBox without erasing:

To avoid erasing caused by an opened combo box, move the combo box to the bottom of the window.

 

ColorChooser:

1.    Replace the combo box by a button labelled "Colors".

2.    Write an anonymous handler for it which shows a JColorChooser dialog and stores the result in a color attribute. Read this attribute instead of the combo box state in MousePressed().

3.    Ersetzen Sie die ComboBox durch eine JButton  mit der Aufschrift "Farbwahl".

4.    Schreiben Sie einen anonymen Ereignisbehandler für den Farbwahl-Knopf, der ein JColorChooser-Fenster anzeigt und das Ergebnis in das Feld aktuelleFarbe einträgt.

 

Permanent Drawings (difficult):

1.    Instead of drawing, store the color and the mouse positions of each line in a collection (of type Vector). Use a second Vector to store all lines.

1.    Override paint: let it take the information from the lines Vector and draws the lines.

2.    Re-implement the clear button: let it empty the lines Vector.

 

            


© Ilse Schmiedecke 2005 – for questions and remarks schmiedecke@tfh-berlin.de