I searched and found tons of questions here about my problem, but it seems I cannot implement correctly the solutions I found.
I have a JScrollPane
in which I put a custom JPanel
.
This custom JPanel
resized an image. This image is put in a JLabel
and the JLabel
in the custom JPanel
.
This is my code:
mainPanel = new PanelPictureV2(gr.getImage());
mainPanel.setBackground(Color.WHITE);
mainPanel.setLayout(new BorderLayout());
scrollPane = new JScrollPane(mainPanel);
add(scrollPane, BorderLayout.CENTER);
Here is my custom JPanel
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class PanelPictureV2 extends JPanel implements MouseWheelListener{
private double zoomFactor = 1;
private double zoomMin = -20;
private double zoomMax = 20;
private BufferedImage myPicture;
private BufferedImage newImage;
public PanelPictureV2(BufferedImage myPicture) {
this.myPicture = myPicture;
addMouseWheelListener(this);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
removeAll();
if(zoomFactor > zoomMax) zoomFactor = zoomMax;
if(zoomFactor < zoomMin) zoomFactor = zoomMin;
newImage = resize(myPicture, (int)(myPicture.getWidth() * zoomFactor), (int (myPicture.getHeight() * zoomFactor));
add(new JLabel(new ImageIcon(newImage)), BorderLayout.CENTER);
validate();
repaint();
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.isControlDown()) {
//Zoom in
if (e.getWheelRotation() < 0) {
zoomFactor *= 1.1;
repaint();
}
//Zoom out
if (e.getWheelRotation() > 0) {
zoomFactor /= 1.1;
repaint();
}
}
}
@Override
public Dimension getPreferredSize() {
return newImage == null ? new Dimension(200, 200) : new Dimension(newImage.getWidth(), newImage.getHeight());
}
private BufferedImage resize(BufferedImage myPicture, int width, int height) {
Image tmp = myPicture.getScaledInstance(width, height, Image.SCALE_SMOOTH);
BufferedImage dimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = dimg.createGraphics();
g2d.drawImage(tmp, 0, 0, null);
g2d.dispose();
return dimg;
}
public void setMyPicture(BufferedImage myPicture) {
this.myPicture = myPicture;
}
}
JScrollPane
does not work correctly.
I think I am missing somephing about the resizing of the image. Thank you.
Whoa: you've got bad code in the paintComponent here:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
removeAll(); // ***** here
if(zoomFactor > zoomMax) zoomFactor = zoomMax;
if(zoomFactor < zoomMin) zoomFactor = zoomMin;
// ********** all the code below
newImage = resize(myPicture, (int)(myPicture.getWidth() * zoomFactor), (int (myPicture.getHeight() * zoomFactor));
add(new JLabel(new ImageIcon(newImage)), BorderLayout.CENTER);
validate();
repaint();
// **********
}
The paintComponent method is for painting and painting only and should never be used to add or remove or create components or for calling revalidate or repaint.
Instead, get rid of the JLabel, the adding and removing of images and instead display the resized BufferedImage in the paintCompoent.
Myself, I would do the zooming and image creating and resizing in the mouse listener, and then in paintComponent simply call after the super's call, g.drawImage(myImage, 0, 0, null);
Or better still:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myPicture != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.scale(zoomFactor, zoomFactor);
g2d.drawImage(myPicture, 0, 0, null);
g2d.dispose();
}
}
Note that I am creating a new Graphics object so that the zoom transformation only affects the image drawing and no other drawing that may be performed down the graphics drawing chain. I also dispose of this same graphics object that I myself create and never the one given by the JVM (which would break the graphics chain).
Also, of course resize the preferred size based on the image size.