I am trying to create the GUI for a connect four game and I want the chips to animate as they drop.I want the chip to look like it is passing behind the parts of the board that aren't cut out. The issue I am running into is that if I print out the board (the piece with the holes in it) first the falling chip will be on top of it and if I print out the chip first the board will cover it (since it is just a rectangle). Is there any way to do this without creating some complex polygons for the background image?
Here is the code I have so far:
public class ConnectFourGrid extends JPanel
{
ConnectFour game;
boolean animate = false;
int animateRow = 0;
int animateCol = 0;
int dropYPos = -30;
Timer dropTimer = new Timer(2, new animateListener());
ConnectFourGrid()
{
this.setPreferredSize(new Dimension(ConnectFour.NUM_OF_COLUMNS * 100, ConnectFour.NUM_OF_ROWS * 100));
}
class animateListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent arg0)
{
dropYPos += 5;
if (dropYPos == (animateRow * 100) + 10)
{
dropTimer.stop();
dropYPos = -30;
animate = false;
}
repaint();
}
}
public void setGame(ConnectFour game) { this.game = game; }
public ConnectFour getGame() { return game; }
public void animate(int row, int col)
{
animate = true;
animateRow = row;
animateCol = col;
dropTimer.start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for (int row = 0; row < ConnectFour.NUM_OF_ROWS; row++)
{
for (int col = 0; col < ConnectFour.NUM_OF_COLUMNS; col++)
{
g.setColor(Color.BLUE);
g.fillRect(col * 100, row * 100, 100, 100);
if (game.getCurrentGameState()[row][col] == 0)
g.setColor(Color.WHITE);
else if (game.getCurrentGameState()[row][col] == 1)
g.setColor(Color.RED);
else
g.setColor(Color.YELLOW);
g.fillOval( col * 100 + 5, row * 100 + 10, 80, 80);
}
}
if (animate)
{
if (game.getCurrentPlayer() == 1)
g.setColor(Color.YELLOW);
else
g.setColor(Color.RED);
g.fillOval(animateCol * 100 + 5, dropYPos, 80, 80);
}
}
}
Okay, there are at least two ways I can think off doing this, one is to create a BufferedImage and use AlphaComposite to "poke" holes in it, the other is to use an Area and subtract holes from it...
The BufferedImage approach can be more efficient, as you only need to create the image when you need it, but can also be a little complicated.
Using an Area
This example demonstrates the use of an Area which has holes "pocked" out of it...
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setBackground(Color.RED);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth() - 20;
int height = getHeight() - 20;
Area area = new Area(new Rectangle(10, 10, width, height));
int cellWidth = width / 4;
int cellHeight = height / 4;
for (int row = 0; row < 4; row++) {
int yPos = 10 + (row * cellHeight);
for (int col = 0; col < 4; col++) {
int xPos = 10 + (col * cellWidth);
area.subtract(new Area(new Ellipse2D.Double(xPos + 2, yPos + 2, cellWidth - 4, cellHeight - 4)));
}
}
g2d.setColor(Color.BLUE);
g2d.fill(area);
g2d.dispose();
}
}
}
Using a BufferedImage and AlphaComposite
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage buffer;
public TestPane() {
setBackground(Color.RED);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
public void invalidate() {
buffer = null;
super.invalidate();
}
protected BufferedImage getBoard() {
if (buffer == null) {
int width = getWidth() - 20;
int height = getHeight() - 20;
buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
g2d.setColor(Color.BLUE);
g2d.fillRect(0, 0, width, height);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN));
g2d.setColor(new Color(0, 0, 0, 0));
int cellWidth = width / 4;
int cellHeight = height / 4;
for (int row = 0; row < 4; row++) {
int yPos = (row * cellHeight);
for (int col = 0; col < 4; col++) {
int xPos = (col * cellWidth);
g2d.fill(new Ellipse2D.Double(xPos + 2, yPos + 2, cellWidth - 4, cellHeight - 4));
}
}
g2d.dispose();
}
return buffer;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
BufferedImage buffer = getBoard();
int x = (getWidth() - buffer.getWidth()) / 2;
int y = (getHeight() - buffer.getHeight()) / 2;
g2d.drawImage(buffer, x, y, this);
g2d.dispose();
}
}
}
Here is some code I found on the Web somewhere years ago:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class CompositeBoardTest extends JFrame {
private static int size = 400;
private static int offset = 10;
private static int ovalSize = size/4 - offset*2;
private static int pos = offset/2;
private static int incr = size/4;
public static void main( String[] args ) throws Exception {
SwingUtilities.invokeLater( new Runnable() {
public void run() { new CompositeBoardTest(); }
} );
}
public CompositeBoardTest() {
super( "CompositeBoardTest" );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Board board = new Board();
getContentPane().add( board );
setSize( size, size+34 );
setVisible( true );
}
static class Board extends JPanel implements ActionListener {
private int[][] pieces = new int[4][4];
private Piece addingPiece = null;
private Timer pieceDropped = null;
public Board() {
setPreferredSize( new Dimension( size, size ) );
setBounds( 0, 0, size, size );
// pieceDropped = new Timer( 10, this );
pieceDropped = new Timer( 20, this );
addMouseListener( new MouseAdapter() {
public void mousePressed( MouseEvent e ) {
int column = ( e.getPoint().x-pos )/incr;
addPiece( column );
}
});
}
protected void paintComponent( Graphics g ) {
super.paintComponent( g );
Graphics2D g2d = (Graphics2D) g;
Composite comp = g2d.getComposite();
Dimension d = getSize();
int w = d.width;
int h = d.height;
BufferedImage buffImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D gbi = buffImg.createGraphics();
// Clear area
g2d.setColor( Color.WHITE );
g2d.fillRect( 0, 0, w, h );
// Draw screen
// gbi.setColor( Color.YELLOW );
gbi.setColor( Color.BLUE );
gbi.fillRect( 0, 0, w, h );
// Draw pieces or holes
gbi.setColor( Color.RED );
for ( int row = 0 ; row < 4 ; row++ ) {
for ( int column = 0 ; column < 4 ; column++ ) {
if ( pieces[row][column] == 1 ) {
// gbi.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 1.0f ) );
gbi.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.5f ) );
} else {
gbi.setComposite( AlphaComposite.getInstance( AlphaComposite.CLEAR, 1.0f ) );
}
gbi.fillOval( incr*column+pos, incr*row+pos, ovalSize, ovalSize );
}
}
// Draw adding piece if we have it
if ( addingPiece != null ) {
gbi.setComposite( AlphaComposite.getInstance( AlphaComposite.DST_OVER, 1.0f ) );
gbi.fillOval( addingPiece.x, addingPiece.y, ovalSize, ovalSize );
}
// Draws the buffered image.
g2d.drawImage(buffImg, null, 0, 0);
g2d.setComposite( comp );
}
public void addPiece( int column ) {
if ( addingPiece == null ) {
if ( pieces[0][column] == 0 ) {
addingPiece = new Piece();
addingPiece.row = 0;
addingPiece.column = column;
addingPiece.x = incr*column+pos;
addingPiece.y = 0;
pieceDropped.start();
} else {
getToolkit().beep();
}
}
}
public void actionPerformed( ActionEvent e ) {
if ( addingPiece != null ) {
addingPiece.y += 5;
int row = ( addingPiece.y - pos )/incr + 1;
if ( row > 3 || pieces[row][addingPiece.column] == 1 ) {
pieces[row-1][addingPiece.column] = 1;
addingPiece = null;
pieceDropped.stop();
}
}
repaint();
}
}
private static class Piece {
public int row, column, x, y;
}
}
Click on a column to start the animation.
Related
I started a Chess Project reusing some older code to paint a map everything basically has been copy pasted. The problem is the squares dont show up? I tried fixing it for a while now and got to no solution. Here are probably the three most important methods and a zip with the whole project. Some of it is in German.
https://drive.google.com/file/d/1nnZHLB0Ycy04eMyYbEmduMwbGhVLZ2VB/view?usp=sharing
public SchachFrame() {
super();
contentPane = new JPanel();
setContentPane(contentPane);
setBounds(0, 0, window.width, window.height);
contentPane.setBackground(Color.darkGray);
contentPane.setVisible(true);
ge = new GameEnvironment(this);
ge.setBounds(window.width/2 - 500, window.height/2 - 500, 1000, 1000);
ge.setVisible(true);
contentPane.add(ge);
Thread gameEnvironment = new Thread(ge);
gameEnvironment.start();
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void createMap(int width, int length, GameEnvironment ge) {
map = new Spielfeld[length][width];
Spielfeld.width = 1000/width;
Spielfeld.height = 1000/length;
for(int i = 0; i < length; i++) {
for(int j = 0; j < width; j++) {
this.map[i][j] = new Spielfeld(j, i, null);
this.map[i][j].setBounds(ge.getX() + j * Spielfeld.width, ge.getY() + i * Spielfeld.height, Spielfeld.width, Spielfeld.height);
this.map[i][j].setVisible(true);
ge.add(this.map[i][j]);
}
}
}
public void paintComponent(Graphics g) {
if((this.px + this.py) % 2 == 0) {
g.setColor(Color.blue);
} else {
g.setColor(Color.cyan);
}
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
repaint();
}
Do not call repaint() in paintComponent. Otherwise you will never exit the EDT and lock up your code. And the first statement in paintComponent(Graphics g) should be super.paintComponent(g);
Updated to include an example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawSquareComponent extends JPanel {
static int WIDTH = 600;
static int HEIGHT = 600;
JFrame frame = new JFrame();
public static void main(String[] args) {
new DrawSquareComponent().start();
}
public void start() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
setBackground(Color.white);
MyComponent my =new MyComponent();
add(my); // add my component to panel
Random r = new Random();
for (int i = 0; i < 20; i++) {
int size = r.nextInt(50)+50;
int x = r.nextInt(WIDTH-size)+1;
int y = r.nextInt(HEIGHT-size)+1;
my.setBounds(x,y,size,size);
frame.repaint();
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
}
}
}
public Dimension getPreferredSize() {
return new Dimension(WIDTH, HEIGHT);
}
}
class MyComponent extends JPanel {
#Override
public void paintComponent(Graphics g) {
Graphics gg = g.create();
super.paintComponent(gg);
// location relative to parent's.
// used to check location in parent's coordinate space.
Point p = getLocation();
if ((p.x + p.y) % 2 == 0) {
gg.setColor(Color.blue);
} else {
gg.setColor(Color.cyan);
}
// paint this component so location is always 0,0.
// all you're doing is painting this squares background
gg.fillRect(0,0, this.getWidth(), this.getHeight());
gg.dispose();
}
}
Right now I have code to be able to randomize colored squares over a 25x25 board. What I'm trying to do is be able to make those colored squares turn white once pressed on and once it turns white, you can't reverse it. I was thinking about using Listeners but I'm not sure how to start.
Here is what I have to create the randomized squares.
import java.awt.*;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
public class ColoredBoxes {
//Selected Colors
private Color[] availableColors = new Color[] {Color.YELLOW, Color.RED, Color.BLUE, Color.GREEN};
public static void main(String[] args) {
new ColoredBoxes();
}
public ColoredBoxes() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Collapse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
//Size of the board
protected static final int ROWS = 25;
protected static final int COLS = 25;
protected static final int BOX_SIZE = 25;
private List<Color> colors;
//RandomColors across the given board size.
public TestPane() {
int length = ROWS * COLS;
colors = new ArrayList<Color>();
for (int index = 0; index < length; index++) {
int randomColor = (int) (Math.random() * availableColors.length);
colors.add(availableColors[randomColor]);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(COLS * BOX_SIZE, ROWS * BOX_SIZE);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int xOffset = (getWidth() - (COLS * BOX_SIZE)) / 2;
int yOffset = (getHeight() - (ROWS * BOX_SIZE)) / 2;
System.out.println("...");
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
int index = (row * COLS) + col;
g2d.setColor(colors.get(index));
g2d.fillRect(xOffset + (col * BOX_SIZE), yOffset + (row * BOX_SIZE), BOX_SIZE, BOX_SIZE);
}
}
g2d.dispose();
}
}
}
Any help is much appreciated.
To change color on click, you just need a MouseListener, in the mouseClicked() method you must convert the click coordinates to row and column of the color grid, change that color and then ask the component to repaint.
Here the implementation, I just replaced your 1-dimensional color list with a 2-dimension color array, since it simplify the representation and the conversion from x,y to row,col.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ColoredBoxes {
//Selected Colors
private Color[] availableColors = new Color[] {Color.YELLOW, Color.RED, Color.BLUE, Color.GREEN};
//This is the color that will be set when a cell is clicked
private static final Color CLICKED_COLOR = Color.white;
public static void main(String[] args) {
new ColoredBoxes();
}
public ColoredBoxes() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Collapse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
//Size of the board
protected static final int ROWS = 25;
protected static final int COLS = 25;
protected static final int BOX_SIZE = 25;
//Since you have a ROWSxCOLS color grid better use a 2-dimension array
private Color[][] cells;
//RandomColors across the given board size.
public TestPane() {
cells=new Color[ROWS][COLS];
for (int i=0;i<cells.length;i++) {
for (int j=0;j<cells[i].length;j++) {
int randomColor = (int) (Math.random() * availableColors.length);
cells[i][j]=availableColors[randomColor];
}
}
//Here the mouse listener, we only need to manage click events
//so I use a MouseAdapter to not implement the complete MouseListener interface
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
onClick(e);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(COLS * BOX_SIZE, ROWS * BOX_SIZE);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int xOffset = (getWidth() - (COLS * BOX_SIZE)) / 2;
int yOffset = (getHeight() - (ROWS * BOX_SIZE)) / 2;
System.out.println("...");
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
g2d.setColor(cells[row][col]);
g2d.fillRect(xOffset + (col * BOX_SIZE), yOffset + (row * BOX_SIZE), BOX_SIZE, BOX_SIZE);
}
}
g2d.dispose();
}
//Finally the click handler
protected void onClick(MouseEvent e) {
//Convert mouse x,y (that are relative to the panel) to row and col
int xOffset = (getWidth() - (COLS * BOX_SIZE)) / 2;
int yOffset = (getHeight() - (ROWS * BOX_SIZE)) / 2;
int row=(e.getY()-yOffset)/BOX_SIZE;
int col=(e.getX()-xOffset)/BOX_SIZE;
//Check that we are in the grid
if (row>=0&&row<ROWS&&col>=0&&col<COLS) {
//Set new color
cells[row][col]=Color.white;
//Repaint, only the changed region
repaint(xOffset + (col * BOX_SIZE), yOffset + (row * BOX_SIZE), BOX_SIZE, BOX_SIZE);
}
}
}
}
You could use GridPane layout with a custom class for representing the squares
I have a working example here if you want to check
All squares handle their own painting
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
public class ColoredBoxes {
//Selected Colors
private Color[] availableColors = new Color[]{Color.YELLOW, Color.RED, Color.BLUE, Color.GREEN};
public ColoredBoxes() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Collapse");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static void main(String[] args) {
new ColoredBoxes();
}
public class TestPane extends JPanel {
//Size of the board
protected static final int ROWS = 25;
protected static final int COLS = 25;
protected static final int BOX_SIZE = 25;
private List<Square> colors; // List of the representation of the Squares
//RandomColors across the given board size.
public TestPane() {
int length = ROWS * COLS;
GridLayout gridLayout = new GridLayout(ROWS, HEIGHT, 0, 0);
this.setLayout(gridLayout);
colors = new ArrayList<>();
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
int randomColor = (int) (Math.random() * availableColors.length);
Square temp = new Square(availableColors[randomColor], row, col);
colors.add(temp);
this.add(temp);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(COLS * BOX_SIZE, ROWS * BOX_SIZE);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int xOffset = (getWidth() - (COLS * BOX_SIZE)) / 2;
int yOffset = (getHeight() - (ROWS * BOX_SIZE)) / 2;
System.out.println("...");
for (int row = 0; row < ROWS; row++) {
for (int col = 0; col < COLS; col++) {
int index = (row * COLS) + col;
g2d.setColor(colors.get(index).getColor());
g2d.fillRect(xOffset + (col * BOX_SIZE), yOffset + (row * BOX_SIZE), BOX_SIZE, BOX_SIZE);
}
}
g2d.dispose();
}
}
public class Square extends JPanel {
private Color color;
private boolean clicked = false;
private int row;
private int col;
public Square(Color color, int row, int col) {
this.row = row;
this.col = col;
this.color = color;
this.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
if (!clicked) {
//do stuff
Square source = (Square) e.getSource();
source.setColor(Color.white);
repaint();//Dont forget the repaint method
clicked = true;
}
}
#Override
public void mousePressed(MouseEvent e) {
if (!clicked) {
//do stuff
Square source = (Square) e.getSource();
source.setColor(Color.white);
repaint();//Dont forget the repaint method
clicked = true;
}
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillRect(0, 0, getWidth(), getHeight());
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
}
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.
I'm making a fun little test screen recording program in java, and I want it to have a preview of your screen before you start recording.. but its a very slow and poor method of which I am using, involving capturing an image, saving it, then reading it in through a bufferedimage and drawing that image using Graphics. Its very slow and not useful as a "preview" is there a way to speed up and have a more efficient "previewing system".
Here is what I have so far:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class MainFrame implements ActionListener, Runnable {
//add frame components
public static JFrame frame = new JFrame("Screen Caper - v1.0.1");
JButton start = new JButton("record");
JButton close = new JButton("Exit");
JPanel preview = new JPanel();
public static boolean running = false;
public static boolean recording = false;
public static boolean paused = false;
public static String curDir = System.getProperty("user.dir");
//get the screen width
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
Container a = new Container();
Container b = new Container();
public MainFrame() {
frame.setSize((int)(width) - 80, (int)(height) - 80);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//setup the buttons and JPanel
a.setLayout(new GridLayout(1, 2));
a.add(start);
start.addActionListener(this);
a.add(close);
close.addActionListener(this);
frame.add(a, BorderLayout.NORTH);
b.setLayout(new GridLayout(1, 2));
b.add(preview);
frame.add(b, BorderLayout.CENTER);
//add anything else
running = true;
//set frame to visible
frame.setVisible(true);
run();
}
public static void main(String[] args) {
new MainFrame();
}
public void run() {
Graphics g = frame.getGraphics();
while (running) {
//draw the preview of the computer screen on the JPanel if its not recording already
if (!recording && !paused) {
drawPreview(g);
}
}
}
public void drawPreview(Graphics g) {
BufferedImage image;
try {
image = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIO.write(image, "png", new File("test.png"));
} catch (Exception ex) {
ex.printStackTrace();
}
BufferedImage prevIm;
try {
prevIm = ImageIO.read(new File("test.png"));
g.setColor(new Color(0, 0, 0));
g.fillRect(preview.getX() + 3, preview.getY() + 51, preview.getWidth(), preview.getHeight() + 1);
g.drawImage(prevIm, preview.getX() + 3, preview.getY() + 51, preview.getX() + preview.getWidth(), preview.getY() + preview.getHeight(), null);
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void record(Graphics g) {
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource().equals(start)) {
if (!recording) {
//if the program isn't recording, then start recording
Graphics g = frame.getGraphics();
record(g);
start.setText("Finish");
recording = true;
System.out.println("recording...");
} else {
//else stop recording
start.setText("record");
recording = false;
System.out.println("done");
}
}
if (event.getSource().equals(close)) {
paused = true;
int ans = JOptionPane.showConfirmDialog(null, "Woah there! You're about to quit the application\nAre you sure you want to procced?", "Caution!", JOptionPane.YES_NO_OPTION);
if (ans == JOptionPane.YES_OPTION) {
System.exit(0);
} else if (ans == JOptionPane.NO_OPTION) {
paused = false;
}
}
}
}
any help is appreciated!
Don't use getGraphics, this is not how custom painting is done.
Your run method may simply be running to fast, consider using a javax.swing.Timer instead
Toolkit.getDefaultToolkit().getScreenSize() only returns the "default" screen and does not take into consideration split screens
Capturing the screen is a time consuming process and there's not much you can do about reducing it (as it's outside of your control). You "could" setup a series of Threads whose job it was to capture a given section of the desktop. You could also achieve this using SwingWorkers which would make it easier to sync the updates back to the UI...
Take a look at:
Performing Custom Painting
Concurrency in Swing
How to Use Swing Timers
Updated with example
This is a proof of concept only! You should understand what it's trying to do and borrow ideas from it...
You can see the preview window change inside the preview window...kinda freaky...
It tested this on a virtual desktop of 4480x1600.
Basically, it divides the desktop up into a 4x4 grid and starts a Thread for each section. Each thread is responsible for capturing it's own section of the screen.
It also scales that resulting image down and feeds it back to the UI.
I had started with SwingWorkers, but it seems to be hard to be limited to 10 threads. You could reduce the grid size and use SwingWorkers, they tend to be simpler to use and manage then raw Threads.
Each section is given an id, which allows me keep track of what's changed. Technically, you could just add elements to a List, but how do you determine what's new and what's old?
import java.awt.AWTException;
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.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PreviewDesktop {
public static void main(String[] args) {
new PreviewDesktop();
}
public PreviewDesktop() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements Puzzler {
private Rectangle virtualBounds;
private double scale;
private Map<Integer, PuzzlePiece> pieces;
public TestPane() {
virtualBounds = getVirtualBounds();
int columns = 4;
int rows = 4;
pieces = new HashMap<>(columns * rows);
int columnWidth = Math.round(virtualBounds.width / (float) columns);
int rowHeight = Math.round(virtualBounds.height / (float) rows);
int id = 0;
for (int row = 0; row < rows; row++) {
int y = virtualBounds.y + (row * rowHeight);
for (int column = 0; column < columns; column++) {
int x = virtualBounds.x + (column * columnWidth);
Rectangle bounds = new Rectangle(x, y, columnWidth, rowHeight);
GrabberWorker worker = new GrabberWorker(id, this, bounds);
System.out.println(id);
id++;
startThread(worker);
}
}
}
#Override
public double getScale() {
return scale;
}
#Override
public void invalidate() {
super.invalidate();
scale = getScaleFactorToFit(virtualBounds.getSize(), getSize());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (Integer id : pieces.keySet()) {
PuzzlePiece piece = pieces.get(id);
Rectangle bounds = piece.getBounds();
BufferedImage img = piece.getImage();
g2d.drawImage(img, bounds.x, bounds.y, this);
// If you want to see each sections bounds, uncomment below...
//g2d.draw(bounds);
}
g2d.dispose();
}
#Override
public void setPiece(int id, PuzzlePiece piece) {
pieces.put(id, piece);
repaint();
}
protected void startThread(GrabberWorker worker) {
Thread thread = new Thread(worker);
thread.setDaemon(true);
thread.start();
}
}
public class PuzzlePiece {
private final Rectangle bounds;
private final BufferedImage img;
public PuzzlePiece(Rectangle bounds, BufferedImage img) {
this.bounds = bounds;
this.img = img;
}
public Rectangle getBounds() {
return bounds;
}
public BufferedImage getImage() {
return img;
}
}
public interface Puzzler {
public void setPiece(int id, PuzzlePiece piece);
public double getScale();
}
public class GrabberWorker implements Runnable {
private Rectangle bounds;
private Puzzler puzzler;
private int id;
private volatile PuzzlePiece parked;
private ReentrantLock lckParked;
public GrabberWorker(int id, Puzzler puzzler, Rectangle bounds) {
this.id = id;
this.bounds = bounds;
this.puzzler = puzzler;
lckParked = new ReentrantLock();
}
protected void process(PuzzlePiece piece) {
// puzzler.setPiece(bounds, chunks.get(chunks.size() - 1));
puzzler.setPiece(id, piece);
}
protected void publish(PuzzlePiece piece) {
lckParked.lock();
try {
parked = piece;
} finally {
lckParked.unlock();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
lckParked.lock();
try {
process(parked);
} finally {
lckParked.unlock();
}
}
});
}
#Override
public void run() {
try {
Robot bot = new Robot();
while (true) {
BufferedImage img = bot.createScreenCapture(bounds);
double scale = puzzler.getScale();
Rectangle scaled = new Rectangle(bounds);
scaled.x *= scale;
scaled.y *= scale;
scaled.width *= scale;
scaled.height *= scale;
BufferedImage imgScaled = getScaledInstance(img, scale);
publish(new PuzzlePiece(scaled, imgScaled));
Thread.sleep(500);
}
} catch (AWTException | InterruptedException exp) {
exp.printStackTrace();
}
}
}
public static Rectangle getVirtualBounds() {
Rectangle bounds = new Rectangle(0, 0, 0, 0);
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
for (GraphicsDevice gd : lstGDs) {
bounds.add(gd.getDefaultConfiguration().getBounds());
}
return bounds;
}
public static double getScaleFactorToFit(Dimension original, Dimension toFit) {
double dScale = 1d;
if (original != null && toFit != null) {
double dScaleWidth = getScaleFactor(original.width, toFit.width);
double dScaleHeight = getScaleFactor(original.height, toFit.height);
dScale = Math.min(dScaleHeight, dScaleWidth);
}
return dScale;
}
public static double getScaleFactor(int iMasterSize, int iTargetSize) {
double dScale = (double) iTargetSize / (double) iMasterSize;
return dScale;
}
public static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor) {
return getScaledInstance(img, dScaleFactor, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
}
protected static BufferedImage getScaledInstance(BufferedImage img, double dScaleFactor, Object hint, boolean bHighQuality) {
BufferedImage imgScale = img;
int iImageWidth = (int) Math.round(img.getWidth() * dScaleFactor);
int iImageHeight = (int) Math.round(img.getHeight() * dScaleFactor);
// System.out.println("Scale Size = " + iImageWidth + "x" + iImageHeight);
if (dScaleFactor <= 1.0d) {
imgScale = getScaledDownInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
} else {
imgScale = getScaledUpInstance(img, iImageWidth, iImageHeight, hint, bHighQuality);
}
return imgScale;
}
protected static BufferedImage getScaledDownInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = (img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
if (targetHeight > 0 || targetWidth > 0) {
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(Math.max(w, 1), Math.max(h, 1), type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
} else {
ret = new BufferedImage(1, 1, type);
}
return ret;
}
protected static BufferedImage getScaledUpInstance(BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality) {
int type = BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality) {
w = img.getWidth();
h = img.getHeight();
} else {
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w < targetWidth) {
w *= 2;
if (w > targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h < targetHeight) {
h *= 2;
if (h > targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
tmp = null;
} while (w != targetWidth || h != targetHeight);
return ret;
}
}
Now, if you're feeling really adventurous, you could update this idea so that if the underlying image for a section didn't change and the scale didn't change, it didn't send that to the UI, which might help reduce some of the overhead ... and no, I don't have code to do that ;)
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();
}
});
}
}