I have a problem using Graphics to put an image in a jPanel. I have the next code:
JFileChooser navegador = new JFileChooser();
if (navegador.showOpenDialog(null) == 0) {
try {
BufferedImage imagenAbrir = ImageIO.read(navegador.getSelectedFile());
lienzo.paintComponents(imagenAbrir.getGraphics());
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Ocurriò un error al guardar la imàgen");
}
}
The code is part of a button, the user could select an imagen from any path, but it doesn't show anything in the panel. What could be the problem?
I think you have to change you method with BufferedImage object not a Graphics object
#Override
public void actionPerformed(ActionEvent e) {
JFileChooser navegador = new JFileChooser();
if (navegador.showOpenDialog(null) == 0) {
try {
BufferedImage imagenAbrir = ImageIO.read(navegador.getSelectedFile());
//drawPan.paintComponents(imagenAbrir.getGraphics());
drawPan.drawImage(imagenAbrir);
} catch (IOException ie) {
JOptionPane.showMessageDialog(null, "Ocurriò un error al guardar la imàgen");
}
}
}
Then, if you want to draw image, create customized JPanel class on your own.
The paintCompoent method of JComponent will be invoked automatically, every time you call repaint method in your code.
final class ImagePane extends JPanel {
private static final long serialVersionUID = 1L;
private BufferedImage myImage;
public ImagePane(final BufferedImage myImage) {
this.myImage = myImage;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(240, 220);
}
public void drawImage(BufferedImage img)
{
this.myImage = img;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myImage != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - myImage.getWidth()) / 2;
int y = (getHeight() - myImage.getHeight()) / 2;
g2d.drawImage(myImage, x, y, this);
g2d.dispose();
}
}
}
Here is full source code.
public class JFileChooserTest {
static Runnable doRun = new Runnable()
{
final class ChooseAction implements ActionListener
{
final ImagePane drawPan;
ChooseAction(final ImagePane drawPan)
{
this.drawPan = drawPan;
}
#Override
public void actionPerformed(ActionEvent e) {
JFileChooser navegador = new JFileChooser();
if (navegador.showOpenDialog(null) == 0) {
try {
BufferedImage imagenAbrir = ImageIO.read(navegador.getSelectedFile());
//drawPan.paintComponents(imagenAbrir.getGraphics());
drawPan.drawImage(imagenAbrir);
} catch (IOException ie) {
JOptionPane.showMessageDialog(null, "Ocurriò un error al guardar la imàgen");
}
}
}
}
final class ImagePane extends JPanel {
private static final long serialVersionUID = 1L;
private BufferedImage myImage;
public ImagePane(final BufferedImage myImage) {
this.myImage = myImage;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(240, 220);
}
public void drawImage(BufferedImage img)
{
this.myImage = img;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myImage != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - myImage.getWidth()) / 2;
int y = (getHeight() - myImage.getHeight()) / 2;
g2d.drawImage(myImage, x, y, this);
g2d.dispose();
}
}
}
#Override
public void run() {
final JFrame frame = new JFrame();
//frame.setSize(new Dimension(300,400));
JPanel lienzo = new JPanel();
lienzo.setLayout(new BorderLayout());
ImagePane drawPan = new ImagePane(null);
JButton drawMe = new JButton("draw me");
lienzo.add(drawMe, BorderLayout.NORTH);
lienzo.add(drawPan, BorderLayout.CENTER);
frame.add(lienzo);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
drawMe.addActionListener(new ChooseAction(drawPan));
}
};
public static void main(String[] args)
{
SwingUtilities.invokeLater(doRun);
}
}
I hope this will help you.
The code is part of a button, the user could select an imagen from any path, but it doesn't show anything in the panel. What could be the problem?
Basically, this is not how custom painting works in Swing. Never call paintComponent or paintComponents yourself, it's not your responsibility.
What you want to do is paint the image to the component via its Graphics context
Take a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting works and how you're suppose to use it
Then take a look at How to use lables for a simple solution for displaying images
You can also have a look at How to set a background picture in JPanel. It demonstrates using a JLabel and custom component for displaying an image
So, Do you want add image on the panel in which some base image is displayed?
If so, there is some trick to achieve to do this.
I prepare two images on the internet ( I am afraid these are licensed images )
Then, now i have three buttons put on your class
JButton drawMe = new JButton("draw me");
JButton pickMe = new JButton("pick me");
JButton clearMe = new JButton("clear me");
I decided to let the DrawAction class reuse with three action commands that are a draw, pick and clear together.
drawMe.addActionListener(drawAct);
drawMe.setActionCommand("draw");
pickMe.addActionListener(drawAct);
pickMe.setActionCommand("pick");
clearMe.addActionListener(drawAct);
clearMe.setActionCommand("clear");
We'll see the ImagePane class again. If you want to add a image on a image, you should have a paintcomponent method inherited from JComponent whatever components you want to use.
The 'draw me' button is to set the base image after clearing all images in the image list in which array list of the bufferedimage class.
public void drawImage(BufferedImage img)
{
if (imageList.size() > 0) imageList.clear();
imageList.add(img);
repaint();
}
The 'pick me' button is the method that add a image to the image list.
public void addImage(BufferedImage imagenAbrir) {
imageList.add(imagenAbrir);
repaint();
}
The last one is clear button, flush and clear all image buffers in the image list.
public void clearImage() {
imageList.clear();
isClear = true;
repaint();
}
Here is my trick to clear image on the panel, it is accomplished by re-drawing canvas(jPanel at this time) with some specific color(gray).
The main method, paintComponent as following..
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(isClear)
{
Graphics2D g2d = (Graphics2D) g.create();
Rectangle2D rectangle = new Rectangle2D.Double(0,0,getWidth(),getHeight());
g2d.setPaint(Color.GRAY);
g2d.fill(rectangle);
g2d.dispose();
isClear = false;
return;
}
if (imageList.size() > 0) {
BufferedImage img = null;
for(int i = 0; i < imageList.size(); i++)
{
img = imageList.get(i);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
Finally, you read the code below how to handle action commands along with java's component,
#Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("draw"))
{
JFileChooser navegador = new JFileChooser();
if (navegador.showOpenDialog(null) == 0) {
try {
BufferedImage imagenAbrir = ImageIO.read(navegador.getSelectedFile());
//drawPan.paintComponents(imagenAbrir.getGraphics());
drawPan.drawImage(imagenAbrir);
} catch (IOException ie) {
JOptionPane.showMessageDialog(null, "Ocurrio un error al guardar la imagen");
}
}
}
else if(e.getActionCommand().equals("pick"))
{
JFileChooser navegador = new JFileChooser();
if (navegador.showOpenDialog(null) == 0) {
try {
BufferedImage imagenAbrir = ImageIO.read(navegador.getSelectedFile());
//drawPan.paintComponents(imagenAbrir.getGraphics());
drawPan.addImage(imagenAbrir);
} catch (IOException ie) {
JOptionPane.showMessageDialog(null, "Ocurrio un error al guardar la imagen");
}
}
}
else if(e.getActionCommand().equals("clear"))
{
drawPan.clearImage();
}
}
As you see the code, picking a file is required every time you click both the pick or draw me button.
Full source code
package com.tobee.ui.test;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JFileChooserTest {
static Runnable doRun = new Runnable()
{
final class DrawAction implements ActionListener
{
final ImagePane drawPan;
DrawAction(final ImagePane drawPan)
{
this.drawPan = drawPan;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
if(e.getActionCommand().equals("draw"))
{
JFileChooser navegador = new JFileChooser();
if (navegador.showOpenDialog(null) == 0) {
try {
BufferedImage imagenAbrir = ImageIO.read(navegador.getSelectedFile());
//drawPan.paintComponents(imagenAbrir.getGraphics());
drawPan.drawImage(imagenAbrir);
} catch (IOException ie) {
JOptionPane.showMessageDialog(null, "Ocurriò un error al guardar la imàgen");
}
}
}
else if(e.getActionCommand().equals("pick"))
{
JFileChooser navegador = new JFileChooser();
if (navegador.showOpenDialog(null) == 0) {
try {
BufferedImage imagenAbrir = ImageIO.read(navegador.getSelectedFile());
//drawPan.paintComponents(imagenAbrir.getGraphics());
drawPan.addImage(imagenAbrir);
} catch (IOException ie) {
JOptionPane.showMessageDialog(null, "Ocurriò un error al guardar la imàgen");
}
}
}
else if(e.getActionCommand().equals("clear"))
{
drawPan.clearImage();
}
}
}
final class ImagePane extends JPanel {
private static final long serialVersionUID = 1L;
private boolean isClear;
private List<BufferedImage> imageList;
public ImagePane()
{
imageList = new ArrayList<BufferedImage>();
isClear = false;
}
public void clearImage() {
imageList.clear();
isClear = true;
repaint();
}
public void addImage(BufferedImage imagenAbrir) {
imageList.add(imagenAbrir);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(240, 220);
}
public void drawImage(BufferedImage img)
{
if (imageList.size() > 0) imageList.clear();
imageList.add(img);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(isClear)
{
Graphics2D g2d = (Graphics2D) g.create();
Rectangle2D rectangle = new Rectangle2D.Double(0,0,getWidth(),getHeight());
g2d.setPaint(Color.GRAY);
g2d.fill(rectangle);
g2d.dispose();
isClear = false;
return;
}
if (imageList.size() > 0) {
BufferedImage img = null;
for(int i = 0; i < imageList.size(); i++)
{
img = imageList.get(i);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
}
#Override
public void run() {
final JFrame frame = new JFrame();
JPanel lienzo = new JPanel();
lienzo.setLayout(new BorderLayout());
JPanel optionPan = new JPanel();
ImagePane drawPan = new ImagePane();
JButton drawMe = new JButton("draw me");
JButton pickMe = new JButton("pick me");
JButton clearMe = new JButton("clear me");
DrawAction drawAct = new DrawAction(drawPan);
optionPan.add(drawMe);
optionPan.add(pickMe);
optionPan.add(clearMe);
lienzo.add(optionPan, BorderLayout.NORTH);
lienzo.add(drawPan, BorderLayout.CENTER);
frame.add(lienzo);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
drawMe.addActionListener(drawAct);
drawMe.setActionCommand("draw");
pickMe.addActionListener(drawAct);
pickMe.setActionCommand("pick");
clearMe.addActionListener(drawAct);
clearMe.setActionCommand("clear");
}
};
public static void main(String[] args)
{
SwingUtilities.invokeLater(doRun);
}
}
Related
I am programming a sprite editor and I would like to implement an Undo button to my program. In order to achieve that, I have thought to use an ArrayList that store my updated BufferedImage after each action in an ArrayList. Then I will just read the ArrayList and find the right image to draw thanks to an index. However, it seems like it always store the same image. I don't know what I am doing wrong so I am asking for your help and advice.
Here is a test code:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
#SuppressWarnings("serial")
public class FromGraphicsToBufferedImage extends JPanel{
private static final int BI_WIDTH = 600;
private static final int BI_HEIGHT = BI_WIDTH;
private static BufferedImage bImage = new BufferedImage(BI_WIDTH, BI_HEIGHT, BufferedImage.TYPE_INT_ARGB); //Enregistrement de l'image en RGBA
private List<Point> pointList = new ArrayList<Point>();
private JLabel imageLabel;
private boolean isInit = false;
private static ArrayList<BufferedImage> historic = new ArrayList<BufferedImage>();
private int historicIndex = 0;
//Constructeur
public FromGraphicsToBufferedImage() {
imageLabel = new JLabel(new ImageIcon(bImage)) {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintInLabel(g);
}
};
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
imageLabel.addMouseListener(myMouseAdapter);
imageLabel.addMouseMotionListener(myMouseAdapter);
imageLabel.setBorder(BorderFactory.createEtchedBorder());
JButton saveImageBtn = new JButton("Save Image");
saveImageBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
saveImageActionPerformed();
}
});
JButton clearImageBtn = new JButton("Clear Image");
clearImageBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Graphics2D g2 = bImage.createGraphics();
g2.setBackground(new Color(255,255,255,0));
g2.clearRect(0, 0, BI_WIDTH, BI_HEIGHT);
g2.dispose();
imageLabel.repaint();
}
});
JButton undo = new JButton("Undo");
undo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("UNDO");
historicIndex -= 1;
bImage = historic.get(historicIndex);
Graphics2D g2 = bImage.createGraphics();
g2.drawImage(bImage, 0, 0, bImage.getWidth(), bImage.getHeight(), imageLabel);
g2.dispose();
imageLabel.setIcon(new ImageIcon(bImage));
imageLabel.repaint();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(saveImageBtn);
btnPanel.add(clearImageBtn);
btnPanel.add(undo);
setLayout(new BorderLayout());
add(imageLabel, BorderLayout.CENTER);
add(btnPanel, BorderLayout.SOUTH);
} //Fin du Constructeur
private void saveImageActionPerformed() {
JFileChooser filechooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG Images", "png");
filechooser.setFileFilter(filter);
int result = filechooser.showSaveDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File saveFile = filechooser.getSelectedFile();
try {
ImageIO.write(bImage, "png", saveFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void paintInLabel(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d = bImage.createGraphics();
if(isInit == false) {
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
g2d.dispose();
isInit = true;
}
else {
g2d.setColor(Color.BLUE);
if(pointList.size() == 0) {
return;
}
//System.out.println(bImage.getRGB(50, 50));
int x1 = pointList.get(0).x;
int y1 = pointList.get(0).y;
int x2 = pointList.get(0).x+32;
int y2 = pointList.get(0).y+32;
g2d.setComposite(AlphaComposite.Src);
g2d.setColor(new Color(255,255,255,0));
g2d.fillRect(x1,y1,32,32);
g2d.dispose();
pointList.clear();
}
historic.add(deepCopy(bImage));
imageLabel.repaint();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
pointList.add(e.getPoint());
imageLabel.repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
//historic.add(deepCopy(bImage));
System.out.println("Historic Size: " + historic.size());
int tailleHistorique = historic.size();
historicIndex = tailleHistorique-1;
if(historic.size() >= 2) {
System.out.println("The 2 images are the same: " + compareImages(historic.get(historicIndex-1), historic.get(historicIndex)));
}
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("DrawAndSaveImage");
frame.getContentPane().add(new FromGraphicsToBufferedImage());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static BufferedImage getBufferedImage() {
return bImage;
}
public static boolean compareImages(BufferedImage imgA, BufferedImage imgB) {
if (imgA.getWidth() == imgB.getWidth() && imgA.getHeight() == imgB.getHeight()) {
int largeurImage = imgA.getWidth();
int hauteurImage = imgA.getHeight();
for (int y = 0; y < hauteurImage; y++) {
for (int x = 0; x < largeurImage; x++) {
if (imgA.getRGB(x, y) != imgB.getRGB(x, y)){
return false;
}
}
}
}
else {
return false;
}
return true;
}
static BufferedImage deepCopy(BufferedImage bi) {
ColorModel cm = bi.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = bi.copyData(null);
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
DeepCopy Code Snippet
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
#SuppressWarnings("serial")
public class FromGraphicsToBufferedImage extends JPanel{
private static final int BI_WIDTH = 600;
private static final int BI_HEIGHT = BI_WIDTH;
private static BufferedImage bImage = new BufferedImage(BI_WIDTH, BI_HEIGHT, BufferedImage.TYPE_INT_ARGB); //Enregistrement de l'image en RGBA
private List<Point> pointList = new ArrayList<Point>();
private JLabel imageLabel;
private boolean isInit = false;
private static ArrayList<BufferedImage> historic = new ArrayList<BufferedImage>();
private int historicIndex = 0;
//Constructeur
public FromGraphicsToBufferedImage() {
imageLabel = new JLabel(new ImageIcon(bImage)) {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintInLabel(g);
}
};
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
imageLabel.addMouseListener(myMouseAdapter);
imageLabel.addMouseMotionListener(myMouseAdapter);
imageLabel.setBorder(BorderFactory.createEtchedBorder());
JButton saveImageBtn = new JButton("Save Image");
saveImageBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
saveImageActionPerformed();
}
});
JButton clearImageBtn = new JButton("Clear Image");
clearImageBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Graphics2D g2 = bImage.createGraphics();
g2.setBackground(new Color(255,255,255,0));
g2.clearRect(0, 0, BI_WIDTH, BI_HEIGHT);
g2.dispose();
imageLabel.repaint();
}
});
JButton undo = new JButton("Undo");
undo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("UNDO");
historicIndex -= 1;
bImage = historic.get(historicIndex);
Graphics2D g2 = bImage.createGraphics();
g2.drawImage(bImage, 0, 0, bImage.getWidth(), bImage.getHeight(), imageLabel);
g2.dispose();
imageLabel.setIcon(new ImageIcon(bImage));
imageLabel.repaint();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(saveImageBtn);
btnPanel.add(clearImageBtn);
btnPanel.add(undo);
setLayout(new BorderLayout());
add(imageLabel, BorderLayout.CENTER);
add(btnPanel, BorderLayout.SOUTH);
} //Fin du Constructeur
private void saveImageActionPerformed() {
JFileChooser filechooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG Images", "png");
filechooser.setFileFilter(filter);
int result = filechooser.showSaveDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File saveFile = filechooser.getSelectedFile();
try {
ImageIO.write(bImage, "png", saveFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void paintInLabel(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d = bImage.createGraphics();
if(isInit == false) {
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
g2d.dispose();
isInit = true;
}
else {
g2d.setColor(Color.BLUE);
if(pointList.size() == 0) {
return;
}
//System.out.println(bImage.getRGB(50, 50));
int x1 = pointList.get(0).x;
int y1 = pointList.get(0).y;
int x2 = pointList.get(0).x+32;
int y2 = pointList.get(0).y+32;
g2d.setComposite(AlphaComposite.Src);
g2d.setColor(new Color(255,255,255,0));
g2d.fillRect(x1,y1,32,32);
g2d.dispose();
pointList.clear();
}
historic.add(deepCopy(bImage));
imageLabel.repaint();
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
pointList.add(e.getPoint());
imageLabel.repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
//historic.add(deepCopy(bImage));
System.out.println("Historic Size: " + historic.size());
int tailleHistorique = historic.size();
historicIndex = tailleHistorique-1;
if(historic.size() >= 2) {
System.out.println("The 2 images are the same: " + compareImages(historic.get(historicIndex-1), historic.get(historicIndex)));
}
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("DrawAndSaveImage");
frame.getContentPane().add(new FromGraphicsToBufferedImage());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static BufferedImage getBufferedImage() {
return bImage;
}
public static boolean compareImages(BufferedImage imgA, BufferedImage imgB) {
if (imgA.getWidth() == imgB.getWidth() && imgA.getHeight() == imgB.getHeight()) {
int largeurImage = imgA.getWidth();
int hauteurImage = imgA.getHeight();
for (int y = 0; y < hauteurImage; y++) {
for (int x = 0; x < largeurImage; x++) {
if (imgA.getRGB(x, y) != imgB.getRGB(x, y)){
return false;
}
}
}
}
else {
return false;
}
return true;
}
static BufferedImage deepCopy(BufferedImage bi) {
ColorModel cm = bi.getColorModel();
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
WritableRaster raster = bi.copyData(null);
return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
I used the first answer of Zoom box for area around mouse location on screen to create a Zoom Box Window around mouse location that would zoom into images as the mouse moves.
Now, I wanna know how to activate this Zoom Box View when a JCheckBox is checked and desactivate it if it's unchecked.
I modified the classes ZoomBoxWindow and ZoomPane written by #MadProgrammer by adding the lines of code for activating and desactivating the ZoomBoxView, but this doesn't seem to work. Could you please tell me what am I doing wrong?
Here is the code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.JCheckBox;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
public class ZoomPane extends JPanel {
protected static final int ZOOM_AREA = 40;
private JComponent parent;
private JWindow popup;
private Boolean zoomBoxActivated = false;
private BufferedImage buffer;
private float zoomLevel = 2f;
public ZoomPane(JComponent parent, Boolean zba) {
this.parent = parent;
this.zoomBoxActivated=zba;
popup = new JWindow();
popup.setLayout(new BorderLayout());
popup.add(this);
popup.pack();
popup.setAlwaysOnTop(true);
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
Point p = e.getPoint();
Point pos = e.getLocationOnScreen();
updateBuffer(p);
popup.setLocation(pos.x - 20, pos.y + 20);
repaint();
}
#Override
public void mouseEntered(MouseEvent e) {
if(zoomBoxActivated){
popup.setVisible(true);
}
else {
popup.setVisible(false);
}
}
#Override
public void mouseExited(MouseEvent e) {
popup.setVisible(false);
}
};
parent.addMouseListener(ma);
parent.addMouseMotionListener(ma);
}
protected void updateBuffer(Point p) {
int width = Math.round(ZOOM_AREA);
int height = Math.round(ZOOM_AREA);
buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
AffineTransform at = new AffineTransform();
int xPos = (ZOOM_AREA / 2) - p.x;
int yPos = (ZOOM_AREA / 2) - p.y;
if (xPos > 0) {
xPos = 0;
}
if (yPos > 0) {
yPos = 0;
}
if ((xPos * -1) + ZOOM_AREA > parent.getWidth()) {
xPos = (parent.getWidth() - ZOOM_AREA) * -1;
}
if ((yPos * -1) + ZOOM_AREA > parent.getHeight()) {
yPos = (parent.getHeight()- ZOOM_AREA) * -1;
}
at.translate(xPos, yPos);
g2d.setTransform(at);
parent.paint(g2d);
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (buffer != null) {
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
g2d.drawImage(buffer, 0, 0, this);
g2d.setTransform(at);
}
g2d.setColor(Color.RED);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.dispose();
}
}
public class TestPane extends JPanel {
private BufferedImage img;
public TestPane() {
try {
img = ImageIO.read(new File("satellite-image-of-spain.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
g2d.dispose();
}
}
}
public class ZoomBoxWindow {
ZoomPane zoomPane;
public static void main(String[] args) {
new ZoomBoxWindow();
}
public ZoomBoxWindow() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane pane = new TestPane();
zoomPane = new ZoomPane(pane, false);
JPanel buttonPanel = new JPanel(new BorderLayout());
JCheckBox zoomBoxChkBox = new JCheckBox("Zoom Box");
zoomBoxChkBox.setMnemonic(KeyEvent.VK_Z);
zoomBoxChkBox.setSelected(false);
zoomBoxChkBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
if ( e.getStateChange() == ItemEvent.SELECTED) {
zoomPane = new ZoomPane(pane,true);
}
else {
zoomPane = new ZoomPane(pane,false);
}
}
});
buttonPanel.add(zoomBoxChkBox);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane,BorderLayout.CENTER);
frame.add(buttonPanel, BorderLayout.PAGE_START);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Thank you for your answer.
So,
zoomBoxChkBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
if (e.getStateChange() == ItemEvent.SELECTED) {
zoomPane = new ZoomPane(pane, true);
} else {
zoomPane = new ZoomPane(pane, false);
}
}
});
Isn't really doing anything, you're just create a new instance of ZoomPane. Apart from adding a bunch of MouseListeners to the parent component, which could cause you no end of issues.
Instead, I'd add a new method to ZoomPane
public class ZoomPane extends JPanel {
private boolean isAutoDisplayEnabled = false;
//...
public void setShowZoomPopup(boolean show) {
popup.setVisible(show);
isAutoDisplayEnabled = show;
}
This now allows you to control the visibility state of the popup externally.
Now, the isAutoDisplayEnabled flag is simply used to determine if the popup should be displayed when the mouseEntered event is triggered, for example...
MouseAdapter ma = new MouseAdapter() {
//...
#Override
public void mouseEntered(MouseEvent e) {
if (isAutoDisplayEnabled) {
popup.setVisible(true);
}
}
Now your ItemListener can control the state of the popup
zoomBoxChkBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
// TODO Auto-generated method stub
if (e.getStateChange() == ItemEvent.SELECTED) {
zoomPane.setShowZoomPopup(true);
} else {
zoomPane.setShowZoomPopup(false);
}
}
});
You could also add a check to see if the mouse is currently within the bounds of the image pane, so you don't show it needlessly, but I'll leave that to you to try and figure out ;)
the popup is flickering as it is being moved
This is, because every time the popup is displayed, it triggers a mouseExit event, which triggers the popup to be hidden, which then triggers a mouseEnter event and so on and so forth...
This is a slightly different take on the same idea, but, instead of a separate window, this paints the zoom as part of the image pane itself.
This does mean that, if the zoom falls beyond the bounds of the panel, it will be truncated, but I've spent some time so that you can resize the panel larger than the image and the zoom effect will still work
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ZoomBoxWindow {
public static void main(String[] args) {
new ZoomBoxWindow();
}
public ZoomBoxWindow() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane pane = new TestPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage img;
private Point zoomPoint;
private boolean zoomEnabled = true;
private int zoomArea = 80;
private float zoom = 2.0f;
public TestPane() {
try {
img = ImageIO.read(new File("/Volumes/Big Fat Extension/Dropbox/MegaTokyo/_cg_1009___Afraid___by_Serena_Clearwater.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
zoomPoint = e.getPoint();
repaint();
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
repaint();
}
#Override
public void mouseExited(MouseEvent e) {
zoomPoint = null;
repaint();
}
});
}
public float getZoom() {
return zoom;
}
public void setZoom(float zoom) {
this.zoom = zoom;
repaint();
}
public int getZoomArea() {
return zoomArea;
}
public void setZoomArea(int zoomArea) {
this.zoomArea = zoomArea;
repaint();
}
public boolean isZoomEnabled() {
return zoomEnabled;
}
public void setZoomEnabled(boolean zoomEnabled) {
this.zoomEnabled = zoomEnabled;
repaint();
}
#Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
protected Point getOffset() {
if (img == null) {
return new Point(0, 0);
}
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
return new Point(x, y);
}
protected Rectangle getImageBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
if (img != null) {
bounds.setLocation(getOffset());
bounds.setSize(img.getWidth(), img.getHeight());
}
return bounds;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
Point offset = getOffset();
g2d.drawImage(img, offset.x, offset.y, this);
if (zoomPoint != null) {
BufferedImage zoomBuffer = updateBuffer(zoomPoint);
if (zoomBuffer != null) {
Rectangle bounds = getZoomBounds();
g2d.drawImage(zoomBuffer, bounds.x, bounds.y, this);
g2d.setColor(Color.RED);
g2d.draw(bounds);
}
}
g2d.dispose();
}
}
protected Rectangle getZoomBounds() {
Rectangle bounds = null;
if (zoomPoint != null && img != null) {
int zoomArea = getZoomArea();
int xPos = zoomPoint.x - (zoomArea / 2);
int yPos = zoomPoint.y - (zoomArea / 2);
Rectangle zoomBounds = new Rectangle(xPos, yPos, zoomArea, zoomArea);
Rectangle imageBounds = getImageBounds();
bounds = imageBounds.intersection(zoomBounds);
System.out.println(bounds);
}
return bounds;
}
protected BufferedImage updateBuffer(Point p) {
if (zoomPoint == null) {
return null;
}
Rectangle bounds = getZoomBounds();
Point offset = getOffset();
bounds.translate(-offset.x, -offset.y);
if (bounds.x < 0 || bounds.y < 0 || bounds.width <= 0 || bounds.height <= 0) {
return null;
}
BufferedImage zoomBuffer = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = zoomBuffer.createGraphics();
BufferedImage sample = img.getSubimage(bounds.x, bounds.y, bounds.width, bounds.height);
double zoom = getZoom();
Image scaled = sample.getScaledInstance((int) (bounds.width * zoom), (int) (bounds.height * zoom), Image.SCALE_SMOOTH);
g2d.drawImage(scaled, 0, 0, this);
g2d.dispose();
return zoomBuffer;
}
}
}
Assigning a new ZoomPane to the zoomPane field will do nothing on the actual displayed ZoomPane.
What you want is to tell the existing ZoomPane to switch its zoom policy.
You could do that by adding the following method to ZoomPane :
void switchZoomBoxActivated() {
zoomBoxActivated = !zoomBoxActivated;
}
Then in the ItemListener, just call it this way :
#Override
public void itemStateChanged(final ItemEvent e) {
zoomPane.switchZoomBoxActivated();
}
Here is my code. I am drawing rectangle, oval, lines on the image. Drawing a line is working fine. I can draw the rectangle, but it is not visible on mouse drag. How to modify this program to show rectangle on mouse drag. How to provide eraser for this program to erase only the shapes while preserving the background image.
package com.sobis.hindalco.bean
import java.awt.*;
import java.awt.RenderingHints.Key;
import java.awt.event.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
public class ImageEdit extends JFrame{
private BufferedImage originalImage;
private BufferedImage canvasImage;
private JPanel gui;
private Color color = Color.WHITE;
private JLabel output = new JLabel("You DooDoodle!");
BufferedImage image=null;
private BufferedImage colorSample = new BufferedImage(
16,16,BufferedImage.TYPE_INT_RGB);
private JLabel imageLabel;
private int activeTool;
public static final int RECTANGLE_TOOL = 0;
public static final int DRAW_TOOL = 1;
public static final int TEXT_TOOL = 2;
public static final int ERASER_TOOL = 3;
public static final int OVAL_TOOL = 4;
Point startDrag, endDrag;
private Point selectionStart;
private Rectangle selection;
private boolean dirty = false;
// private Stroke stroke = new BasicStroke(
// 3,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND,1.7f);
private RenderingHints renderingHints;
public JComponent getGui() {
if(gui==null) {
Map<Key, Object> hintsMap = new
HashMap();
hintsMap.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
hintsMap.put(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
hintsMap.put(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
renderingHints = new RenderingHints(hintsMap);
setImage(new BufferedImage(320,240,BufferedImage.TYPE_INT_RGB));
gui = new JPanel(new BorderLayout(4,4));
gui.setBorder(new EmptyBorder(5,3,5,3));
JPanel imageView = new JPanel(new GridBagLayout());
imageView.setPreferredSize(new Dimension(480,320));
imageLabel = new JLabel(new ImageIcon(canvasImage));
JScrollPane imageScroll = new JScrollPane(imageView);
imageView.add(imageLabel);
imageLabel.addMouseMotionListener(new
ImageMouseMotionListener());
imageLabel.addMouseListener(new ImageMouseListener());
gui.add(imageScroll,BorderLayout.CENTER);
JToolBar tb = new JToolBar();
tb.setFloatable(false);
JButton colorButton = new JButton("Color");
colorButton.setMnemonic('o'); colorButton.setToolTipText("Choose a Color");
ActionListener colorListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Color c = JColorChooser.showDialog(
gui, "Choose a color", color);
if(c!=null) {
setColor(c);
}
}
};
colorButton.addActionListener(colorListener);
colorButton.setIcon(new ImageIcon(colorSample));
tb.add(colorButton);
setColor(color);
// final SpinnerNumberModel strokeModel =
// new SpinnerNumberModel(3,1,16,1);
/// JSpinner strokeSize = new JSpinner(strokeModel);
ChangeListener strokeListener = new ChangeListener() {
#Override
public void stateChanged(ChangeEvent arg0) {
}
};
tb.addSeparator();
ActionListener clearListener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
int result = JOptionPane.OK_OPTION;
if(dirty) {
result = JOptionPane.showConfirmDialog(
gui, "Erase the current painting?");
}
if(result==JOptionPane.OK_OPTION) {
clear(canvasImage);
}
}
};
JButton clearButton = new JButton("Clear");
tb.add(clearButton);
clearButton.addActionListener(clearListener);
gui.add(tb, BorderLayout.PAGE_START);
JToolBar tools = new JToolBar(JToolBar.VERTICAL);
tools.setFloatable(false);
JButton crop = new JButton("Crop");
final JRadioButton select = new JRadioButton("Rectangle", true);
final JRadioButton eraser = new JRadioButton("Eraser", true);
final JRadioButton draw = new JRadioButton("Draw");
final JRadioButton text = new JRadioButton("Text");
final JRadioButton oval = new JRadioButton("oval");
tools.add(select);
tools.add(draw);
tools.add(text);
tools.add(eraser);
tools.add(oval);
ButtonGroup bg = new ButtonGroup();
bg.add(select);
bg.add(text);
bg.add(draw);
bg.add(eraser);
bg.add(oval);
ActionListener toolGroupListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
if(ae.getSource()==select) {
activeTool = RECTANGLE_TOOL;
}else if(ae.getSource()==draw) {
activeTool = DRAW_TOOL;
}else if(ae.getSource()==text) {
activeTool = TEXT_TOOL;
}else if(ae.getSource()==eraser) {
activeTool = ERASER_TOOL;
}else if(ae.getSource()==oval) {
activeTool = OVAL_TOOL;
}
}
};
select.addActionListener(toolGroupListener);
draw.addActionListener(toolGroupListener);
text.addActionListener(toolGroupListener);
eraser.addActionListener(toolGroupListener);
oval.addActionListener(toolGroupListener);
gui.add(tools, BorderLayout.LINE_END);
gui.add(output,BorderLayout.PAGE_END);
clear(colorSample);
clear(canvasImage);
}
return gui;
}
/** Clears the entire image area by painting it with the current color. */
public void clear(BufferedImage bi) {
try{
image = ImageIO.read(new File("D:\\images.jpeg"));
}catch(Exception e){
}
this.originalImage = image;
int w = image.getWidth();
int h = image.getHeight();
canvasImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.drawImage(image, 0, 0, gui);
g.dispose();
selection = new Rectangle(0,0,w,h);
if(this.imageLabel!=null) {
imageLabel.setIcon(new ImageIcon(canvasImage));
this.imageLabel.repaint();
}
if(gui!=null) {
gui.invalidate();
}
}
public void setImage(BufferedImage image1) {
try{
image = ImageIO.read(new File("D:\\images.jpeg"));
}catch(Exception e){
}
this.originalImage = image;
int w = image.getWidth();
int h = image.getHeight();
canvasImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.drawImage(image, 0, 0, gui);
g.dispose();
selection = new Rectangle(0,0,w,h);
if(this.imageLabel!=null) {
imageLabel.setIcon(new ImageIcon(canvasImage));
this.imageLabel.repaint();
}
if(gui!=null) {
gui.invalidate();
}
}
/** Set the current painting color and refresh any elements needed. */
public void setColor(Color color) {
this.color = color;
clear(colorSample);
}
private JMenu getFileMenu(boolean webstart){
JMenu file = new JMenu("File");
file.setMnemonic('f');
//JMenuItem newImageItem = new JMenuItem("New");
//newImageItem.setMnemonic('n');
ActionListener newImage = new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
BufferedImage bi = new BufferedImage(
360, 300, BufferedImage.TYPE_INT_ARGB);
clear(bi);
setImage(bi);
}
};
if(webstart) {
//TODO Add open/save functionality using JNLP API
}else{
//TODO Add save functionality using J2SE API
file.addSeparator();
ActionListener saveListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JFileChooser ch = getFileChooser();
int result = ch.showSaveDialog(gui);
if(result==JFileChooser.APPROVE_OPTION ) {
try {
File f = ch.getSelectedFile();
ImageIO.write(ImageEdit.this.canvasImage, "png",
f); ImageEdit.this.originalImage =
ImageEdit.this.canvasImage;
dirty = false;
} catch (IOException ioe) {
showError(ioe);
ioe.printStackTrace();
}
}
}
};
JMenuItem saveItem = new JMenuItem("Save");
saveItem.addActionListener(saveListener);
saveItem.setMnemonic('s');
file.add(saveItem);
}
if(canExit()) {
ActionListener exit = new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
System.exit(0);
}
};
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.setMnemonic('x');
file.addSeparator();
exitItem.addActionListener(exit);
file.add(exitItem);
}
return file;
}
private void showError(Throwable t) {
JOptionPane.showMessageDialog(
gui,
t.getMessage(),
t.toString(),
JOptionPane.ERROR_MESSAGE);
}
JFileChooser chooser = null;
public JFileChooser getFileChooser() {
if(chooser==null) {
chooser = new JFileChooser();
FileFilter ff= new FileNameExtensionFilter( "myfiles","jpg",
"jpeg","png");
chooser.addChoosableFileFilter(ff);
}
return chooser;
}
public boolean canExit() {
boolean canExit = false;
SecurityManager sm = System.getSecurityManager();
if(sm==null) {
canExit = true;
}else{
try {
sm.checkExit(0);
canExit = true;
} catch(Exception stayFalse) {
}
}
return canExit;
}
public JMenuBar getMenuBar(boolean webstart){
JMenuBar mb = new JMenuBar();
mb.add(this.getFileMenu(webstart));
return mb;
}
public void openPanel() {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
// use default
}
ImageEdit bp = new ImageEdit();
JFrame f = new JFrame("Image Editing");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(bp.getGui());
f.setJMenuBar(bp.getMenuBar(false));
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
public void text(Point point) {
String text = JOptionPane.showInputDialog(gui, "Text to add",
"Text");
if(text!=null) {
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.setColor(this.color);
// g.setStroke(stroke);
int n = 0;
g.drawString(text,point.x,point.y);
g.dispose();
this.imageLabel.repaint();
}
}
public void draw(Point point) {
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.setColor(this.color);
int n = 0;
g.drawLine(point.x, point.y, point.x+n, point.y+n);
g.dispose();
this.imageLabel.repaint();
}
public void drawRectangle() {
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.setColor(this.color);
g.drawRect(Math.min(startDrag.x, endDrag.x), Math.min(
startDrag.y,endDrag.y), Math.abs(startDrag.x -endDrag.x),
Math.abs(startDrag.y - endDrag.y));
this.imageLabel.repaint();
}
public void eraser(Point point) {
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.setColor(this.color);
int n = 0;
g.clearRect(point.x, point.y, point.x+n, point.y+n);
g.dispose();
this.imageLabel.repaint();
}
public void oval() {
Graphics2D g = this.canvasImage.createGraphics();
g.setRenderingHints(renderingHints);
g.setColor(this.color);
// g.setStroke(stroke);
int n = 0;
// g.clearRect(x1,y1,x2,y2);
g.dispose();
this.imageLabel.repaint();
}
class ImageMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent arg0) {
if(activeTool==ImageEdit.TEXT_TOOL) {
// TODO
text(arg0.getPoint());
}else if(activeTool==ImageEdit.ERASER_TOOL) {
// TODO
eraser(arg0.getPoint());
}else if(activeTool==ImageEdit.ERASER_TOOL) {
// TODO
draw(arg0.getPoint());
}else{
startDrag = new Point(arg0.getX(), arg0.getY());
endDrag = startDrag;
}
}
#Override
public void mouseReleased(MouseEvent arg0) {
if(activeTool==ImageEdit.RECTANGLE_TOOL) {
endDrag = new Point( arg0.getX(), arg0.getY());
drawRectangle();
}
}
}
class ImageMouseMotionListener implements MouseMotionListener {
#Override
public void mouseDragged(MouseEvent arg0) {
reportPositionAndColor(arg0);
endDrag = new Point( arg0.getX(), arg0.getY());
if(activeTool==ImageEdit.DRAW_TOOL) {
draw(arg0.getPoint());
}else if(activeTool==ImageEdit.RECTANGLE_TOOL) {
endDrag = new Point( arg0.getX(), arg0.getY());
}else if(activeTool==ImageEdit.OVAL_TOOL) {
oval();
}
}
#Override
public void mouseMoved(MouseEvent arg0) {
reportPositionAndColor(arg0);
}
}
private void reportPositionAndColor(MouseEvent me) {
String text = "";
if(activeTool==ImageEdit.RECTANGLE_TOOL) {
text += "Selection (X,Y:WxH): " +
(int)selection.getX() +
"," +
(int)selection.getY() +
":" +
(int)selection.getWidth() +
"x" +
(int)selection.getHeight();
}else{
text += "X,Y: " + (me.getPoint().x+1) + "," +
(me.getPoint().y+1);
}
output.setText(text);
}
}
How to modify this program to show rectangle on mouse drag.
You can check out Custom Painting Approaches.
Both approaches draw a temporary Rectangle as you hold down the mouse and drag it. Basically you need to handle mousePressed to track the starting point, mouseDragged to get the current mouse point (and to a repaint()) and mouseReleased to save the actual Rectangle.
How to provide eraser for this program to erase only the shapes while preserving the background image.
You would probably want to use the Draw On Component approach from the above link. Then you would iterated through the List of shapes to determine if the mouse point is contained by the shape. If so, then you would remove the shapes from the List. So this will only permit erasure of entire shapes.
I'd like to do JButton with nice transition effect. I write a class which extend by JButton and add to it custom MouseAdapter. It almost works, but if opacity should have 0 my one BufferedImage don't vanish.
Here my all source code:
public class ImageHoverButton extends JButton {
public class MouseListener extends MouseAdapter
{
public void mouseExited(MouseEvent me)
{
new Thread(new Runnable()
{
public void run()
{
for (float i = 1f; i >= 0f; i -= .03f)
{
setOpacity(i);
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
}
}
}).start();
}
public void mouseEntered(MouseEvent me)
{
new Thread(new Runnable()
{
public void run()
{
for (float i = 0f; i <= 1f; i += .03f)
{
setOpacity(i);
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
}
}
}).start();
}
public void mousePressed(MouseEvent me)
{
new Thread(new Runnable()
{
public void run()
{
for (float i = 1f; i >= 0.6f; i -= .1f)
{
setOpacity(i);
try
{
Thread.sleep(1);
}
catch (Exception e)
{
}
}
}
}).start();
}
}
private static final long serialVersionUID = 1L;
private BufferedImage imgBottom;
private BufferedImage imgHover;
private BufferedImage imgHoverRGB;
// filter to imgInActive
float[] scales = { 1f, 1f, 1f, 0f};
float[] offsets = new float[4];
RescaleOp rop = new RescaleOp(scales, offsets, null);
/**
* Constructor for image path
* #param img
* #param x
* #param y
*/
public ImageHoverButton(String imgBottomPath, String imgHoverPath, int x, int y) {
try {
this.imgBottom = ImageIO.read(new File(imgBottomPath));
this.imgHover = ImageIO.read(new File(imgHoverPath));
imgHoverRGB = new BufferedImage(imgHover.getWidth(null),
imgHover.getHeight(null),
BufferedImage.TYPE_INT_ARGB);
Graphics g = imgHoverRGB.getGraphics();
g.drawImage(imgHover, 0, 0, null);
} catch (IOException e) {
}
this.setBounds(x, y, imgBottom.getWidth() + 40 , imgBottom.getHeight() + 50);
addMouseListener(new MouseListener());
setOpacity(0f);
setOpaque(false);
setBorderPainted(false);
setRolloverEnabled(false);
setCursor(new Cursor(Cursor.HAND_CURSOR));
setLayout(null);
}
public void setOpacity(float opacity) {
scales[3] = opacity;
rop = new RescaleOp(scales, offsets, null);
repaint();
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(imgBottom, 50, 50, null);
g2d.drawImage(imgHoverRGB, rop, 0, 0);
}
}
Have any idea how to improve this?
I'm not so familiar with RescaleOp, and can't remember having used this before. But it seems like the results of applying it in this case are somewhat unexpected.
As an alternative, you might consider an AlphaComposite. The minimum modification that is necessary to achieve the desired effect would then be to change the line
g2d.drawImage(imgHoverRGB, rop, 0, 0);
to
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, scales[3]));
g2d.drawImage(imgHoverRGB, 0, 0, null);
However, there are several other issues with the code:
don't override paint. Instead, override paintComponent
don't call setBounds on a component (particlularly not in a constructor). The placement should be done by a layout manager
don't swallow Exceptions silently
don't load the images in the constructor of the button
implement getPreferredSize properly
don't spawn hundreds of threads due to mouse movement. (When you quickly move the mouse in and out, you'll have several threads running - some of them increasing the opacity, and some of them decreasing the opacity)
I created an example showing one possible approach: It contains an OpacityAnimator that allows a transition between two opacities, with a predefined delay in milliseconds. This animator is used to increase the opacity of the foreground image when the button is hovered with the mouse, and to decrease it when the mouse leaves the button.
(Note that this could be generalized further, and there are many possible "configuration settings" (like the transition delay) that could be exposed, but this is just intended as an example)
import java.awt.AlphaComposite;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class HoverButtonTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
try
{
createAndShowGUI();
}
catch (IOException e)
{
e.printStackTrace();
}
}
});
}
private static void createAndShowGUI() throws IOException
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage backgroundImage = loadImage("background.png");
BufferedImage foregroundImage = loadImage("foreground.png");
f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(
new ImageHoverButton(backgroundImage, foregroundImage));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static BufferedImage loadImage(String path) throws IOException
{
return convertToARGB(ImageIO.read(new File(path)));
}
public static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(image.getWidth(),
image.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
}
class ImageHoverButton extends JButton
{
private class MouseHoverListener extends MouseAdapter
{
#Override
public void mouseExited(MouseEvent me)
{
opacityAnimator.changeOpacity(0.0f, 250);
}
#Override
public void mouseEntered(MouseEvent me)
{
opacityAnimator.changeOpacity(1.0f, 1000);
}
#Override
public void mousePressed(MouseEvent me)
{
opacityAnimator.changeOpacity(0.5f, 50);
}
}
private class OpacityAnimator
{
private final int DELAY_MS = 10;
private final Timer timer;
private float targetOpacity;
private float currentOpacity;
private float opacityStep;
OpacityAnimator()
{
timer = new Timer(DELAY_MS, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if (currentOpacity > targetOpacity)
{
currentOpacity += opacityStep;
currentOpacity = Math.max(
currentOpacity, targetOpacity);
}
else if (currentOpacity < targetOpacity)
{
currentOpacity += opacityStep;
currentOpacity = Math.min(
currentOpacity, targetOpacity);
}
if (currentOpacity == targetOpacity)
{
timer.stop();
}
setOpacity(currentOpacity);
}
});
}
void changeOpacity(float targetOpacity, int durationMs)
{
timer.stop();
this.targetOpacity = targetOpacity;
float delta = targetOpacity - currentOpacity;
if (durationMs > 0)
{
opacityStep = (delta / durationMs) * DELAY_MS;
}
else
{
opacityStep = delta;
}
timer.start();
}
}
private final OpacityAnimator opacityAnimator;
private final BufferedImage backgroundImage;
private final BufferedImage foregroundImage;
private float opacity = 0.0f;
public ImageHoverButton(BufferedImage backgroundImage,
BufferedImage foregroundImage)
{
this.backgroundImage = backgroundImage;
this.foregroundImage = foregroundImage;
this.opacityAnimator = new OpacityAnimator();
addMouseListener(new MouseHoverListener());
setOpaque(false);
setBorderPainted(false);
setRolloverEnabled(false);
setCursor(new Cursor(Cursor.HAND_CURSOR));
}
#Override
public Dimension getPreferredSize()
{
if (super.isPreferredSizeSet())
{
return super.getPreferredSize();
}
int w = Math
.max(backgroundImage.getWidth(), foregroundImage.getWidth());
int h = Math.max(backgroundImage.getHeight(),
foregroundImage.getHeight());
return new Dimension(w, h);
}
public void setOpacity(float opacity)
{
this.opacity = opacity;
repaint();
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
g.drawImage(backgroundImage, 0, 0, null);
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
opacity));
g.drawImage(foregroundImage, 0, 0, null);
}
}
Don't access Swing components from other threads. Use a swing Timer instead.
See How to use swing timers
Let say I have an image. I put the image in a JPanel and add the JPanel inside a JFrame. The image moves from the bottom part of the frame to top of the frame while its size is also decreased using AffineTransform. The variable changes using thread.
So here's the following code:
public class SplashScreen extends JFrame{
Image img1;
int w=1,h=1;
int x=0,y=0;
Thread th = new Thread(new Runnable() {
#Override
public void run() {
while(true){
w-=0.05;
h-=0.05;
y-=2;
x+=1;
if(y==-100){
new MainMenu_BlueJay().setVisible(true);
dispose();
}
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
Logger.getLogger(SplashScreen.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
JPanel p = new JPanel();
public SplashScreen(){
setLayout(new BorderLayout());
p.setPreferredSize(new Dimension(900,600));
p.setBackground(Color.black);
p.setLayout(new GridLayout());
add(p);
setTitle("BlueJay");
setSize(900,600);
getContentPane().setBackground(Color.black);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
th.start();
requestFocus();
setFocusable(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
img1 = new ImageIcon("images/Intro/BJ Production 2013.png").getImage();
AffineTransform at = new AffineTransform();
at.scale(w,h);
g2d.setTransform(at);
g2d.drawImage(img1, x, y, p);
}
public static void main(String[] args) {
new SplashScreen();
}
However what I get from code above is only black screen. What's the matter? Anyway, If I don't use the AffineTransform function (just move it from bottom to top), the image is shown and moves BUT the frame is flickered (blinking) rapidly.
Any idea to solve this problem so I could move the image while decrease its size and also solve the flickered/rapid blinking frame?
You should not override the paint method of the JFrame. If you want to paint anything, you should paint this in a class that extends JPanel, where you override the paintComponent method.
You should NOT load the image in the painting method. This is horribly inefficient. You should load the image only ONCE, probably in a constructor.
You should not call Graphics2D#setTransform(). Have a look at the JavaDoc at http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#setTransform%28java.awt.geom.AffineTransform%29 , which explicitly states
WARNING: This method should never be used to apply a new coordinate transform on top of an existing transform
You should think about your w and h values. Should they be the size of the image that is painted, or used as scaling factors for the image? Setting them as the scaling factors of an AffineTransform will NOT have the effect of scaling an image to the desired size. At the moment, they are declared as int values, so something like w-=0.05 does not really make sense anyhow.
You should have a clear idea of how you are going to describe the animation that the image should perform.
One could possibly summarize this:
You should not write code and assume it is "correct" only because there are no compilation errors ;-)
However, the following snippet may be a first step towards your goal:
package stackoverflow;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SplashScreen extends JFrame
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new SplashScreen();
}
});
}
private PaintPanel paintPanel;
public SplashScreen()
{
setTitle("BlueJay");
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setBackground(Color.BLACK);
getContentPane().setLayout(new BorderLayout());
paintPanel = new PaintPanel();
getContentPane().add(paintPanel, BorderLayout.CENTER);
setSize(900,600);
setLocationRelativeTo(null);
setFocusable(true);
requestFocus();
setVisible(true);
startAnimation();
}
void startAnimation()
{
Thread thread = new Thread(new Runnable()
{
int x = 100;
int y = 100;
int w = 0;
int h = 0;
#Override
public void run()
{
try
{
Thread.sleep(500);
}
catch (InterruptedException ex)
{
Thread.currentThread().interrupt();
return;
}
while (true)
{
if (y == 200)
{
// new MainMenu_BlueJay().setVisible(true);
dispose();
}
x += 2;
y += 1;
w += 1;
h += 1;
paintPanel.setImageCoordinates(x, y, w, h);
repaint();
try
{
Thread.sleep(10);
}
catch (InterruptedException ex)
{
Thread.currentThread().interrupt();
return;
}
}
}
});
thread.start();
}
}
class PaintPanel extends JPanel
{
private final Image image;
private int imageX, imageY;
private int imageW, imageH;
PaintPanel()
{
image = new ImageIcon("Clipboard02.jpg").getImage();
imageX = 0;
imageY = 0;
imageW = 0;
imageH = 0;
}
void setImageCoordinates(int imageX, int imageY, int imageW, int imageH)
{
this.imageX = imageX;
this.imageY = imageY;
this.imageW = imageW;
this.imageH = imageH;
repaint();
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
float scalingX = (float) imageW / image.getWidth(null);
float scalingY = (float) imageH / image.getHeight(null);
g.scale(scalingX, scalingY);
int ix = (int)(imageX / scalingX);
int iy = (int)(imageY / scalingY);
g.drawImage(image, ix, iy, null);
}
}
Don't paint on top-level containers like JFrame. Instead use a JPanel and override its paintComponent method and call super.paintComponent
No need to call Thread.sleep(). Instead Use a javax.swing.Timer.
Run your program from the EDT
Don't create a new ImageIcon in the paint method. It will create new ImageIcon object every time repaint() is called. Instead, instantiate it in the constructor.
Here's a refactor of the code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SplashScreen extends JFrame {
Image img1;
int w = 900, h = 600;
int x = 0, y = 0;
public SplashScreen() {
setLayout(new BorderLayout());
add(new MyPanel());
setTitle("BlueJay");
setSize(900, 600);
getContentPane().setBackground(Color.black);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
requestFocus();
setFocusable(true);
}
private class MyPanel extends JPanel {
public MyPanel() {
img1 = new ImageIcon(SplashScreen.class.getResource("/resources/stackoverflow5.png")).getImage();
setBackground(Color.black);
setLayout(new GridLayout());
Timer timer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
w -= 5;
h -= 5;
y -= 2;
x += 1;
if (y == -250) {
new MainMenu_BlueJay().setVisible(true);
dispose();
}
repaint();
}
});
timer.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//AffineTransform at = new AffineTransform();
// at.scale(w, h);
// g2d.setTransform(at);
g2d.drawImage(img1, x, y, w, h, this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(900, 600);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new SplashScreen();
}
});
}
}
I'm not too familiar with Graphics2D so I commented out the AffirmTransformation stuff, but fixed your other problems.