Re: Drawing an Image in a JPanel
Hi.
I've been through this a few weeks ago, and the best solution is to use
JPanel with mouse listeners and background image handling. Let's call
it ImagePanel.
Your ImagePanel class should of course extend JPanel and needs to have
following fields:
Image img;
int imgWidth, imgHeight;
First, you need to override JPanel's paint(Graphics g) method:
public void paint(Graphics g) {
super.paint(g);
if ((img != null) && (imgWidth > 0) && (imgHeight > 0)) {
g.drawImage(img, 0, 0, this);
}
}
and then make sure that your ImagePanel always has the size of your
image:
public Dimension getPreferredSize() {
return new Dimension(imgWidth,imgHeight);
}
You also need a method setting the image. In my example, it uses a byte
array containing the image data, because I'm storing the images in DB:
public void setImage(byte[] b) {
img = Toolkit.getDefaultToolkit().createImage(b);
imgWidth = img.getWidth(null);
imgHeight = img.getHeight(null);
}
Now you have an ImagePanel that displays an image as its background,
and its size always
fits the image size, so you can use it in JScrollPanes and so on.
Now, if you want to edit the image, use listeners. For example, my
ImagePanel allows user to make a selection inside the image:
Point dragFrom,dragTo;
public void mousePressed(MouseEvent e) {
dragFrom = e.getPoint();
}
public void mouseReleased(MouseEvent e) {
dragTo = e.getPoint();
}
public void paint(Graphics g) {
super.paint(g);
if ((img != null) && (imgWidth > 0) && (imgHeight > 0)) {
g.drawImage(img, 0, 0, this);
}
int dragFromX, dragFromY, dragToX, dragToY;
if(dragFrom.x < dragTo.x) {
dragFromX = dragFrom.x;
dragToX = dragTo.x;
} else {
dragFromX = dragTo.x;
dragToX = dragFrom.x;
}
if(dragFrom.y < dragTo.y) {
dragFromY = dragFrom.y;
dragToY = dragTo.y;
} else {
dragFromY = dragTo.y;
dragToY = dragFrom.y;
}
g.setColor(new Color(0, 0, 0));
g.setXORMode(new Color(255, 255, 255));
g.fillRect(dragFromX, dragFromY, dragToX - dragFromX, dragToY -
dragFromY);
}
For resizing, you need an additional field: Image imgBackup;
In setImage(byte[] b) create two images: imgBackup to store the initial
image and img to be painted in paint(Graphics g). Inside the method
resize(float resizeFloat) dispose of img and create it once again from
imgBackup, transforming it by the given resizeFloat value. This
prevents the image from loosing quality, because every time you
transform the initial image, which is never changed. Remember, that
imgWidth/imgHeight have to represent the actual size of the image, so
initiate it with img variables, not imgBackup.
As we come to a multiple-tool editing panel, you need different
behaviours of MouseListener methods for every tool. Creating a separate
MouseListener for every tool won't work - because you still have only
one paint(Graphics g) method. You can do it be defining a list
of possible tools as final int, for example TOOL_SELECT, TOOL_DRAW,
etc. Add a field
int tool and use switch/case blocks in paint(Graphics g) and each of
MouseListener methods.
Multi-tool event handling is always tricky, expect to spend at least
two days over this to plan everything right. It's easy to code, but the
hell lots of analysing, because you need to communicate between
different MouseListener methods - you start the action in one of them,
end it in another, and sometimes you have to catch also
mouseMoved/Dragged event in the middle. Make sure all those methods
always know, what action is the user planning to cause - and react
correctly in paint(Graphics g).
If you need some more help over this, just post :)
Michal K.