How to edit a curve in java - java

I am making a Java program which is able to draw a curve on JPanel on mouse events.
Now I want to ask after drawing that curve, how can I edit that curve?
This is my Java program:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.QuadCurve2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import javax.swing.*;
public class MouseTestHovercraft extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int MAX_CLR = 5;
private static final Color CURRENT_LIST_COLOR = new Color(190, 190, 255);
private List<Color> colors = new ArrayList<Color>();
private boolean tracking = false;
private List<Point> currentList = null;
private BufferedImage bufferedImage = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
private Random random = new Random();
This contructor is used to change the color of the curve as soon as mouse is released.
public MouseTestHovercraft() {
for (int redIndex = 0; redIndex < MAX_CLR; redIndex++) {
int r = (redIndex * 256) / (MAX_CLR - 1);
r = (r == 256) ? 255 : r;
for (int greenIndex = 0; greenIndex < MAX_CLR; greenIndex++) {
int g = (greenIndex * 256) / (MAX_CLR - 1);
g = (g == 256) ? 255 : g;
for (int blueIndex = 0; blueIndex < MAX_CLR; blueIndex++) {
int b = (blueIndex * 256) / (MAX_CLR - 1);
b = (b == 256) ? 255 : b;
Color c = new Color(r, g, b);
colors.add(c);
}
}
}
add(new JToggleButton(new AbstractAction("TrackMouse") {
public void actionPerformed(ActionEvent ae) {
trackMouse(ae);
}
}));
add(new JButton(new AbstractAction("Clear Image") {
public void actionPerformed(ActionEvent e) {
bufferedImage = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
repaint();
}
}));
MyMouseAdapter myMA = new MyMouseAdapter();
addMouseListener(myMA);
addMouseMotionListener(myMA);
}
This is used to listen the event of tracking button.
private void trackMouse(ActionEvent ae) {
JToggleButton toggleBtn = (JToggleButton) ae.getSource();
tracking = toggleBtn.isSelected();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void msg(String message) {
System.out.println(message);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bufferedImage, 0, 0, null);
if (currentList != null) {
drawList(g, currentList, CURRENT_LIST_COLOR, 1f);
}
}
This will draw a curve on jpanel using quadcurve
private void drawList(Graphics g, List<Point> ptList, Color color,
float strokeWidth) {
if (ptList.size() > 1) {
Graphics2D g2 = (Graphics2D) g.create();
// Graphics2D g2 = (Graphics2D) g;
g2.setColor(color);
// g2.setStroke(new BasicStroke(strokeWidth));
QuadCurve2D selectedCurve = null;
for (int j = 0; j < ptList.size() - 1; j++) {
int x1 = ptList.get(j).x;
int y1 = ptList.get(j).y;
int x2 = ptList.get(j + 1).x;
int y2 = ptList.get(j + 1).y;
selectedCurve =new QuadCurve2D.Float(x1, y1, 5, 5, x2,y2);
g2.draw(selectedCurve);
}
g2.dispose();
}
}
On mouse press this code will first add the starting point into currentlist list and after that till mouse released all the points are added into currentlist.
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (tracking && e.getButton() == MouseEvent.BUTTON1) {
currentList = new ArrayList<Point>();
currentList.add(e.getPoint());
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (tracking && e.getButton() == MouseEvent.BUTTON1) {
currentList.add(e.getPoint());
Graphics2D g2 = bufferedImage.createGraphics();
Color color = colors.get(random.nextInt(colors.size()));
drawList(g2, currentList, color, 3f);
currentList = null;
repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (tracking && currentList != null) {
currentList.add(e.getPoint());
repaint();
}
}
}
private static void createAndShowGui() {
MouseTestHovercraft mainPanel = new MouseTestHovercraft();
JFrame frame = new JFrame("MouseMotion Eg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Related

Why is my JFrame blank in my breakout game?

So I'm new at java and need some help with my breakout game. My JFrame is just blank and i don't know how to fix it?
So I have a ball class, paddle class, canvas class and a brick class as well as a main class. In my canvas class I set all functions the ball, paddle and bricks has etc. In brick class I draw the bricks. And in my main I do the JFrame but it's blank
Main class :
public class Main {
public static void main(String[] args){
JFrame frame = new JFrame();
Canvas c = new Canvas();
frame.add(c);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I expect the JFrame to show the game instead of just blank window
package breakout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.KeyEvent;
import breakout.Bricks.Type;
public class Canvas extends JPanel implements ActionListener, MouseMotionListener, MouseListener, KeyListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int HEIGHT = 600;
public static final int WIDTH = 720;
private int horizontalCount;
private BufferedImage image;
private Graphics2D bufferedGraphics;
private Timer time;
private static final Font endFont = new Font(Font.SANS_SERIF, Font.BOLD, 20);
private static final Font scoreFont = new Font(Font.SANS_SERIF, Font.BOLD, 15);
private Paddle player;
private Ball ball;
ArrayList<ArrayList<Bricks>> bricks;
public Canvas() {
super();
setPreferredSize( new Dimension(WIDTH, HEIGHT));
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
bufferedGraphics = image.createGraphics();
time = new Timer (15, this);
player = new Paddle((WIDTH/2)-(Paddle.PADDLE_WIDTH/2));
ball = new Ball (((player.getX() + (Paddle.PADDLE_WIDTH / 2 )) - (Ball.DIAMETER / 2)), (Paddle.Y_POS - (Ball.DIAMETER + 10 )), -5, -5);
bricks = new ArrayList<ArrayList<Bricks>>();
horizontalCount = WIDTH / Bricks.BRICK_WIDTH;
for(int i = 0; i < 8; ++i) {
ArrayList<Bricks> temp = new ArrayList<Bricks>();
#SuppressWarnings("unused")
Type rowColor = null;
switch(i) {
case 0 :
case 2:
rowColor = Type.LOW;
break;
case 1 :
case 3 :
case 5 :
rowColor = Type.MEDIUM;
break;
case 4 :
case 6 :
rowColor = Type.HIGH;
break;
case 7 :
default :
rowColor = Type.ULTRA;
break;
}
for(int j = 0; j < horizontalCount; ++j) {
Bricks tempBrick = new Bricks();
temp.add(tempBrick);
}
bricks.add(temp);
addMouseMotionListener(this);
addMouseListener(this);
addKeyListener(this);
requestFocus();
}
}
public void actionPerformed(ActionEvent e) {
checkCollisions();
ball.Move();
for(int i = 0; i < bricks.size(); ++i) {
ArrayList<Bricks> al = bricks.get(i);
for(int j = 0; j < al.size(); ++j) {
Bricks b = al.get(j);
if(b.dead()) {
al.remove(b);
}
}
}
repaint();
}
private void checkCollisions() {
if(player.hitPaddle(ball)) {
ball.setDY(ball.getDY() * -1);
return;
}
if(ball.getX() >= (WIDTH - Ball.DIAMETER) || ball.getX() <= 0) {
ball.setDX(ball.getDX() * -1);
}
if(ball.getY() > (Paddle.Y_POS + Paddle.PADDLE_HEIGHT + 10)) {
resetBall();
}
if(ball.getY() <= 0) {
ball.setDY(ball.getDY() * -1);
}
int brickRowActive = 0;
for(ArrayList<Bricks> alb : bricks) {
if(alb.size() == horizontalCount) {
++brickRowActive;
}
}
for(int i = (brickRowActive==0) ? 0 : (brickRowActive - 1); i < bricks.size(); ++i) {
for(Bricks b : bricks.get(i)) {
if(b.hitBy(ball)) {
player.setScore(player.getScore() + b.getBrickType().getPoints());
b.decrementType();
}
}
}
}
private void resetBall() {
if(gameOver()) {
time.stop();
return;
}
ball.setX(WIDTH/2);
ball.setDY((HEIGHT/2) + 80);
player.setLives(player.getLives() -1);
player.setScore(player.getScore() <= 1);
}
private boolean gameOver() {
if(player.getLives() <= 1) {
return true;
}
return false;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
bufferedGraphics.clearRect(0, 0, WIDTH, HEIGHT);
player.drawPaddle(bufferedGraphics);
player.drawBall(bufferedGraphics);
for(ArrayList<Bricks> row : bricks) {
for(Bricks b : row) {
b.drawBrick(bufferedGraphics);
}
}
bufferedGraphics.setFont(scoreFont);
bufferedGraphics.drawString("Score: " + player.getScore(), 10, 25);
if(gameOver() && ball.getY() >= HEIGHT) {
bufferedGraphics.setColor(Color.black);
bufferedGraphics.setFont(endFont);
bufferedGraphics.drawString("Game Over Score: " + player.getScore(), (WIDTH /2) -85, (HEIGHT/2));
}
if(empty()) {
bufferedGraphics.setColor(Color.black);
bufferedGraphics.setFont(endFont);
bufferedGraphics.drawString("You won. Score: " + player.getScore(), (WIDTH /2) -85, (HEIGHT /2));
time.stop();
}
g.drawImage(image, 0, 0, this);
Toolkit.getDefaultToolkit().sync();
}
private boolean empty() {
for(ArrayList<Bricks> al : bricks) {
if(al.size() != 0) {
return false;
}
}
return true;
}
#Override
public void mouseMoved(MouseEvent e) {
player.setX(e.getX() - (Paddle.PADDLE_WIDTH / 2));
}
#Override
public void mouseClicked(MouseEvent e) {
if(time.isRunning()) {
return;
}
time.start();
}
#Override
public void mouseDragged(MouseEvent e) { }
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
#Override
public void mousePressed(MouseEvent arg0) {}
#Override
public void mouseReleased(MouseEvent arg0) {}
#Override
public void keyPressed(KeyEvent arg0) {}
#Override
public void keyReleased(KeyEvent arg0) {}
#Override
public void keyTyped(KeyEvent arg0) {}
}
Preparing an MCVE, as required in SO, not only it makes helping much easier.
In many case, while preparing one, you are likely to find the problem, so it is a good debugging tool.
To answer "why is my JFrame blank ?" you could create the minimal code example like the following (copy-paste the entire code into GameBoard.java and run):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameBoard extends JPanel {
static final int HEIGHT = 600, WIDTH = 720, BRICK_ROWS = 8;
private final int horizontalCount;
private static final Font scoreFont = new Font(Font.SANS_SERIF, Font.BOLD, 15);
private final Paddle player;
private final Ball ball;
ArrayList<ArrayList<Brick>> bricks;
public GameBoard() {
super();
setPreferredSize( new Dimension(WIDTH, HEIGHT));
player = new Paddle(WIDTH/2-Paddle.PADDLE_WIDTH/2);
ball = new Ball (player.getX() + Paddle.PADDLE_WIDTH / 2 - Ball.DIAMETER / 2,
Paddle.Y_POS - (Ball.DIAMETER + 10 ));
bricks = new ArrayList<>();
horizontalCount = WIDTH / Brick.BRICK_WIDTH;
for(int i = 0; i < BRICK_ROWS; ++i) {
ArrayList<Brick> temp = new ArrayList<>();
for(int j = 0; j < horizontalCount; ++j) {
Brick tempBrick = new Brick(j*Brick.BRICK_WIDTH , Brick.BRICK_YPOS + i*Brick.BRICK_HEIGHT);
temp.add(tempBrick);
}
bricks.add(temp);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)g;
g2D.clearRect(0, 0, WIDTH, HEIGHT);
player.drawPaddle(g2D);
ball.drawBall(g2D);
for(ArrayList<Brick> row : bricks) {
for(Brick b : row) {
b.drawBrick(g2D);
}
}
g2D.setFont(scoreFont);
g2D.drawString("Score: " + player.getScore(), 10, 25);
}
}
class Paddle{
public final static int PADDLE_WIDTH = 100, PADDLE_HEIGHT= 30, Y_POS = GameBoard.HEIGHT - 2* PADDLE_HEIGHT;
private int xPos, score;
Paddle(int xPos) {
this.xPos = xPos;
}
void setX(int xPos) {this.xPos = xPos;}
int getX() {return xPos;}
String getScore() {
return String.valueOf(score);
}
void drawPaddle(Graphics2D g2D) {
g2D.setColor(Color.GREEN);
g2D.fillRect(xPos, Y_POS, PADDLE_WIDTH, PADDLE_HEIGHT);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(400,250);
frame.add(new GameBoard());
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
}
}
class Brick{
final static int BRICK_WIDTH = 80, BRICK_HEIGHT = 15, BRICK_YPOS = 50;
int xPos, yPos;
Brick(int xPos, int yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
void drawBrick(Graphics2D g2D) {
g2D.setColor(Color.RED);
g2D.fillRect(xPos, yPos, BRICK_WIDTH, BRICK_HEIGHT);
g2D.setColor(Color.BLACK);
g2D.drawRect(xPos, yPos, BRICK_WIDTH, BRICK_HEIGHT);
}
}
class Ball{
final static int DIAMETER = 40;
int xPos, yPos;
Ball(int xPos, int yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
void drawBall(Graphics2D g2D) {
g2D.setColor(Color.BLUE);
g2D.fillOval(xPos, yPos, DIAMETER, DIAMETER);
}
}
This produces the following result, which I believe can serve as the basis of what you wanted to achieve:
Now start adding the missing functionality and see what breaks it.

Undo Action with ArrayList of BufferedImage

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();
}
});
}
}

