Displaying rotated ImageIcon on JScrollPane with menu bar




I am writing a large java application (not applet) that needs to
display a map image and overlay it with moving object icons. I also
want users to be able to zoom in and see detail and scroll around the
map, so I am drawing on a JPanel inside a JScrollPane inside a JFrame.
I also need to be able to rotate the icons and have a menu bar.

The map consists of approx. 3900 filled polygons. Because of this large
number, and because the map does not change, I am creating a
BufferedImage, drawing the polygons on that image, then using
Graphics2D.drawImage() to draw the map image on the JPanel. To zoom in,
I will eventually generate a larger image and redraw the map. For
testing, I am making the initail panel just about large enough to show
the whole map, then resizing the frame to make it smaller. This part is
working OK.

After drawing the map image in the JPanel, I draw an ImageIcon at each
position where there should be an object, using a rotational Affine
Transformation to rotate the graphics around the icon position
(actually the center of the icon and not the origin at the upper left
corner). This part is a little flakey.

The problem is that the icons are not always drawn in the correct
position. They are sometimes displaced upwards by what looks like the
height of the menu bar. This happens when the icons are drawn initially
and whenever I manually try to resize the window. However, whenever the
window is repainted, the icons are drawn at the correct positions.

The program at the end of this message illustrates the problem. For a
map, the program draws two rectangles, one blue and one green. A single
object at the middle of the rectangles is drawn rotated right by 30
deg. The window is updated after 20 seconds and every 5 seconds
thereafter.

There are several problems with this program's behaviour:

1. The aforementioned behaviour of the icons. Under Linux Red Hat 9,
Java 1.5, the icon is misplaced until the first repaint. Under Mac OS
X, Java 1.4.2, the icon starts out misplaced, but is quickly redrawn in
the correct location. Under both systems, resizing the screen moves the
icon until the next repaint is done. This behaviour goes away if either
the menu bar does not exist or if the icon is not rotated, and this is
why I say the displacement is about equal to the height of the menu
bar. It looks like the icon is drawn at a position relative to the
upper left corner of the menu bar and not of the panel.

2. The redrawing of the screen when a resizing is done can be very,
very slow, sometimes taking 10 seconds. The screen seems to be redrawn
at every 1 or 2 pixel locations, instead of just the final screen size.

3. The background of the icon is not transparent as I think it should
be.

4. I am required to adjust the drawn position of the icon by the value
of the scrollbars. In other words, it looks like the graphics context
of the icon is the viewport of the scroll pane, and not the underlying
panel, even though I am drawing the icon as part of paintComponent of
the JPanel and using the Graphics context provided. This is not
necessary when drawing the line and the label string.

Can anyone see what I am doing wrong or explain this behaviour? If not,
is there a work-around? Can anyone suggest a better approach that might
work better?

Thank you for reading this lengthy post.


// ScrollMap.java

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;

public class ScrollMap extends JFrame
{
JScrollPane scrollpane;
MapPanel map;
ImageIcon dot;
BufferedImage img;
Container mainw;

public ScrollMap() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(820,820);
mainw = getContentPane();
map = new MapPanel();
map.setBackground(Color.gray);
scrollpane = new JScrollPane( map,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS
);
mainw.add(scrollpane, BorderLayout.CENTER);
JMenuBar menu = new JMenuBar();
JMenu file = new JMenu("File");
menu.add(file);
JMenuItem item = new JMenuItem("Exit");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { System.exit(0);}
});
file.add(item);
setJMenuBar(menu); // comment out and it works
setVisible(true);
}

public void initialize() {

// create map image
int w = map.getWidth();
int h = map.getHeight();
map.setPreferredSize(new Dimension(w,h));
img = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
System.out.println("image size ("+w+","+h+") created");
Graphics2D g1 = (Graphics2D)img.getGraphics();
g1.setBackground(new Color(64,64,64));
g1.clearRect(0,0,w,h);
Rectangle2D.Float rec = new Rectangle2D.Float(200,200,400,200);
g1.setPaint(new Color(0,0,128));
g1.fill(rec);
rec.setRect(200,400,400,200);
g1.setPaint(new Color(0,128,0));
g1.fill(rec);

// create object icon as skinny oval
BufferedImage img2 =
new BufferedImage(20,40,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D)img2.getGraphics();
g2.setBackground(new Color(0,0,0,0));
g2.clearRect(0,0,20,40);
Ellipse2D.Float oval = new Ellipse2D.Float(4,0,12,40);
g2.setPaint(Color.yellow);
g2.fill(oval);
dot = new ImageIcon(img2);
}

public void repaint() { mainw.repaint();}

public static void main(String[] args) {
ScrollMap sm = new ScrollMap();
sm.initialize();
int delay = 20000;
while(true) {
try{
Thread.sleep(delay);
System.out.println("repainting screen");
sm.repaint();
delay = 5000;
}catch( InterruptedException e ){}
}
}

class MapPanel extends JPanel
{
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;

// get scrollbar positions
int x = scrollpane.getHorizontalScrollBar().getValue();
int y = scrollpane.getVerticalScrollBar().getValue();

// draw map image
g2.drawImage(img,0,0,null);

// draw rotated object at (400,400) but displaced by scroll values
int px = 400 - x;
int py = 400 - y;
AffineTransform save = g2.getTransform();
AffineTransform rotate = new AffineTransform();
rotate.setToRotation(0.523599,px,py);
g2.setTransform(rotate); // comment out and it works
dot.paintIcon(this,g2,px-10,py-20);
g2.setTransform(save);

// draw label for object at (400,400) with no displacement
Line2D.Float leader = new Line2D.Float(400,400,440,440);
g2.setPaint(Color.white);
g2.draw(leader);
g2.drawString("Object",442,446);
}
}
}

--
Jim Gibson


----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= East/West-Coast Server Farms - Total Privacy via Encryption =---
.



Relevant Pages

  • Creating Interactive Maps
    ... I need to display a map of North American on the Map. ... to drag icons from another window onto the map. ... need to "capture" the icon and determine whether or not the icon is in ... America with the cities Los Angeles, New York, Dallas, Tampa Bay, ...
    (comp.lang.java.gui)
  • Re: Rfc map link
    ... "Christine Dabney" wrote ... Google upgraded the map, and the old link doesn't work any more. ... Well, to redo your location, I need to delete your old icon first. ... do you place your marker. ...
    (rec.food.cooking)
  • Re: GPS Map
    ... display a icon in a map. ... Like the GPS application out there. ... But I need to plot that information into a map. ... from map DC to tempDC so image can be retrieved. ...
    (microsoft.public.vc.mfc)
  • Re: Where are YOU? (an rpca map)
    ... Use the slider to the left to zoom in by pushing ... Jill, ... I went to put my icon beneath Denise's on the Florida map. ...
    (rec.pets.cats.anecdotes)