Mailing Lists: Apple Mailing Lists

Image of Mac OS face in stamp
 
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

painting / origin puzzle



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.

(Btw, this is a followup to a question several months ago...
Great thanks to several people who pointed out that I should be
overriding paintComponent() rather than paint().  I read through
the rendering tutorials suggested and rewrote the code, but still
have the same problem.  Took a couple months off hoping it would
just go away... :).

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 with jdk1.4 on 10.3.8, though the problem has been with me
on earlier releases, and I believe it is my programming rather
than an apple bug.

----------------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----------------




_______________________________________________ Do not post admin requests to the list. They will be ignored. Java-dev mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/java-dev/email@hidden

This email sent to email@hidden


Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2007 Apple Inc. All rights reserved.