Event Driven Drawing?

I know that drawing is always done in the paint(Graphics g) or paintComponent(Graphics g) methods if you want to paint on some object that inherits from Container class. So I was wondering how to make my JPanel draw something on when the user clicks on a button and draw something else when it clicks on another button. Well actually I am using a ComboBox for selection but it doesn't matter here...I know all about the listeners and stuff. I just dont know if I can call a specific method that paints let's say a triangle..and I have many methods that paint different objects ,but eventually all of these methods need to be called within paint method or paintComponent method of the JPanel class...so I wanna know if there is any better solution to this problem than just setting some boolean flags and use the if statements inside the paint method which will trigger a specific method that will paint something on the JPanel.

I hope I was clear. Thanks for any help!

[984 byte] By [byteministera] at [2007-11-26 15:34:25]
# 1

... any better solution to this problem than just setting some boolean flags and use

the if statements inside the paint method which will trigger a specific method that will

paint something on the JPanel.

There are two general approaches to this.

One is to use an (offscreen) image to do all the drawing on and draw the image during each

trip through paintComponent. All additions of geom primitives is done in event code by

drawing directly to the image. In pseudo杍ava:

BufferedImage image;

...

protected void paintComponent(Graphics g) {

if(image == null) initImage();

g.drawImage(image, 0, 0, this);

}

private void initImage() {

int w = getWidth();

int h = getHeight();

int type = BufferedImage.TYPE_INT_RGB;

image = new BufferedImage(w, h, type);

Graphics2D g2 = image.createGraphics();

g2.setBackground(getBackground());

g2.clearRect(0,0,w,h);

g2.dispose();

}

// In your event code, when you are ready to draw a new geom primitive

// update the image and call repaint.

Graphics2D g2 = (Graphics2D)image.getGraphics();

g2.draw(new_geom_primitive);

g2.dispose();

repaint();

For componentResized events you set the image to null and call repaint.

The other is to use one or more data structures to keep the geom primitives that have been

added and draw all of them during each trip through paintComponent.

All of the additions of geom primitives are done in event code followed by a call to

repaint to show the latest change(s).

Here's an example of this second approach. The extra methods for locating/scaling the new

additons are unnecessary frills; adding the new geom primitives and calling repaint from

within the event code are the essential parts.

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.util.*;

import java.util.List;

import javax.swing.*;

public class DrawingObjects extends JPanel implements ActionListener {

List<Shape> shapes;

Random seed;

final int R = 60;

final int MAX_SIZE_REDUCTIONS = 2;

final int MAX_FIT_ATTEMPTS = 4;

public DrawingObjects() {

shapes = new ArrayList<Shape>();

seed = new Random();

}

public void actionPerformed(ActionEvent e) {

String id = e.getActionCommand();

int sides = 0;

if(id.equals("triangle"))

sides = 3;

if(id.equals("pentagon"))

sides = 5;

if(id.equals("hexagon"))

sides = 6;

if(id.equals("septagon"))

sides = 7;

int[][] xy = generateShapeArrays(0, 0, R, sides);

Polygon p = new Polygon(xy[0], xy[1], sides);

placePolygon(p);

}

protected void paintComponent(Graphics g) {

super.paintComponent(g);

Graphics2D g2 = (Graphics2D)g;

g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON);

g2.setPaint(Color.blue);

for(Shape s : shapes)

g2.draw(s);

}

public Dimension getPreferredSize() {

return new Dimension(400,400);

}

private void placePolygon(Polygon polygon) {

Shape shape = locateBySize(polygon);

if(shape != null) {

shapes.add(shape);

repaint();

} else {

System.out.println("polygon could not be placed");

}

}

private Shape locateBySize(Polygon polygon) {

Shape shape = polygon;

int sides = polygon.npoints;

int sizeReductions = 0;

do {

Shape s = fitShape(shape, sides);

if(s != null)

return s;

AffineTransform at = AffineTransform.getScaleInstance(0.6, 0.6);

shape = (Shape)at.createTransformedShape(shape);

sizeReductions++;

}

while(sizeReductions <= MAX_SIZE_REDUCTIONS);

return null;

}

private Shape fitShape(Shape shape, int sides) {

int w = getWidth();

int h = getHeight();

Rectangle r = shape.getBounds();

AffineTransform at = new AffineTransform();

int count = 0;

while(count < MAX_FIT_ATTEMPTS) {

int x = seed.nextInt(w - r.width);

int y = seed.nextInt(h - r.height);

// Original shape has its center at the view (this) origin (0,0).

// The extra factors after x and y below are to move the polygon

// fully into the view.

double dy = getOffset(r.height, sides);

at.setToTranslation(x+r.width/2, y+r.height/2+dy);

Shape s = at.createTransformedShape(shape);

if(isClear(s)) {

return s;

}

count++;

}

return null;

}

private double getOffset(int height, int sides) {

// R + r = height center to vertex

// r = R * cos(PI/sides)center to side

double R = height/(1 + Math.cos(Math.PI/sides));

double r = R * Math.cos(Math.PI/sides);

return (R - r)/2;

}

private boolean isClear(Shape shape) {

Area area = new Area(shape);

for(int j = 0; j < shapes.size(); j++) {

Area test = (Area)area.clone();

test.subtract(new Area(shapes.get(j)));

if(!test.equals(area)) {

return false;

}

}

return true;

}

private int[][] generateShapeArrays(int cx, int cy, int R, int sides) {

int radInc = 0;

if(sides % 2 == 0)

radInc = 1;

int[] x = new int[sides];

int[] y = new int[sides];

for(int i = 0; i < sides; i++) {

x[i] = cx + (int)(R * Math.sin(radInc*Math.PI/sides));

y[i] = cy - (int)(R * Math.cos(radInc*Math.PI/sides));

radInc += 2;

}

// keep base of triangle level

if(sides == 3)

y[2] = y[1];

return new int[][] { x, y };

}

private Box getUIBox() {

Box box = Box.createHorizontalBox();

box.add(Box.createHorizontalGlue());

String[] ids = { "triangle", "pentagon", "hexagon", "septagon" };

for(int j = 0; j < ids.length; j++) {

JButton button = new JButton(ids[j]);

button.setActionCommand(ids[j]);

button.addActionListener(this);

box.add(button);

box.add(Box.createHorizontalGlue());

}

return box;

}

public static void main(String[] args) {

DrawingObjects test = new DrawingObjects();

JFrame f = new JFrame();

f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

f.getContentPane().add(test);

f.getContentPane().add(test.getUIBox(), "Last");

f.pack();

f.setLocationRelativeTo(null);

f.setVisible(true);

}

}

crwooda at 2007-7-8 21:51:42 > top of Java-index,Security,Cryptography...
# 2
Thanks crwood. That really helped a lot! Very nice examples, they explain a lot.null
byteministera at 2007-7-8 21:51:42 > top of Java-index,Security,Cryptography...