CardLayout showing two panels, flashing

I'm trying to use CardLayout to show two JPanels, a main menu, and a controls screen. When I add two JPanels to my cards JPanel, it just shows two with flashing images. Here is my code:
package main;
public class MazeGame {
// Layout
public static JPanel cards = new JPanel();
// Window
public static JFrame window;
public static String windowLabel = "2D Maze Game - Before Alpha";
// Window Dimensions and Location
public static int WIDTH = 600;
public static int HEIGHT = 600;
public static Component center = null;
public static int exit = 3;
public static void main(String[] args) {
window = new JFrame(windowLabel);
window.setSize(new Dimension(WIDTH, HEIGHT));
window.setResizable(false);
window.setLocationRelativeTo(center);
window.setDefaultCloseOperation(exit);
cards.setLayout(new CardLayout());
cards.add(new MazeGamePanel(), "main");
cards.add(new MazeControlsPanel(), "controls");
window.add(cards);
CardLayout cl = (CardLayout) cards.getLayout();
cl.show(cards, "main");
window.setVisible(true);
}
}
MazeGamePanel:
public class MazeGamePanel extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
// Timer
public Timer timer;
// Font
public Font bitTrip;
public Thread thread;
public BufferedImage canvas;
public Graphics2D g;
public boolean running;
public int HEIGHT = MazeGame.HEIGHT;
public int WIDTH = MazeGame.WIDTH;
public int FPS = 30;
public int opacity = 255;
public int selectedOption = 0;
public String option1 = "Play";
public String option2 = "Controls";
public String option3 = "Quit";
public MazeGamePanel() {
this.setFocusable(true);
this.requestFocus();
addKeyListener(new MazeGameKeyListener());
try {
bitTrip = Font.createFont(Font.TRUETYPE_FONT, new File(
"res/font/BitTrip7.TTF"));
} catch (FontFormatException | IOException e) {
e.printStackTrace();
}
/**
ActionListener action = new ActionListener () {
public void actionPerformed (ActionEvent e) {
if(opacity != 0) {
opacity--;
} else {
timer.stop();
opacity = 0;
}
}
};
timer = new Timer(10, action);
timer.setInitialDelay(0);
timer.start();
*/
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public void run() {
running = true;
canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) canvas.getGraphics();
long startTime = 0;
long millis = 0;
long waitTime = 0;
long targetTime = 1000 / FPS;
while (running) {
startTime = System.nanoTime();
update();
render();
draw();
millis = (System.nanoTime() - startTime) / 1000000;
waitTime = targetTime - millis;
try {
Thread.sleep(waitTime);
} catch (Exception e) {
}
}
}
// TODO
public void render() {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
bitTrip = bitTrip.deriveFont(40F);
g.setFont(bitTrip);
if (selectedOption == 0) {
//Play
g.setColor(Color.BLACK);
g.drawString(option1, WIDTH / 2 - 200, HEIGHT / 2);
//Controls
g.setColor(Color.GRAY);
g.drawString(option2, WIDTH / 2 - 200, HEIGHT / 2 + 50);
//Quit
g.setColor(Color.GRAY);
g.drawString(option3, WIDTH / 2 - 200, HEIGHT / 2 + 100);
} else if (selectedOption == 1) {
//Play
g.setColor(Color.GRAY);
g.drawString(option1, WIDTH / 2 - 200, HEIGHT / 2);
//Controls
g.setColor(Color.BLACK);
g.drawString(option2, WIDTH / 2 - 200, HEIGHT / 2 + 50);
//Quit
g.setColor(Color.GRAY);
g.drawString(option3, WIDTH / 2 - 200, HEIGHT / 2 + 100);
} else if (selectedOption == 2) {
//Play
g.setColor(Color.GRAY);
g.drawString(option1, WIDTH / 2 - 200, HEIGHT / 2);
//Controls
g.setColor(Color.GRAY);
g.drawString(option2, WIDTH / 2 - 200, HEIGHT / 2 + 50);
//Quit
g.setColor(Color.BLACK);
g.drawString(option3, WIDTH / 2 - 200, HEIGHT / 2 + 100);
}
//g.setColor(new Color(0, 0, 0, opacity));
//g.fillRect(0, 0, WIDTH, HEIGHT);
}
public void update() {
}
public void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(canvas, 0, 0, null);
g2.dispose();
}
private class MazeGameKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
if (selectedOption == 1) {
selectedOption = 0;
} else if (selectedOption == 2) {
selectedOption = 1;
}
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
if (selectedOption == 0) {
selectedOption = 1;
} else if (selectedOption == 1) {
selectedOption = 2;
}
}
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
if(selectedOption == 1) {
MazeGame.window.removeAll();
MazeGame.window.add(new MazeControlsPanel());
MazeGame.window.validate();
}
}
}
}
}
MazeControlsPanel:
package screens;
public class MazeControlsPanel extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
// Font
public Font bitTrip;
public Thread thread;
public BufferedImage canvas;
public Graphics2D g;
public boolean running;
public int HEIGHT = MazeGame.HEIGHT;
public int WIDTH = MazeGame.WIDTH;
public int FPS = 30;
public int opacity = 255;
public int selectedOption = 0;
public MazeControlsPanel() {
this.setFocusable(true);
this.requestFocus();
addKeyListener(new MazeControlsKeyListener());
try {
bitTrip = Font.createFont(Font.TRUETYPE_FONT, new File(
"res/font/BitTrip7.TTF"));
} catch (FontFormatException | IOException e) {
e.printStackTrace();
}
/**
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (opacity != 0) {
opacity--;
} else {
timer.cancel();
opacity = 0;
}
}
}, 0, 4);
*/
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public void run() {
running = true;
canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) canvas.getGraphics();
long startTime = 0;
long millis = 0;
long waitTime = 0;
long targetTime = 1000 / FPS;
while (running) {
startTime = System.nanoTime();
update();
render();
draw();
millis = (System.nanoTime() - startTime) / 1000000;
waitTime = targetTime - millis;
try {
Thread.sleep(waitTime);
} catch (Exception e) {
}
}
}
// TODO
public void render() {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
bitTrip = bitTrip.deriveFont(40F);
g.setFont(bitTrip);
// Quit
g.setColor(Color.BLACK);
g.drawString("Main Menu", WIDTH / 2 - 200, HEIGHT / 2 + 100);
//g.setColor(new Color(0, 0, 0, opacity));
//g.fillRect(0, 0, WIDTH, HEIGHT);
}
public void update() {
}
public void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(canvas, 0, 0, null);
g2.dispose();
}
private class MazeControlsKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
}
}
}
}
Here's a problem:
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
Don't use a java.util.Timer in a Swing program as you will have threading problems. Instead use a Swing Timer.
Also, you're making Swing calls in background threads and using Graphics object obtained by calling getGraphics() on a component, two no-nos for Swing programs.
EDIT
Here is a program that I worked on that swaps components with a CardLayout, but fades one component out as it fades the other one in. What it does:
The program adds all the swapping components to the CardLayout using JPanel.
It also adds a single SwappingImgPanel, a JPanel created to draw two images, one of the component that is fading out, and one of the component that is fading in.
When you swap components, you create images of the two components, the one currently visible, and the one that will next be visible.
You send the images to the SwappingImgPanel instance
You call swap() on the SwappingImgPanel instance.
The SwappingImgPanel will then draw both images but uses a Swing Timer to change the Graphic object's composite value. This is what causes an image to be partially visible.
When the SwappingImgPanel's Timer is done, a done() method is called which sets the SwappingImgPanel's State to State.DONE.
The main GUI is listening to the SwappingImgPanel's state value, and when it achieves State.DONE, the main GUI shows the actual next component (and not an image of it).
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
#SuppressWarnings("serial")
public class DimmingPanelSwaps extends JPanel {
private static final int DELTA_TIME = 10;
private static final int ELAPSED_TIME = 3000;
private static final String SWAPPING_IMG_PANEL = "swapping img panel";
private CardLayout cardlayout = new CardLayout();
private JPanel cardHolderPanel = new JPanel(cardlayout);
private DefaultComboBoxModel<String> comboModel = new DefaultComboBoxModel<>();
private JComboBox<String> cardCombo = new JComboBox<>(comboModel);
private Map<String, JComponent> componentMap = new HashMap<String, JComponent>();
private String key = "";
private SwappingImgPanel swappingImgPanel = new SwappingImgPanel(DELTA_TIME, ELAPSED_TIME);
public DimmingPanelSwaps() {
registerComponent(createComponentOne(), "one");
registerComponent(createComponentTwo(), "two");
registerComponent(createComponentThree(), "three");
registerComponent(createComponentFour(), "four");
key = "one";
cardHolderPanel.add(swappingImgPanel, SWAPPING_IMG_PANEL);
JPanel southPanel = new JPanel();
southPanel.add(cardCombo);
setLayout(new BorderLayout());
add(cardHolderPanel, BorderLayout.CENTER);
add(southPanel, BorderLayout.SOUTH);
swappingImgPanel.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == State.DONE) {
cardlayout.show(cardHolderPanel, key);
cardCombo.setEnabled(true);
}
}
});
cardCombo.addActionListener(new CardComboListener());
}
private JPanel createComponentFour() {
int rows = 4;
int cols = 4;
int gap = 5;
int tfColumns = 8;
JPanel panel = new JPanel(new GridLayout(rows, cols, gap, gap));
for (int i = 0; i < rows * cols; i++) {
JTextField textField = new JTextField(tfColumns);
JPanel tfPanel = new JPanel();
tfPanel.add(textField);
panel.add(tfPanel);
}
return panel;
}
private JLabel createComponentThree() {
int biWidth = 200;
BufferedImage img = new BufferedImage(biWidth, biWidth, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(new GradientPaint(0, 0, Color.red, 20, 20, Color.blue, true));
g2.fillOval(0, 0, biWidth, biWidth);
g2.dispose();
Icon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
return label;
}
private JScrollPane createComponentTwo() {
JTextArea textArea = new JTextArea(15, 40);
JScrollPane scrollpane = new JScrollPane(textArea);
scrollpane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
return scrollpane;
}
private JPanel createComponentOne() {
JPanel innerPanel = new JPanel(new GridLayout(1, 0, 5, 0));
String[] btnTitles = {"One", "Two", "Three"};
for (String btnTitle : btnTitles) {
JButton btn = new JButton(btnTitle);
innerPanel.add(btn);
}
JPanel panel = new JPanel(new GridBagLayout());
panel.add(innerPanel);
return panel;
}
#SuppressWarnings("hiding")
private void registerComponent(JComponent jComp, String key) {
cardHolderPanel.add(jComp, key);
componentMap.put(key, jComp);
comboModel.addElement(key);
}
private class CardComboListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
final String oldKey = key;
key = (String) cardCombo.getSelectedItem();
cardCombo.setEnabled(false);
final JComponent firstComp = componentMap.get(oldKey);
final BufferedImage firstImg = extractComponentImg(firstComp);
final JComponent secondComp = componentMap.get(key);
final BufferedImage secondImg = extractComponentImg(secondComp);
cardlayout.show(cardHolderPanel, SWAPPING_IMG_PANEL);
swappingImgPanel.setFirstImg(firstImg);
swappingImgPanel.setSecondImg(secondImg);
swappingImgPanel.swap();
}
private BufferedImage extractComponentImg(final JComponent component) {
Dimension size = component.getSize();
BufferedImage img = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
component.paint(g2);
g2.dispose();
return img;
}
}
private static void createAndShowGui() {
DimmingPanelSwaps mainPanel = new DimmingPanelSwaps();
JFrame frame = new JFrame("Dimming Panel Swaps");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
/**
* A JPanel that draws two images
* When swap is called, the first image is shown
* Then a Timer dims the first image while it reveals
* the second image.
* When the elapsed time is complete, it sets its state to State.DONE.
* #author Pete
*
*/
#SuppressWarnings("serial")
class SwappingImgPanel extends JPanel {
public static final String STATE = "state";
private BufferedImage firstImg;
private BufferedImage secondImg;
private int deltaTime;
private int elapsedTime;
// state is a "bound" property, one that is listened to via PropertyChangeSupport
private State state = State.PENDING;
private float alpha1;
private float alpha2;
public SwappingImgPanel(final int deltaTime, final int elapsedTime) {
this.deltaTime = deltaTime;
this.elapsedTime = elapsedTime;
}
public void swap() {
setState(State.STARTED);
if (firstImg == null || secondImg == null) {
done();
}
alpha1 = 1.0f;
alpha2 = 0.0f;
new Timer(deltaTime, new ActionListener() {
private int counter = 0;
private int max = elapsedTime / deltaTime;
#Override
public void actionPerformed(ActionEvent e) {
if (counter >= elapsedTime / deltaTime) {
((Timer)e.getSource()).stop();
done();
return;
}
// set new alpha composite values
alpha1 = ((float)max - counter) / (float) max;
alpha2 = (float) counter / (float) max;
// make sure alphas are within bounds
alpha1 = Math.min(1f, alpha1);
alpha1 = Math.max(0f, alpha1);
alpha2 = Math.min(1f, alpha2);
alpha2 = Math.max(0f, alpha2);
repaint();
counter++;
}
}).start();
}
private void done() {
firstImg = null;
secondImg = null;
setState(State.DONE);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (firstImg == null || secondImg == null) {
return;
}
// create a new Graphics2D object with g.create()
// to avoid any possible side effects from changing the
// composite of the JVM's Graphics object
Graphics2D g2 = (Graphics2D) g.create();
// set the first alpha composite, and draw the image
g2.setComposite(((AlphaComposite)g2.getComposite()).derive(alpha1));
g2.drawImage(firstImg, 0, 0, this);
// set the second alpha composite, and draw the image
g2.setComposite(((AlphaComposite)g2.getComposite()).derive(alpha2));
g2.drawImage(secondImg, 0, 0, this);
g2.dispose(); // can get rid of this Graphics because we created it
}
public void setFirstImg(BufferedImage firstImg) {
this.firstImg = firstImg;
}
public void setSecondImg(BufferedImage secondImg) {
this.secondImg = secondImg;
}
public State getState() {
return state;
}
public void setState(State state) {
State oldValue = this.state;
State newValue = state;
this.state = state;
firePropertyChange(STATE, oldValue, newValue);
}
}
/**
* Modeled on SwingWorker.StateValue
* #author Pete
*
*/
enum State {
PENDING, STARTED, DONE
}

dynamically update JPanel background does't work

After reading image from JFilechooser, I am trying to read pixel of an image one by one and display it to JPanel after some delay in sequential manner. can't update the background of JPanel.
public class ImageMain extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 2916361361443483318L;
private JFileChooser fc = null;
private JMenuItem item1, item2;
private BufferedImage image = null;
private JPanel panel = null;
private int width = 0;
private int height = 0;
private BorderLayout card;
private Container contentPane;
//private int loopcount = 0;
//private int counter = 0;
public ImageMain() {
JFrame frame = new JFrame("Image Extraction Tool");
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = frame.getContentPane();
panel = new JPanel();
card = new BorderLayout();
panel.setLayout(card);
panel.setBackground(Color.white);
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
item1 = new JMenuItem("Browse an image");
item2 = new JMenuItem("Exit");
item1.addActionListener(this);
item2.addActionListener(this);
menu.add(item1);
menu.add(item2);
frame.setJMenuBar(menuBar);
contentPane.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
ImageMain img = new ImageMain();
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == item1) {
if (fc == null)
fc = new JFileChooser();
int retVal = fc.showOpenDialog(null);
if (retVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
try {
image = ImageIO.read(file);
height = image.getHeight();
width = image.getWidth();
// final int[][] pixelData = new int[height * width][3];
// int[] rgb;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
System.out.println(i + " " + j);
Color c = new Color(image.getRGB(j, i));
panel.setBackground(c);
panel.invalidate();
panel.validate();
panel.repaint();
}
}
} catch (IOException e1) {
System.out.println("IO::" + e1.getMessage());
} catch (Exception e1) {
System.out.println("Exception::" + e1.getMessage());
}
}
}
if (e.getSource() == item2) {
System.exit(0);
}
}}
Inside ActionPerformed, I got Color object by reading RGB values and then I am stuck at displaying them to JApplet. Suggestion are welcome if there is a better way to achieve this.
Thanks in advance.
The main problem is your performing a long running task within the context of the Event Dispatching Thread, which is responsible for, amongst other things, processing repaint requests.
#Override
public void actionPerformed(ActionEvent e) {
//...
// Nothing will be updated until after the
// actionPerformed method exists
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
System.out.println(i + " " + j);
Color c = new Color(image.getRGB(j, i));
panel.setBackground(c);
panel.invalidate();
panel.validate();
panel.repaint();
}
}
The other problem you have is that you are required to only modify the state of the UI from within the context of the EDT
Depending on your exact needs, you could use a SwingWorker, which would allow you to process the pixels in the background while updating the UI from within the context of the EDT, however, because SwingWorker consolidates it's updates, you could miss color changes.
A better solution might be to use a java.swing.Timer which would allow you to trigger updates at a specified period, which are triggered within the context of the EDT.
See Concurrency in Swing for more details...
Updated with example
In order to draw pixels, you need something to draw them on. Now, you could simply add each pixel you want to paint to an array and loop that array each time you need to repaint the component, but that's kind of expensive...
Instead, it would be simpler to have a backing buffer of some kind, onto which you paint the pixels and then paint that buffer to the component, which should be faster.
Basically, the allows you to supply the height and width of the expected image and then supply each pixel as you need..
public class ImagePane extends JPanel {
private BufferedImage img;
public ImagePane() {
}
public void reset(int width, int height) {
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
revalidate();
}
public void reset() {
img = null;
revalidate();
}
public void setPixelAt(int x, int y, int pixel) {
img.setRGB(x, y, pixel);
}
#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);
Graphics2D g2d = (Graphics2D) g.create();
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
}
g2d.dispose();
}
}
Take a look at Performing Custom Painting for more details...
Then you need some way to process the original image and update the image panel...Now, based on the updated requirements, I would use a SwingWorker, the reason for this, is that the SwingWorker can cache what is passed back to the EDT, this allows the background thread to continue processing and caching the output until the EDT (and system) is ready to process it...
public class PixelExposerWorker extends SwingWorker<Void, Pixel> {
private final BufferedImage img;
private final ImagePane imagePane;
private final List<Point> points;
public PixelExposerWorker(BufferedImage img, ImagePane imagePane) {
this.img = img;
this.imagePane = imagePane;
points = new ArrayList<>(img.getWidth() * img.getHeight());
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
points.add(new Point(x, y));
}
}
}
#Override
protected void process(List<Pixel> chunks) {
System.out.println("Publish " + chunks.size());
for (Pixel pixel : chunks) {
imagePane.setPixelAt(pixel.getX(), pixel.getY(), pixel.getColor());
}
imagePane.repaint();
}
#Override
protected Void doInBackground() throws Exception {
int pixelCount = (int) (points.size() * 0.005);
while (!points.isEmpty()) {
for (int count = 0; count < pixelCount && !points.isEmpty(); count++) {
int index = (int) (Math.random() * (points.size() - 1));
Point p = points.remove(index);
Pixel pixel = new Pixel(p.x, p.y, img.getRGB(p.x, p.y));
publish(pixel);
}
Thread.yield();
}
return null;
}
}
Basically, this SwingWorker builds a List of "pixel points", it uses the list to randomly remove points from the list, generate a virtual Pixel and publish back to the EDT for processing. The worker will process around 0.5% of the pixels at a time, meaning that the work is always trying to send a "bunch" of pixels back to the EDT, rather the one at a time.
Finally, it will yield to allow other threads to run (and the hopefully for the EDT to update it self)
An image of 650x975 takes roughly 1m and 10s to fully renderer
And the full code...
import core.util.StopWatch;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.Timer;
public class PixelShower implements ActionListener {
private static final long serialVersionUID = 2916361361443483318L;
private JFileChooser fc = null;
private JMenuItem item1, item2;
private BufferedImage image = null;
private ImagePane panel = null;
private int width = 0;
private int height = 0;
private BorderLayout card;
private Container contentPane;
public PixelShower() {
JFrame frame = new JFrame("Image Extraction Tool");
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = frame.getContentPane();
panel = new ImagePane();
card = new BorderLayout();
panel.setLayout(card);
panel.setBackground(Color.white);
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
menuBar.add(menu);
item1 = new JMenuItem("Browse an image");
item2 = new JMenuItem("Exit");
item1.addActionListener(this);
item2.addActionListener(this);
menu.add(item1);
menu.add(item2);
frame.setJMenuBar(menuBar);
contentPane.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
PixelShower img = new PixelShower();
}
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == item1) {
if (fc == null) {
fc = new JFileChooser();
}
int retVal = fc.showOpenDialog(null);
if (retVal == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
try {
image = ImageIO.read(file);
panel.reset(image.getWidth(), image.getHeight());
PixelExposerWorker worker = new PixelExposerWorker(image, panel);
worker.execute();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
if (e.getSource() == item2) {
System.exit(0);
}
}
public class ImagePane extends JPanel {
private BufferedImage img;
public ImagePane() {
}
public void reset(int width, int height) {
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
revalidate();
}
public void reset() {
img = null;
revalidate();
}
public void setPixelAt(int x, int y, int pixel) {
img.setRGB(x, y, pixel);
}
#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);
Graphics2D g2d = (Graphics2D) g.create();
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
}
g2d.dispose();
}
}
public class Pixel {
private int x;
private int y;
private int color;
public Pixel(int x, int y, int color) {
this.x = x;
this.y = y;
this.color = color;
}
public int getColor() {
return color;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
public class PixelExposerWorker extends SwingWorker<Void, Pixel> {
private final BufferedImage img;
private final ImagePane imagePane;
private final List<Point> points;
public PixelExposerWorker(BufferedImage img, ImagePane imagePane) {
this.img = img;
this.imagePane = imagePane;
points = new ArrayList<>(img.getWidth() * img.getHeight());
for (int x = 0; x < img.getWidth(); x++) {
for (int y = 0; y < img.getHeight(); y++) {
points.add(new Point(x, y));
}
}
}
#Override
protected void process(List<Pixel> chunks) {
System.out.println("Publish " + chunks.size());
for (Pixel pixel : chunks) {
imagePane.setPixelAt(pixel.getX(), pixel.getY(), pixel.getColor());
}
imagePane.repaint();
}
#Override
protected Void doInBackground() throws Exception {
StopWatch sw = StopWatch.newInstance().start();
int pixelCount = (int) (points.size() * 0.005);
System.out.println("pixelCount = " + pixelCount + "; " + points.size());
while (!points.isEmpty()) {
StopWatch sw1 = StopWatch.newInstance().start();
for (int count = 0; count < pixelCount && !points.isEmpty(); count++) {
int index = (int) (Math.random() * (points.size() - 1));
Point p = points.remove(index);
Pixel pixel = new Pixel(p.x, p.y, img.getRGB(p.x, p.y));
publish(pixel);
}
Thread.yield();
}
System.out.println("Took " + sw.stop());
return null;
}
}
}

Drawing a line using a Mouse Motion Listener

I'm new at using actionListener and mouselistner. I want to track the Mouse movements and connect the dots as I go. So it will be one continuous line. I am using the MouseMotionListener every time I move the mouse across the screen and get a new set of points. I am not using mousePressed or mouseReleased.
Everytime I move the mouse, I can get every point of where my mouse's position is on my JPanel to show up on my results window, but in order to draw the line between two points, I'm not sure how to decipher between each different set of points so I can have a beginning and ending set of points to use for drawing a line? I checked through here and the API and I'm stuck.
I was asked to put more code and so I gave you my code.
I am basically creating a Jpane that tracks mouse movement when the Track Mouse button or Draw Track Radio button is pressed
These results will print out as (x,y) on the output screen
FYI: You can also draw circles once the Draw circles RadioButton is checked
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class MouseTest {
private JFrame frame;
private boolean tracking;
private boolean drawing;
private boolean connectdots;
private int xstart;
private int ystart;
private int xend;
private int y;
private int x;
private int yend;
private int borderWidth = 5;
String drawCircles = "Draw Circles";
String drawTrack = "Draw Track";
public static void main (String [] arg) {
MouseTest first = new MouseTest();
}//main
$
public MouseTest() {
tracking = false;
frame = new JFrame();
frame.setBounds(250,98,600,480);
frame.setTitle("Window number three");
Container cp = frame.getContentPane();
JButton track = new JButton("Track Mouse");
track.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
trackMouse();
}
});
JPanel top = new JPanel();
top.add(track);
cp.add(top,BorderLayout.NORTH);
MyPanel pane = new MyPanel();
cp.add(pane,BorderLayout.CENTER);
pane.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
xstart = e.getX();
ystart = e.getY();
}
public void mouseReleased(MouseEvent e) {
xend = e.getX();
yend = e.getY();
if (xend < xstart) { int tmp = xstart; xstart = xend; xend = tmp; }
if (yend < ystart) { int tmp = ystart; ystart = yend; yend = tmp; }
frame.repaint();
}
});
pane.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
if (tracking) {
x = e.getX();
y = e.getY();
msg("(" + x + ", " + y + ")");
}
}
});
JRadioButton circleButton = new JRadioButton(drawCircles);
circleButton.setMnemonic(KeyEvent.VK_B);
circleButton.setActionCommand(drawCircles);
circleButton.setSelected(false);
JRadioButton trackButton = new JRadioButton(drawTrack);
trackButton.setMnemonic(KeyEvent.VK_C);
ButtonGroup group = new ButtonGroup();
group.add(circleButton);
group.add(trackButton);
JPanel radioPanel = new JPanel(new GridLayout(2,0));
radioPanel.add(circleButton);
radioPanel.add(trackButton);
cp.add(radioPanel,BorderLayout.EAST);
drawing = false;
connectdots = false;
circleButton.addActionListener(new ActionListener() { //Set drawing to true when the button is clicked
public void actionPerformed(ActionEvent ae) {
tracking = !tracking;
drawCircles();
}
});
trackButton.addActionListener(new ActionListener() { //Set drawing to true when the button is clicked
public void actionPerformed(ActionEvent ae) {
drawing = false;
tracking = true;
connectDots();
}
});
frame.setVisible(true);
}//constructor
$
public void trackMouse() {
tracking = !tracking;
}//trackMouse
public void msg(String s) { //new method to simplify the system.out.print method
System.out.println(s);
}
public void drawCircles() {
drawing = true;
}//Allow Drawing of Circles
public void connectDots() {
connectdots = !connectdots;
}//Trying to use for connecting the mouse motion listener points when tracking
$
public class MyPanel extends JPanel {
ArrayList<Circle> circles = new ArrayList<Circle>();
public void paintComponent(Graphics g) {
int width = this.getWidth();
int height = this.getHeight();
msg("H = " + height + ", w = " + width);
g.setColor(Color.BLACK);
Circle c = new Circle(xstart, ystart);
circles.add(c);
if (drawing){
for(int k=0; k<circles.size(); k++){
circles.get(k).draw(g);
}
} // draw the circle
if (connectdots && tracking) { //trying to use for drawing the lines
g.drawLine(x,y,x,y);
}
for (int delta = 0; delta < borderWidth; delta++) {
g.drawRect(delta,delta,width-(2*delta),height-(2*delta));
}
if (xstart != xend || ystart != yend) {
int red = (int)(256*Math.random());
int green = (int)(256*Math.random());
int blue = (int)(256*Math.random());
g.setColor(new Color(red, green, blue));
msg("Colors are: " + red + " - " + green + " - " + blue );
msg("Drawing from: (" + xstart + ", " + ystart + ") to (" + xend + ", " + yend + ")");
msg("Width is " + (xend-xstart) + " - Height is " + (yend-ystart));
g.fillRect(xstart,ystart,xend-xstart,yend-ystart);
}
}
}
}
$
public class Circle {
// instance variables:
int radius; //random radius
int x, y; // coords of the center point
private Graphics g;
public Circle(int xIn, int yIn) {
radius = (int)(127*Math.random());
x = xIn;
y = yIn;
}
public void draw(Graphics g){
g.drawOval(x-radius, y-radius, radius, radius);
g.fillOval(x-radius, y-radius, radius, radius);
int red = (int)(256*Math.random());
int green = (int)(256*Math.random());
int blue = (int)(256*Math.random());
g.setColor(new Color(red, green, blue));
}
public int getX(int xstart) {
// TODO Auto-generated method stub
return x;
}
public int getY(int ystart) {
// TODO Auto-generated method stub
return y;
}
}
You just have to save x and y in some attribute for your class (like lastX and lastY.) When you get the event the second time, your first point coordinates are saved in your attributes and you can then draw your line. This new point has to be saved too to serve as your new lastX and lastY.
Even better: since you'll probably need to redraw your lines each frame (if you want a set of lines and not just a single line to be drawn each frame), use Point to save your coordinates and some kind of list like ArrayList. Save the full set of tracked points in an ArrayList<Point> and then draw each frame iterating over this list.
An example of an sscce:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class Foo3 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private boolean tracking = false;
private int x, y;
public Foo3() {
add(new JToggleButton(new AbstractAction("TrackMouse") {
public void actionPerformed(ActionEvent ae) {
trackMouse(ae);
}
}));
MyMouseAdapter myMA = new MyMouseAdapter();
addMouseMotionListener(myMA);
}
private void trackMouse(ActionEvent ae) {
JToggleButton toggleBtn = (JToggleButton) ae.getSource();
tracking = toggleBtn.isSelected();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void msg(String message) {
System.out.println(message);
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
if (tracking) {
x = e.getX();
y = e.getY();
msg("(" + x + ", " + y + ")");
}
}
}
private static void createAndShowGui() {
Foo3 mainPanel = new Foo3();
JFrame frame = new JFrame("MouseMotion Eg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Edit: Example 2
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class MouseTestHovercraft extends JPanel {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final int MAX_CLR = 5;
private static final Color CURRENT_LIST_COLOR = new Color(190, 190, 255);
private List<Color> colors = new ArrayList<Color>();
private boolean tracking = false;
private List<Point> currentList = null;
private BufferedImage bufferedImage = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
private Random random = new Random();
public MouseTestHovercraft() {
for (int redIndex = 0; redIndex < MAX_CLR; redIndex++) {
int r = (redIndex * 256) / (MAX_CLR - 1);
r = (r == 256) ? 255 : r;
for (int greenIndex = 0; greenIndex < MAX_CLR; greenIndex++) {
int g = (greenIndex * 256) / (MAX_CLR - 1);
g = (g == 256) ? 255 : g;
for (int blueIndex = 0; blueIndex < MAX_CLR; blueIndex++) {
int b = (blueIndex * 256) / (MAX_CLR - 1);
b = (b == 256) ? 255 : b;
Color c = new Color(r, g, b);
colors.add(c);
}
}
}
add(new JToggleButton(new AbstractAction("TrackMouse") {
public void actionPerformed(ActionEvent ae) {
trackMouse(ae);
}
}));
add(new JButton(new AbstractAction("Clear Image") {
public void actionPerformed(ActionEvent e) {
bufferedImage = new BufferedImage(getWidth(), getHeight(),
BufferedImage.TYPE_INT_ARGB);
repaint();
}
}));
MyMouseAdapter myMA = new MyMouseAdapter();
addMouseListener(myMA);
addMouseMotionListener(myMA);
}
private void trackMouse(ActionEvent ae) {
JToggleButton toggleBtn = (JToggleButton) ae.getSource();
tracking = toggleBtn.isSelected();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void msg(String message) {
System.out.println(message);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bufferedImage, 0, 0, null);
if (currentList != null) {
drawList(g, currentList, CURRENT_LIST_COLOR, 1f);
}
}
private void drawList(Graphics g, List<Point> ptList, Color color,
float strokeWidth) {
if (ptList.size() > 1) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(color);
g2.setStroke(new BasicStroke(strokeWidth));
for (int j = 0; j < ptList.size() - 1; j++) {
int x1 = ptList.get(j).x;
int y1 = ptList.get(j).y;
int x2 = ptList.get(j + 1).x;
int y2 = ptList.get(j + 1).y;
g2.drawLine(x1, y1, x2, y2);
}
g2.dispose();
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (tracking && e.getButton() == MouseEvent.BUTTON1) {
currentList = new ArrayList<Point>();
currentList.add(e.getPoint());
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (tracking && e.getButton() == MouseEvent.BUTTON1) {
currentList.add(e.getPoint());
Graphics2D g2 = bufferedImage.createGraphics();
Color color = colors.get(random.nextInt(colors.size()));
drawList(g2, currentList, color, 3f);
currentList = null;
repaint();
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (tracking && currentList != null) {
currentList.add(e.getPoint());
repaint();
}
}
}
private static void createAndShowGui() {
MouseTestHovercraft mainPanel = new MouseTestHovercraft();
JFrame frame = new JFrame("MouseMotion Eg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories