Code Comments
Programming Forum and web based access to our favorite programming groups.Hi,
I've tried to make a class that allows one to annotate an image
by clicking with the mouse; each mouse click will place a little "X"
or other graphic at that location. The class is user-configurable, with
callbacks to handle what happens when you click, and a list
of callbacks to draw the graphics.
The puzzle: after I click on the image, the repaint draws
the image origin _at the location of the mouse click_,
rather than at 0,0, though I do not ask it to do this.
I've produced a simplified example, where the "image" is a just a
red square. There is a base class "GRJImage" with a paintComponent
method that does this:
Graphics g2 = g.create();
g2.setColor(Color.red);
g2.fillRect(0, 0, getWidth(), getHeight()); // testing, show the
problem
Then a derived class "GRJTestImage" handles all the mouse callback
stuff.
It's paintComponent() is like this:
Graphics g2 = g1.create(); // save the context
super.paintComponent(g1); // draw the red rectangle
int npts = _drawList.size(); //d raw the graphics
for( int i = 0; i < npts; i++ ) {
Drawable d = (Drawable)_drawList.get(i); d.draw(g2);
}
g2.dispose();
I do not see what is causing the fillRect to draw at a location
other than 0,0! And various fiddling with copying the Graphics
object and reusing it has not resolved it.
Here are two files that isolate the problem. If you compile and run,
you will see a red rectangle. Increase the window size.
Then click inside the window, and the red rectangle will
move so it's upper-left is at the mouse location, rather
than covering the whole window.
This is on jdk1.4 on a mac, though I think it is my bug rather
than apple's.
----------------GRJImage.java----------------
import java.awt.*;
import javax.swing.*;
public class GRJImage extends JComponent
{
final int _verbose = 2;
int _xres;
int _yres;
public GRJImage()
{
}
public void setImage()
{
_xres = 300;
_yres = 200;
} //setImage
public Dimension getPreferredSize()
{
return new Dimension(_xres, _yres);
}
public void paintComponent(Graphics g)
{
Graphics g2 = g.create();
if (_verbose > 1) System.out.println("GRJImage.paint");
if (isOpaque()) {
//&& ((_xres != getWidth()) || (_yres != getHeight()))) {
// this is the specified desired behaviour for paintComponent,
// but is inefficient, so warn if we end up doing it.
System.out.println("PAINTING BACKGROUND "+_xres+" "+getWidth());
g2.setColor(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
}
g2.setColor(Color.red);
g2.fillRect(0, 0, getWidth(), getHeight()); // testing, show the
problem
g2.dispose();
} //paintComponent
} //GRJImage
----------------GRJTestImage.java----------------
// GRJTestImage.java - debug the interface mouseclick puzzle
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* displays an image, with manipulatible drawn overlays.
*
* _drawList is an arrayList of things to draw, each is passed
* the Graphics2D and maintains its own location. Each also
* has a clicked() method that gets called when the image is clicked
* near it.
*
* _clickList is a list of callbacks to call on each mouseClick.
* Register something with this in order to get something onto the
drawlist.
*
* Example usage:
* create an OnClick whose call() method creates a drawable
* located at the click location, adds it to the drawList,
* and optionally removes itself from the clickList.
*
* <pre>
* GRJTestImage p = new GRJTestImage(pic);
p.addDrawable(_trackMarker);
GRJTestImage.OnClick c = new GRJTestImage.OnClick() {
public void call(int x, int y) {
Drawable d = new GRJTestImage.plusMarker(x,y, Color.red);
p.addDrawable(d);
}
};
p.addOnClick(c);
*/
public class GRJTestImage extends GRJImage
{
final GRJTestImage _p;
ArrayList _drawList = new ArrayList();
ArrayList _clickList = new ArrayList();
int _lx, _ly; // location of last mouse click
//----------------------------------------------------------------
public int getX() { return _lx; }
public int getY() { return _ly; }
public void setX(int x) { _lx = x; }
public void setY(int y) { _ly = y; }
//----------------------------------------------------------------
// an OnClick handler is a high level click dispatcher
// c.f. drawable, which also does mouse handling, but is intended
// to be a single object such as a point or curve.
public interface OnClick
{
void call(int x, int y);
}
public void addOnClick(OnClick c)
{
System.out.println("adding clickable "+c);
_clickList.add(c);
}
public void removeOnClick(OnClick c)
{
System.out.println("removing clickable "+c);
_clickList.remove(c);
}
public void clearOnClick()
{
_clickList.clear();
}
//----------------------------------------------------------------
public interface Drawable
{
// GRJTestImage makes a copy of g, so this method does not need
// to restore its state, at least if the next draw() knows
// how to reset what this one changed
void draw(Graphics g);
// formerly had getX/getY to let the caller see if a mouse click is
// near this object. That does not work for a polyline, so
// have the object itself do the test.
// int getX(); int getY();
// did this event hit near us == should we be called with
click/press/...
boolean hit(MouseEvent evt);
// implement null methods if not interested
void click(MouseEvent evt, GRJTestImage p);
void press(MouseEvent evt, GRJTestImage p);
void drag(MouseEvent evt, GRJTestImage p);
void release(MouseEvent evt, GRJTestImage p);
}
public void addDrawable(Drawable d) { _drawList.add(d); repaint(); }
public void removeDrawable(Drawable d)
{
_drawList.remove(d);
System.out.println("removing drawable "+d+
", "+_drawList.size()+" remaining");
repaint();
}
public void removeDrawables()
{
_drawList.clear();
repaint();
}
//---------------- example drawable ----------------
public static class plusMarker implements Drawable {
int _x,_y;
Color _c;
public plusMarker(int x, int y, Color c) {
_x = x; _y = y; _c = c;
}
public void draw(Graphics g)
{
g.setColor(_c);
g.drawLine(_x-5,_y,_x+5,_y);
g.drawLine(_x,_y+5,_x,_y-5);
} //plus
public boolean hit(MouseEvent evt)
{
int mx = evt.getX();
int my = evt.getY();
int dx = _x - mx;
int dy = _y - my;
int d2 = (dx*dx + dy*dy);
// distance < 3 pixels
return (d2 < 9);
} //hit
public void click(MouseEvent evt, GRJTestImage p)
{
System.out.println("ispopuptrigger = "+evt.isPopupTrigger());
System.out.println("getbutton = "+evt.getButton());
if (evt.getButton() == 3) { // 3 is the right mouse button
System.out.println("removing...");
p.removeDrawable(this);
p.repaint();
}
else {
_x = evt.getX();
_y = evt.getY();
}
} //click
public void press(MouseEvent evt, GRJTestImage p) {}
public void drag(MouseEvent evt, GRJTestImage p) {}
public void release(MouseEvent evt, GRJTestImage p) {}
} //plusMarker
//----------------------------------------------------------------
public GRJTestImage(/*gr[] img*/)
{
//super(img);
super();
setBorder(BorderFactory.createLineBorder(Color.BLUE, 5));
if (false)
setDebugGraphicsOptions(DebugGraphics.LOG_OPTION|
//DebugGraphics.FLASH_OPTION|
DebugGraphics.BUFFERED_OPTION);
_p = this;
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt)
{
System.out.println("mouse clicked.");
super.mouseClicked(evt);
_lx = evt.getX();
_ly = evt.getY();
// call all the "clickables"
for( int i = 0; i < _clickList.size(); i++ ) {
System.out.println("calling clickable #"+i+", "+_lx+","+_ly);
OnClick c = (OnClick)_clickList.get(i);
c.call(_lx, _ly);
}
// note call all the drawables also, let them handle
// mouse events as well!
System.out.println("calling drawables.click");
for( int i = 0; i < _drawList.size(); i++ ) {
System.out.println("calling drawable #"+i);
Drawable d = (Drawable)_drawList.get(i);
if (d.hit(evt)) d.click(evt, _p);
else System.out.println("missed hit");
}
repaint();
} //mouseClicked
public void mousePressed(MouseEvent evt)
{
System.out.println("mouse pressed.");
super.mousePressed(evt);
System.out.println("calling drawables.press");
if (false)
for( int i = 0; i < _drawList.size(); i++ ) {
System.out.println("calling drawable #"+i);
Drawable d = (Drawable)_drawList.get(i);
if (d.hit(evt)) d.press(evt, _p);
}
repaint();
} //mousePressed
public void mouseReleased(MouseEvent evt)
{
System.out.println("mouse released.");
super.mouseReleased(evt);
System.out.println("calling drawables.release");
for( int i = 0; i < _drawList.size(); i++ ) {
System.out.println("calling drawable #"+i);
Drawable d = (Drawable)_drawList.get(i);
if (d.hit(evt)) d.release(evt, _p);
}
repaint();
} //mouseReleased
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
System.out.println("calling drawables.drag");
for( int i = 0; i < _drawList.size(); i++ ) {
System.out.println("calling drawable #"+i);
Drawable d = (Drawable)_drawList.get(i);
if (d.hit(e)) d.drag(e, _p);
}
}
});
} //constructor
public void paintComponent(Graphics g1)
{
if (_verbose > 1) System.out.println("GRJTestImage.paint");
Graphics g2 = g1.create();
super.paintComponent(g1);
int npts = _drawList.size();
for( int i = 0; i < npts; i++ ) {
System.out.println("calling drawable #"+i);
Drawable d = (Drawable)_drawList.get(i);
d.draw(g2);
}
g2.dispose();
} //paint
//----------------------------------------------------------------
public static GRJTestImage showme()
{
JFrame f = new JFrame("foo");
GRJTestImage p = new GRJTestImage();
f.getContentPane().add(p);
//f.setSize(xres+20, yres+20);
f. setDefaultCloseOperation(WindowConstants
.DISPOSE_ON_CLOSE);
f.setVisible(true);
f.repaint();
return p;
} //showme
//----------------------------------------------------------------
public static void main(String[] cmdline)
{
System.out.println("GRJTestImage");
final GRJTestImage p = GRJTestImage.showme();
OnClick c = new OnClick() {
public void call(int x, int y) {
Drawable d = new GRJTestImage.plusMarker(x,y, Color.red);
p.addDrawable(d);
p.removeOnClick(this);
}
};
p.addOnClick(c);
} //main
} //GRJTestImage
----------------end----------------
Post Follow-up to this message
Show a Printable Version
Email This Page to Someone!
Receive updates to this thread
Powered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.