How to stop background graphics in java? - java

i try to make a simple java game . ıt work fine but i draw a background but i didn't stop square's color , it always change
i write another class for that and i call it in main but i didn't work it
#SuppressWarnings("serial")
class BackPan extends JFrame{
private JLayeredPane layers;
private JPanel down;
static int width = Board.boardWidth;
static int height = Board.boardHeight;
Random rnd = new Random();
public BackPan(){
layers = new JLayeredPane();
rnd =new Random();
down = new JPanel(){
public void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D)g;
//***************************************************************
int low = 50;
int high = 255;
for(int i = 0; i<= width; i+=50){
g2d.setColor(new Color(rnd.nextInt(high-low)+low,rnd.nextInt(high-low)+low,rnd.nextInt(high-low)+low));
g2d.fillRect(i, 50, 50, 50);
for(int j = 0; j<= height; j += 50 ){
g2d.setColor(new Color(rnd.nextInt(high-low)+low,rnd.nextInt(high-low)+low,rnd.nextInt(high-low)+low));
g2d.fillRect(i, j, 50, 50);
}
}
}
};
//****************************************************************
down.setBounds(0, 0, width, height);
layers.add(down, new Integer(1));
getContentPane().add(layers, BorderLayout.CENTER);
}
}

Better than using a set seed for your randomization, simply fix the random image by one of two ways:
Create an array of colors that you randomize when needed and then use this array when drawing the background
Even better, simply draw your random colors to a BufferedImage and draw that in the paintComponent method. If this needs to be re-randomized, then re-create the image.
For an example of the latter, note that the image re-randomizes only when the button is pressed (by calling the createBackground() method):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class ColorSquares extends JPanel {
public static final int SQR_SIDE = 50;
public static final int COLUMNS = 20;
public static final int ROWS = 16;
private int columns;
private int rows;
private int sqrSide;
private Image backgroundImg;
public ColorSquares(int columns, int rows, int sqrSide) {
this.columns = columns;
this.rows = rows;
this.sqrSide = sqrSide;
backgroundImg = createBackground();
add(new JButton(new AbstractAction("New Background") {
#Override
public void actionPerformed(ActionEvent arg0) {
backgroundImg = createBackground();
repaint();
}
}));
}
public Image createBackground() {
int w = columns * sqrSide;
int h = rows * sqrSide;
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.getGraphics();
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
float hue = (float) Math.random();
float saturation = (float) (Math.random() * 0.5 + 0.5);
float brightness = (float) (Math.random() * 0.5 + 0.5);
Color randColor = Color.getHSBColor(hue, saturation, brightness);
g.setColor(randColor);
int x = c * sqrSide;
int y = r * sqrSide;
g.fillRect(x, y, sqrSide, sqrSide);
}
}
g.dispose();
return img;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(columns * sqrSide, rows * sqrSide);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Colors");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ColorSquares(COLUMNS, ROWS, SQR_SIDE));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
An additional benefit of using a BufferedImage is that it's quicker to draw this than as you're doing it.

The simplest solution would be to remember a constant random seed and set it via rnd.setSeed() each time paintComponent is called. For example:
private final static int SEED = 1000;
rnd.setSeed(SEED);

Related

how to draw moving rectangle in java canvas? [duplicate]

I'm currently working on a 2D game in Java for school. We have to use an Abstract Factory design pattern. For the 2D implementation I use a factory as follows:
public class Java2DFact extends AbstractFactory {
public Display display;
private Graphics g;
public Java2DFact() {
display = new Display(2000, 1200);
}
#Override
public PlayerShip getPlayership()
{
return new Java2DPlayership(display.panel);
}
In my display class I create a JFrame and Jpanel
public class Display {
public JFrame frame;
public JPanel panel;
public int width, height;
public Display(int width, int height) {
this.width = width;
this.height = height;
frame = new JFrame();
frame.setTitle("SpaceInvaders");
frame.setSize(1200,800);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
panel = new JPanel(){
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
}
};
panel.setFocusable(true);
frame.add(panel);
}
}
Now from my main gameloop I call the visualize method inside the Java2DPLayership class to visualize my Playership
public class Java2DPlayership extends PlayerShip {
private JPanel panel;
private Graphics2D g2d;
private Image image;
private BufferStrategy bs;
public Java2DPlayership(JPanel panel) {
super();
this.panel = panel;
}
public void visualize() {
try {
image = ImageIO.read(new File("src/Bee.gif"));
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
//g.setColor(new Color(0, 0, 0));
//g.fillRect(10, 10, 12, 8);
g.drawImage(image, (int) super.getMovementComponent().x, (int) super.getMovementComponent().y, null);
Toolkit.getDefaultToolkit().sync();
g.dispose();
panel.repaint();
} catch(Exception e){
System.out.println(e.toString());
}
}
}
My goal is to pass around the JPanel to every entity and let it draw its contents onto the panel before showing it. However I can't seem to figure out how to do this. When using this approach by changing the Graphics of the panel I get a lot of flickering.
Here is a fully functional, albeit simple example, I wrote some time ago. It just has a bunch of balls bouncing off the sides of the panel. Notice that the render method of the Ball class accepts the graphics context from paintComponent. If I had more classes that needed to be rendered, I could have created a Renderable interface and have each class implement it. Then I could have a list of Renderable objects and just go thru them and call the method. But as I also said, that would need to happen quickly to avoid tying up the EDT.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Bounce extends JPanel {
private static final int COLOR_BOUND = 256;
private final static double INC = 1;
private final static int DIAMETER = 40;
private final static int NBALLS = 20;
private final static int DELAY = 5;
private final static int PANEL_WIDTH = 800;
private final static int PANEL_HEIGHT = 600;
private final static int LEFT_EDGE = 0;
private final static int TOP_EDGE = 0;
private JFrame frame;
private double rightEdge;
private double bottomEdge;
private List<Ball> balls = new ArrayList<>();
private Random rand = new Random();
private List<Long> times = new ArrayList<>();
private int width;
private int height;
public Bounce(int width, int height) {
this.width = width;
this.height = height;
frame = new JFrame("Bounce");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
addComponentListener(new MyComponentListener());
frame.pack();
frame.setLocationRelativeTo(null);
rightEdge = width - DIAMETER;
bottomEdge = height - DIAMETER;
for (int j = 0; j < NBALLS; j++) {
int r = rand.nextInt(COLOR_BOUND);
int g = rand.nextInt(COLOR_BOUND);
int b = rand.nextInt(COLOR_BOUND);
Ball bb = new Ball(new Color(r, g, b), DIAMETER);
balls.add(bb);
}
frame.setVisible(true);
}
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public static void main(String[] args) {
new Bounce(PANEL_WIDTH, PANEL_HEIGHT).start();
}
public void start() {
/**
* Note: Using sleep gives a better response time than
* either the Swing timer or the utility timer. For a DELAY
* of 5 msecs between updates, the sleep "wakes up" every 5
* to 6 msecs while the other two options are about every
* 15 to 16 msecs. Not certain why this is happening though
* since the other timers are run on threads.
*
*/
Timer timer = new Timer(0,(ae)-> {repaint();
for (Ball b : balls) {
b.updateDirection();
}} );
timer.setDelay(5); // 5 ms.
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Ball ball : balls) {
ball.render(g2d);
}
}
class MyComponentListener extends ComponentAdapter {
public void componentResized(ComponentEvent ce) {
Component comp = ce.getComponent();
rightEdge = comp.getWidth() - DIAMETER;
bottomEdge = comp.getHeight() - DIAMETER;
for (Ball b : balls) {
b.init();
}
}
}
class Ball {
private Color color;
public double x;
private double y;
private double yy;
private int ydir = 1;
private int xdir = 1;
private double slope;
private int diameter;
public Ball(Color color, int diameter) {
this.color = color;
this.diameter = diameter;
init();
}
public void init() {
// Local constants not uses outside of method
// Provides default slope and direction for ball
slope = Math.random() * .25 + .50;
x = (int) (rightEdge * Math.random());
yy = (int) (bottomEdge * Math.random()) + diameter;
xdir = Math.random() > .5 ? -1
: 1;
ydir = Math.random() > .5 ? -1
: 1;
y = yy;
}
public void render(Graphics2D g2d) {
g2d.setColor(color);
g2d.fillOval((int) x, (int) y, diameter, diameter);
}
public void updateDirection() {
x += (xdir * INC);
yy += (ydir * INC);
y = yy * slope;
if (x < LEFT_EDGE || x > rightEdge) {
xdir = -xdir;
}
if (y < TOP_EDGE || y > bottomEdge) {
ydir = -ydir;
}
}
}
}

Why are the randomized rectangles I've created not showing up in my game?

I'm new to gui java and I've been trying to recreate the game called" jump it" (http://www.crazygames.com/game/jump-it) and I'm currently on the process of making the randomized rectangles for my character to jump on. However I ran my code and I had no errors, but the rectangles that I made isn't showing up. I attached my code underneath, it's kinda long sorry about that.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.util.Random;
import java.util.TimerTask;
class GuiGame{
public static void main(String args[]) {
JFrame f = new JFrame("RUN - Christine & Esther"); //title of frame
Container cont = f.getContentPane(); // get container - top of the frame
cont.setLayout(new BorderLayout());
BtnActPanel bp = new BtnActPanel(); // create an object of our game panel
cont.add(bp, BorderLayout.CENTER );
f.setVisible(true);
f.setSize(975,613); //size of frame
}
}
class Rectangle{
static Random r = new Random();
static int upperX = 100;
static int lowerX = 20;
static int upperY = 550;
static int lowerY = 450;
static int minWidth = 200;
static int maxWidth = 600;
static int minHeight = 40;
static int maxHeight = 140;
static int x = 0, y = 0, w = 0, h = 0, check = 0;
public Rectangle(){
check++;
int x = 650 + 50*check;
int y = r.nextInt(upperY-lowerY + 1) + lowerY; // from 450 to 550
int w = r.nextInt(maxWidth-minWidth + 1) + minWidth; // from 200 to 600
int h = r.nextInt(maxHeight - minHeight + 1) + minHeight; // from 40 to 140
}
public int getx(){
return x;
}
public int gety(){
return y;
}
public int getw(){
return w;
}
public int geth(){
return h;
}
}
class BtnActPanel extends JPanel implements ActionListener{
//variables
private JButton b1, b2, b3;
private JPanel background;
private JPanel game;
private Timer t, timer;
private int x = 0, check1 = 0, index = 0, x1 = 650, count2 = 0,
y2 = (int)(Math.random()*100)+40, y1 = (int)(Math.random()*100)+450,
x2 = (int)(Math.random()*600)+200, xaxis = 0, yaxis = 0, w = 0, h = 0, count = 0;
private ImageIcon []arrImage;
private boolean check2;
private static ImageIcon icon, exitButton, startButton, questionButton, b, instruct, c ;
public BtnActPanel(){
c = new ImageIcon("character.png"); // constructor
t = new Timer (100,this);
arrImage = new ImageIcon[2];
arrImage[0] = new ImageIcon("character.png");
arrImage[1] = new ImageIcon("character2.png");
startButton = new ImageIcon("startButton.png");//start button image
questionButton = new ImageIcon("QuestionButton.png"); //question button image
exitButton = new ImageIcon("exitButton.png"); //exit button image
icon = new ImageIcon("Title.jpg");//title image
b1 = new JButton(questionButton); // creates first button
//only shows button image with borders
b1.setOpaque(false);
b1.setContentAreaFilled(false);
b1.setBorderPainted(false);
b1.setFocusPainted(false);
b2 = new JButton(startButton);// creates second button
//only shows button image with borders
b2.setOpaque(false);
b2.setContentAreaFilled(false);
b2.setBorderPainted(false);
b2.setFocusPainted(false);
b3 = new JButton(exitButton);// creates third button
//only shows button image with borders
b3.setOpaque(false);
b3.setContentAreaFilled(false);
b3.setBorderPainted(false);
b3.setFocusPainted(false);
//adds buttons to code
this.add(b1);
this.add(b2);
this.add(b3);
b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
}// end of constructor
public void actionPerformed(ActionEvent e) { //checks which button the user presses and performs actions based off choice
if(e.getSource() == b1){
check1 = 2;
this.remove(b1);
this.remove(b3);
repaint();
instruct = new ImageIcon("Instructions.jpg");
}
else if (e.getSource() == b2){
t.start();
check1 = 1;
this.remove(b1);
this.remove(b2);
this.remove(b3);
repaint();
b = new ImageIcon("toskyline.png");
}
else if (e.getSource() == b3){
JOptionPane.showMessageDialog(null, "This is an exit button, hope you enjoyed the game! :)", "Exit message",JOptionPane.WARNING_MESSAGE ); //shows exit message
System.exit(0);//exits program
}
else if (e.getSource() == t){
if (index == 0){
index = 1;
c = arrImage[1];
}
else{
index = 0;
c = arrImage[0];
}
if(count%50 == 0 && count >= 50){
Rectangle obstacle = new Rectangle();
int xaxis = obstacle.getx();
int yaxis = obstacle.gety();
int w = obstacle.getw();
int h = obstacle.geth();
xaxis = xaxis - 10;
count2 = 1;
}
x = x - 10;
x1 = x1 - 10;
repaint();
}
}
public void paintComponent(Graphics g){//this method draws and paints images and icons based on the user decisions
super.paintComponent(g);
if(check1 == 0)[enter image description here][1]
g.drawImage(icon.getImage(),0,0,null);
if(check1 == 1){
g.drawImage(b.getImage(),0,0,null);
g.setColor(Color.black);
g.fillRect(x,495, 500, 35);
g.fillRect(x1, y1, x2, y2);
count++;
System.out.println(count);
if(count2 == 1){
g.fillRect(xaxis, yaxis, w, h);
count2 = 0;
}
g.drawImage(c.getImage(), 100, 460, null);
}
if(check1 == 2)
g.drawImage(instruct.getImage(),0,0,null);
b1.setBounds(320, 350, 100, 100);
b2.setBounds(420, 350, 100, 100);
b3.setBounds(520, 350, 100, 100);
}
}//end of class
Using your ranges I made a demo.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Demo extends JPanel implements ActionListener {
final static int height = 800;
final static int width = 800;
final static String title = "title";
JFrame frame = new JFrame("default title");
Timer timer;
static Random r = new Random();
static int upperX = 100;
static int lowerX = 20;
static int upperY = 550;
static int lowerY = 450;
static int minWidth = 200;
static int maxWidth = 600;
static int minHeight = 40;
static int maxHeight = 140;
List<MyRectangle> rectangles = new ArrayList<>();
public static void main(String[] args) {
SwingUtilities
.invokeLater(() -> new Demo().start());
}
public Demo() {
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.setPreferredSize(
new Dimension(width, height));
setBackground(Color.WHITE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void start() {
timer = new Timer(0, this);
timer.setDelay(1000);
timer.start();
}
public void actionPerformed(ActionEvent ae) {
rectangles.add(createRectangle());
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (MyRectangle r : rectangles) {
g2d.setColor(Color.black);
g2d.drawRect(r.x, r.y, r.width, r.height);
g2d.setColor(r.color);
g2d.fillRect(r.x+1, r.y+1, r.width-1,r.height-1);
}
g2d.dispose();
}
Color[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.ORANGE, Color.GRAY};
int color = 0;
public MyRectangle createRectangle() {
int y = r.nextInt(upperY - lowerY + 1) + lowerY; // from 450 to 550
int w = r.nextInt(maxWidth - minWidth + 1)
+ minWidth; // from 200 to 600
int h = r.nextInt(maxHeight - minHeight + 1)
+ minHeight; // from 40 to 140
int x = r.nextInt(upperX - lowerX + 1) + lowerX;
Color c = colors[color++ % colors.length];
return new MyRectangle(c, x, y, w, h);
}
class MyRectangle extends Rectangle {
Color color;
MyRectangle(Color c, int x, int y, int w, int h) {
super(x, y, w, h);
this.color = c;
}
}
}
This extends the JDK class Rectangle and adds a color field to the subclass. It displays a new rectangle very second.

How do I show only the HSV box of a JColorChooser?

In this image you can see a default Java Swing color chooser, JColorChooser:
What I want is just the color square and vertical slider as outlined in red:
I was able to remove all the tabs (Swatches, HSL, etc) and the preview, but I was unable to remove all the sliders. How can I do this?
OK, just for grins, I decided to create your desired JPanel from scratch, wiring it up in a kind of View-Controller set up, since the model here is trivial -- a Color field within the controller. To use this component you create an instance of the component, add it to your GUI where desired and simply add a PropertyChangeListener to it that listens to its COLOR property:
hsvChooserPanel.addPropertyChangeListener(HsvChooserPanel.COLOR, pce -> {
Color c = (Color) pce.getNewValue();
// do what you want with Color value, c, here
});
The test class:
Version 2: this allows use of any 3 of the HSV panel/bar combinations, either the one with the bar focused on Hue, or Saturation, or Value (here Brightness). It uses an enum, ColorProperty, that has 3 values, ColorProperty.HUE, ColorProperty.SATURATION, and ColorProperty.BRIGHTNESS, and has the calculations within the enum items themselves on how to create the color bar and the color square BufferedImages. Comments welcome:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestHsvChooser2 {
// ***** choose which color panel / color bar you'd like to test:
// private static final ColorProperty COLOR_PROP = ColorProperty.HUE;
// private static final ColorProperty COLOR_PROP = ColorProperty.BRIGHTNESS;
private static final ColorProperty COLOR_PROP = ColorProperty.SATURATION;
private static void createAndShowGui() {
HsvChooserPanel2 hsvChooserPanel = new HsvChooserPanel2(COLOR_PROP);
JPanel testPanel = new JPanel();
JPanel outerPanel = new JPanel(new BorderLayout());
outerPanel.add(testPanel);
outerPanel.setBorder(BorderFactory.createTitledBorder("Test Panel"));
hsvChooserPanel.addPropertyChangeListener(HsvChooserPanel2.COLOR, pce -> {
Color c = (Color) pce.getNewValue();
testPanel.setBackground(c);
});
JPanel gridPanel = new JPanel(new GridLayout(0, 1, 10, 10));
gridPanel.add(hsvChooserPanel);
gridPanel.add(outerPanel);
JFrame frame = new JFrame("HSV Chooser");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gridPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
The whole shebang:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.event.SwingPropertyChangeSupport;
#SuppressWarnings("serial")
public class HsvChooserPanel2 extends JPanel {
public static final String COLOR = "color";
private static final int PREF_W = 180;
private static final int PREF_H = PREF_W;
private static final int PREF_W_CB = 20;
private static final int GAP = 10;
private MyColorPanel2 colorPanel = null;
private MyColorBar2 colorBar = null;
private InnerControl2 innerControl = null;
public HsvChooserPanel2(ColorProperty colorProp) {
colorPanel = new MyColorPanel2(PREF_W, PREF_H, colorProp);
colorBar = new MyColorBar2(PREF_W_CB, PREF_H, colorProp);
innerControl = new InnerControl2(this, colorPanel, colorBar);
colorPanel.setColorPropertyValue(Color.RED); // !! magic value
setLayout(new BorderLayout(GAP, GAP));
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
add(colorPanel, BorderLayout.CENTER);
add(colorBar, BorderLayout.LINE_END);
// propagate COLOR changes in the inner controller
// to this component's property change support
innerControl.addPropertyChangeListener(COLOR, pce -> {
firePropertyChange(COLOR, pce.getOldValue(), pce.getNewValue());
});
}
}
// listens for changes to both the color bar and the color panel
class InnerControl2 {
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private HsvChooserPanel2 hsvChooser;
private MyColorPanel2 colorPanel;
private MyColorBar2 colorBar;
private Color color; // This is all there is to the model, a "bound"
// property
public InnerControl2(HsvChooserPanel2 hsvChooser, MyColorPanel2 colorPanel, MyColorBar2 colorBar) {
this.hsvChooser = hsvChooser;
this.colorPanel = colorPanel;
this.colorBar = colorBar;
// listen for changes
colorPanel.addPropertyChangeListener(ColorPanelParent.CURSOR, new ColorPanelListener());
colorBar.addPropertyChangeListener(ColorPanelParent.CURSOR, new ColorBarListener());
}
public Color getColor() {
return color;
}
// classic setter method for a "bound" property
public void setColor(Color color) {
Color oldValue = this.color;
Color newValue = color;
this.color = color;
// notify listeners of the change
pcSupport.firePropertyChange(HsvChooserPanel2.COLOR, oldValue, newValue);
}
// allow outside classes the ability to listen
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(name, listener);
}
public HsvChooserPanel2 getHsvChooser() {
return hsvChooser;
}
// inner listeners
private class ColorPanelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
Point p = colorPanel.getCursorP();
Color c = colorPanel.getColor(p);
colorBar.setColorPropertyValue(c);
setColor(c); // this will fire the prop change
// support
}
}
private class ColorBarListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
// get hue from the color bar and use it to set the main hue
// of the color panel
Point p = colorBar.getCursorP();
Color c = colorBar.getColor(p);
colorPanel.setColorPropertyValue(c);
}
}
}
// parent of both color bar panel and color panel
#SuppressWarnings("serial")
abstract class ColorPanelParent extends JPanel {
public static final String CURSOR = "cursor";
private int prefW;
private int prefH;
private Point cursorP = new Point(0, 0);
private BufferedImage img = null;
private ColorProperty colorProperty;
private boolean panel;
public ColorPanelParent(int prefW, int prefH, ColorProperty colorProperty, boolean panel) {
this.prefW = prefW;
this.prefH = prefH;
this.colorProperty = colorProperty;
this.panel = panel;
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
setBorder(BorderFactory.createLineBorder(Color.BLACK));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
public int getPrefH() {
return prefH;
}
public int getPrefW() {
return prefW;
}
public ColorProperty getColorProperty() {
return colorProperty;
}
public BufferedImage getImg() {
return img;
}
public Point getCursorP() {
return cursorP;
}
public void setImg(BufferedImage img) {
this.img = img;
repaint();
}
public Color getColor(Point p) {
Color c = null;
if (getImg() != null) {
int rgb = getImg().getRGB(p.x, p.y);
c = new Color(rgb);
}
return c;
}
// when the main hue is changed, we have to create a new
// background image to reflect the new main color
public void setColorPropertyValue(Color color) {
int w = getPrefW();
int h = getPrefH();
BufferedImage img = getColorProperty().createImage(color, w, h, panel);
setImg(img);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
// change the cursor point and then
// notify prop change support of changes
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
mouseResponse(e);
}
#Override
public void mouseDragged(MouseEvent e) {
mouseResponse(e);
}
private void mouseResponse(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (!contains(e.getPoint())) {
x = Math.max(0, x);
x = Math.min(prefW - 1, x);
y = Math.max(0, y);
y = Math.min(prefH - 1, y);
}
Point oldValue = cursorP;
cursorP = new Point(x, y);
firePropertyChange(CURSOR, oldValue, cursorP);
repaint();
}
}
}
// color bar on the right side of the HsvChooser JPanel.
// Controller action: Changing selection point on this JPanel
// will change the hue of the color panel
#SuppressWarnings("serial")
class MyColorBar2 extends ColorPanelParent {
public MyColorBar2(int prefW, int prefH, ColorProperty colorProperty) {
super(prefW, prefH, colorProperty, false);
// create and set the background image
setColorPropertyValue(Color.RED); // fix the magic number?
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // draws the background image
// this draws a line at the cursor's location
g.setXORMode(Color.WHITE);
int y = getCursorP().y;
g.drawLine(0, y, getPrefW(), y);
}
}
// color panel on the left side of the HsvChooser JPanel.
// Controller action: Changing selection point on this JPanel
// will notify listeners of a new COLOR selection
#SuppressWarnings("serial")
class MyColorPanel2 extends ColorPanelParent {
private static final int CURSOR_RADIUS = 8;
public MyColorPanel2(int prefW, int prefH, ColorProperty colorProperty) {
super(prefW, prefH, colorProperty, true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // draws the background image
// draws the cross hatch indicating color selection point
g.setXORMode(Color.WHITE);
int x = getCursorP().x;
int y = getCursorP().y;
int x1 = x - CURSOR_RADIUS;
int y1 = y - CURSOR_RADIUS;
int x2 = x + CURSOR_RADIUS;
int y2 = y + CURSOR_RADIUS;
g.drawLine(x1, y, x2, y);
g.drawLine(x, y1, x, y2);
}
}
enum ColorProperty {
HUE {
#Override
public BufferedImage createImage(Color color, int w, int h, boolean panel) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
if (panel) {
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
// float array is HSB
float hue = Color.RGBtoHSB(red, green, blue, null)[0];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float s = ((float) j) / (float) w;
float b = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, s, b).getRGB();
img.setRGB(j, i, rgb);
}
}
} else {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float hue = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, 1f, 1f).getRGB();
img.setRGB(j, i, rgb);
}
}
}
return img;
}
},
SATURATION {
#Override
public BufferedImage createImage(Color color, int w, int h, boolean panel) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
// float array is HSB
float[] hsb = Color.RGBtoHSB(red, green, blue, null);
return panel ? createPanelImg(w, h, img, hsb) : createBarImg(w, h, img, hsb);
}
private BufferedImage createBarImg(int w, int h, BufferedImage img, float[] hsb) {
float hue = hsb[0];
// float brightness = hsb[2];
float brightness = 1f;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float saturation = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, saturation, brightness).getRGB();
img.setRGB(j, i, rgb);
}
}
return img;
}
private BufferedImage createPanelImg(int w, int h, BufferedImage img, float[] hsb) {
float saturation = hsb[1];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float hue = ((float) j) / (float) w;
float b = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, saturation, b).getRGB();
img.setRGB(j, i, rgb);
}
}
return img;
}
},
BRIGHTNESS {
#Override
public BufferedImage createImage(Color color, int w, int h, boolean panel) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
// float array is HSB
float[] hsb = Color.RGBtoHSB(red, green, blue, null);
return panel ? createPanelImg(w, h, img, hsb) : createBarImg(w, h, img, hsb);
}
private BufferedImage createBarImg(int w, int h, BufferedImage img, float[] hsb) {
float hue = hsb[0];
// float saturation = hsb[1];
float saturation = 1f;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float brightness = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, saturation, brightness).getRGB();
img.setRGB(j, i, rgb);
}
}
return img;
}
private BufferedImage createPanelImg(int w, int h, BufferedImage img, float[] hsb) {
float brightness = hsb[2];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float hue = ((float) j) / (float) w;
float saturation = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, saturation, brightness).getRGB();
img.setRGB(j, i, rgb);
}
}
return img;
}
};
public abstract BufferedImage createImage(Color color, int w, int h, boolean panel);
}
My solution:
colorChooser.setPreviewPanel(new JPanel());
AbstractColorChooserPanel[] panels = colorChooser.getChooserPanels();
for (AbstractColorChooserPanel accp : panels) {
if(!accp.getDisplayName().equals("HSV")) {
colorChooser.removeChooserPanel(accp);
}
}
JComponent current = (JComponent) colorChooser.getComponents()[0];
while( !current.getClass().toString().equals( "class javax.swing.colorchooser.ColorChooserPanel" ) ){
current = (JComponent) current.getComponents()[0];
}
for(Component jc : current.getComponents()){
if(!jc.getClass().toString().equals( "class javax.swing.colorchooser.DiagramComponent" )){
current.remove(jc);
}
}
This removes everything that I don't want, but I think making a custom one would be a better solution.
I am going to try trashgod's to see if it works better.
You can use the Swing Utils class to search for components of a given type on the panel.
In the example below you can find all the sliders and then make them invisible:
import java.awt.*;
import java.util.List;
import javax.swing.*;
import javax.swing.colorchooser.*;
public class ColorChooserPanel extends JPanel
{
ColorChooserPanel()
{
JColorChooser chooser = new JColorChooser();
AbstractColorChooserPanel[] panels = chooser.getChooserPanels();
for (AbstractColorChooserPanel panel: panels)
{
if ("HSL".equals(panel.getDisplayName()))
{
add( panel );
List<JSlider> sliders = SwingUtils.getDescendantsOfType(JSlider.class, panel, true);
for (JSlider slider: sliders)
{
slider.setVisible( false );
}
}
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("ColorChooserPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ColorChooserPanel());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
A look at the javax.swing.colorchooser internals reveals that ColorChooserComponentFactory creates subclasses of AbstractColorChooserPanel using ColorChooserPanel and a suitable subclass of ColorModel. ColorChooserPanel holds the parts you want as two instances of DiagramComponent: the left is named diagram and the right is named slider.
Instead of removing components from an existing ColorChooserPanel, consider Creating a Custom Chooser Panel that contains just the desired elements.
class MyChooserPanel extends AbstractColorChooserPanel implements PropertyChangeListener {
private final ColorModel model;
private final DiagramComponent diagram;
private final DiagramComponent slider;
MyChooserPanel(ColorModel model) {
this.model = model;
this.diagram = new DiagramComponent(this.panel, true);
this.slider = new DiagramComponent(this.panel, false);
}
…
}
Naturally, you'll have to recapitulate some of the (package-)private code, but the result will be less fragile.

Why does my buffered image not display in my JPanel?

I am trying to edit the pixels of a new buffered image but when I use the constructor for a new BufferedImage it does not display, when I load an image and set the pixels it does. Why does it not display?
public void paintComponent(Graphics g) {
super.paintComponent(g);
int w = 1000;
int h = 1000;
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
//ImageIO.read(new File("/Users/george/Documents/Ali.png"));
int color = Color.BLACK.getRGB();
for(int x = 0; x < w; x++) {
for(int y = 0; y < h; y++) {
image.setRGB(x, y, color);
}
}
g.drawImage(image, 0, 0, null);
}
Again, don't edit the BufferedImage from within paintComponent -- do it elsewhere. For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class ImageEdit extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int COLOR = Color.BLACK.getRGB();
private BufferedImage image = null;
public ImageEdit() {
image = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_RGB);
for(int x = 0; x < PREF_H; x++) {
for(int y = 0; y < PREF_W; y++) {
image.setRGB(x, y, COLOR);
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
ImageEdit mainPanel = new ImageEdit();
JFrame frame = new JFrame("ImageEdit");
frame.setDefaultCloseOperation(JFrame.DISPOSE_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();
}
});
}
}

Absolute Positioning Graphic JPanel Inside JFrame Blocked by Blank Sections

I'm trying to improve my understanding of Java, particularly Java GUI, by making a puzzle program. Currently the user selects an image, which is cut up into a specified number of pieces. The pieces are drawn randomly to the screen but they seem to be covered by blank portions of other pieces, and not all of them show up, but I can print out all the coordinates. I am using absolute positioning because a LayoutManager didn't seem to work. I briefly tried layeredPanes but they confused me and didn't seem to solve the problem. I would really appreciate some help.
Here are the 2 relevant classes:
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
public class PuzzlePieceDriver extends JFrame
{
private static Dimension SCREENSIZE = Toolkit.getDefaultToolkit().getScreenSize();
private static final int HEIGHT = SCREENSIZE.height;
private static final int WIDTH = SCREENSIZE.width;
public static int MY_WIDTH;
public static int MY_HEIGHT;
private static BufferedImage image;
private int xPieces = PuzzleMagicDriver.getXPieces();
private int yPieces = PuzzleMagicDriver.getYPieces();
private PuzzlePiece[] puzzle = new PuzzlePiece[xPieces*yPieces];
public Container pane = this.getContentPane();
private JLayeredPane layeredPane = new JLayeredPane();
public PuzzlePieceDriver(ImageIcon myPuzzleImage)
{
MY_WIDTH = myPuzzleImage.getIconWidth()+(int)myPuzzleImage.getIconHeight()/2;
MY_HEIGHT = myPuzzleImage.getIconHeight()+(int)myPuzzleImage.getIconHeight()/2;
setTitle("Hot Puzz");
setSize(MY_WIDTH,MY_HEIGHT);
setLocationByPlatform(true);
pane.setLayout(null);
image = iconToImage(myPuzzleImage); //pass image into bufferedImage form
puzzle = createClip(image);
//pane.add(layeredPane);
setVisible(true);
}//end constructor
public static BufferedImage iconToImage(ImageIcon icon)
{
Image img = icon.getImage();
int w = img.getWidth(null);
int h = img.getHeight(null);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
// Paint the image onto the buffered image
g.drawImage(img, 0, 0, null);
g.dispose();
return image;
}//end BufferedImage
protected int randomNumber(int min, int max)
{
int temp =
min + (int)(Math.random() * ((max - min) + 1));
return temp;
}//end randomNumber
private PuzzlePiece[] createClip(BufferedImage passedImage)
{
int cw, ch;
int w,h;
w = image.getWidth(null);
h = image.getHeight(null);
cw = w/xPieces;
ch = h/yPieces;
int[] cells=new int[xPieces*yPieces];
int dx, dy;
BufferedImage clip = passedImage;
//layeredPane.setPreferredSize(new Dimension(w,h));
for (int x=0; x<xPieces; x++)
{
int sx = x*cw;
for (int y=0; y<yPieces; y++)
{
int sy = y*ch;
int cell = cells[x*xPieces+y];
dx = (cell / xPieces) * cw;
dy = (cell % yPieces) * ch;
clip= passedImage.getSubimage(sx, sy, cw, ch);
int myX = randomNumber(0,(int)w);
int myY = randomNumber(0,(int)h);
PuzzlePiece piece=new PuzzlePiece(clip,myX,myY);
puzzle[x*xPieces+y]=piece;
piece.setBounds(myX,myY,w,h);
//layeredPane.setBounds(myX,myY,w,h);
//layeredPane.add(piece,new Integer(x*xPieces+y));
pane.add(piece);
piece.repaint();
}//end nested for
}//end for
return puzzle;
}//end createClip
}//end class
Sorry if the spacing is a little messed up!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
public class PuzzlePiece extends JPanel
{
private Point imageCorner; //the image's top-left corner location
private Point prevPt; //mouse location for previous event
private Boolean insideImage =false;
private BufferedImage image;
public PuzzlePiece(BufferedImage clip, int x, int y)
{
image = clip;
imageCorner = new Point(x,y);
//repaint();
}//end constructor
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, (int)getImageCornerX(),(int)getImageCornerY(), this);
System.out.println("paint "+getImageCornerX()+" "+getImageCornerY());
//repaint();
//g.dispose();
}//end paintComponent
public Point getImageCorner()
{
return imageCorner;
}//end getImageCorner
public double getImageCornerY()
{
return imageCorner.getY();
}//end getImageCornerY
public double getImageCornerX()
{
return imageCorner.getX();
}//end getPoint
}//end class PuzzlePiece
Any help would be appreciated, I've gotten really stuck! Thanks!!
I was really intrigued by this idea, so I made another example, using a custom layout manager.
public class MyPuzzelBoard extends JPanel {
public static final int GRID_X = 4;
public static final int GRID_Y = 4;
private BufferedImage image;
public MyPuzzelBoard(BufferedImage image) {
setLayout(new VirtualLayoutManager());
setImage(image);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
removeAll();
generatePuzzel();
} else {
Component comp = getComponentAt(e.getPoint());
if (comp != null && comp != MyPuzzelBoard.this) {
setComponentZOrder(comp, 0);
invalidate();
revalidate();
repaint();
}
}
}
});
}
public void setImage(BufferedImage value) {
if (value != image) {
image = value;
removeAll();
generatePuzzel();
}
}
public BufferedImage getImage() {
return image;
}
protected float generateRandomNumber() {
return (float) Math.random();
}
protected void generatePuzzel() {
BufferedImage image = getImage();
if (image != null) {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
int clipWidth = imageWidth / GRID_X;
int clipHeight = imageHeight / GRID_Y;
for (int x = 0; x < GRID_X; x++) {
for (int y = 0; y < GRID_Y; y++) {
float xPos = generateRandomNumber();
float yPos = generateRandomNumber();
Rectangle bounds = new Rectangle((x * clipWidth), (y * clipHeight), clipWidth, clipHeight);
MyPiece piece = new MyPiece(image, bounds);
add(piece, new VirtualPoint(xPos, yPos));
}
}
}
invalidate();
revalidate();
repaint();
}
public class VirtualPoint {
private float x;
private float y;
public VirtualPoint(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public void setX(float x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
}
public class VirtualLayoutManager implements LayoutManager2 {
private Map<Component, VirtualPoint> mapConstraints;
public VirtualLayoutManager() {
mapConstraints = new WeakHashMap<>(25);
}
#Override
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints instanceof VirtualPoint) {
mapConstraints.put(comp, (VirtualPoint) constraints);
}
}
#Override
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
#Override
public float getLayoutAlignmentX(Container target) {
return 0.5f;
}
#Override
public float getLayoutAlignmentY(Container target) {
return 0.5f;
}
#Override
public void invalidateLayout(Container target) {
}
#Override
public void addLayoutComponent(String name, Component comp) {
}
#Override
public void removeLayoutComponent(Component comp) {
mapConstraints.remove(comp);
}
#Override
public Dimension preferredLayoutSize(Container parent) {
return new Dimension(400, 400);
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
#Override
public void layoutContainer(Container parent) {
int width = parent.getWidth();
int height = parent.getHeight();
for (Component comp : parent.getComponents()) {
VirtualPoint p = mapConstraints.get(comp);
if (p != null) {
int x = Math.round(width * p.getX());
int y = Math.round(height * p.getY());
Dimension size = comp.getPreferredSize();
x = Math.min(x, width - size.width);
y = Math.min(y, height - size.height);
comp.setBounds(x, y, size.width, size.height);
}
}
}
}
}
Basically, this uses a "virtual" coordinate system, where by rather then supply absolute x/y positions in pixels, you provide them as percentage of the parent container. Now, to be honest, it wouldn't take much to convert back to absolute positioning, just this way, you also get layout scaling.
The example also demonstrates Z-reording (just in case) and the double click simple re-randomizes the puzzel
Oh, I also made the piece transparent (opaque = false)
Oh, one thing I should mention, while going through this example, I found that it was possible to have pieces placed off screen (completely and partially).
You may want to check your positioning code to make sure that the images when they are laid out aren't been moved off screen ;)
Try using setBorder(new LineBorder(Color.RED)) in your puzzle piece constructor to see where the bounds of your puzzle pieces are. If they are where you'd expect them to be, it's likely that your positioning is wrong. Also make your puzzle pieces extend JComponent instead, or use setOpaque(false) if you're extending JPanel.
There are lots of suggestions I'd like to make, but first...
The way you choose a random position is off...
int myX = randomNumber(0,(int)w);
int myY = randomNumber(0,(int)h);
This allows duplicate position's to be generated (and overlaying cells)
UPDATES (using a layout manager)
Okay, so this is a slight shift in paradigm. Rather then producing a clip and passing it to the piece, I allowed the piece to make chooses about how it was going to render the the piece. Instead, I passed it the Rectangle it was responsible for.
This means, you could simply use something like setCell(Rectangle) to make a piece change (unless you're hell bent on drag'n'drop ;))
I ended up using Board panel due to some interesting behavior under Java 7, but that's another question ;)
package puzzel;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.*;
public class PuzzlePieceDriver extends JFrame {
public PuzzlePieceDriver(ImageIcon myPuzzleImage) {
setTitle("Hot Puzz");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(new Board(myPuzzleImage));
pack();
setVisible(true);
}//end constructor
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
ImageIcon image = new ImageIcon(PuzzlePieceDriver.class.getResource("/issue459.jpg"));
PuzzlePieceDriver driver = new PuzzlePieceDriver(image);
driver.setLocationRelativeTo(null);
driver.setVisible(true);
}
});
}
}//end class
A piece panel...
The panel overrides the preferred and minimum size methods...while it works for this example, it's probably better to use setPreferredSize and setMiniumumSize instead ;)
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package puzzel;
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
public class PuzzlePiece extends JPanel {
private BufferedImage masterImage;
private Rectangle pieceBounds;
private BufferedImage clip;
public PuzzlePiece(BufferedImage image, Rectangle bounds) {
masterImage = image;
pieceBounds = bounds;
// Make sure the rectangle fits the image
int width = Math.min(pieceBounds.x + pieceBounds.width, image.getWidth() - pieceBounds.x);
int height = Math.min(pieceBounds.y + pieceBounds.height, image.getHeight() - pieceBounds.y);
clip = image.getSubimage(pieceBounds.x, pieceBounds.y, width, height);
}//end constructor
#Override
public Dimension getPreferredSize() {
return pieceBounds.getSize();
}
#Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 0;
int y = 0;
g.drawImage(clip, x, y, this);
g.setColor(Color.RED);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}//end paintComponent
}//end class PuzzlePiece
The board panel...used mostly because of some interesting issues I was having with Java 7...Implements a MouseListener, when you run the program, click the board, it's fun ;)
package puzzel;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
/**
*
* #author shane
*/
public class Board extends JPanel {
public static final int X_PIECES = 4;
public static final int Y_PIECES = 4;
private PuzzlePiece[] puzzle = new PuzzlePiece[X_PIECES * Y_PIECES];
private static BufferedImage image;
public Board(ImageIcon myPuzzleImage) {
image = iconToImage(myPuzzleImage); //pass image into bufferedImage form
puzzle = createClip();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
removeAll();
invalidate();
createClip();
// doLayout();
invalidate();
revalidate();
repaint();
}
});
}
public static BufferedImage iconToImage(ImageIcon icon) {
Image img = icon.getImage();
int w = img.getWidth(null);
int h = img.getHeight(null);
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = image.createGraphics();
// Paint the image onto the buffered image
g.drawImage(img, 0, 0, null);
g.dispose();
return image;
}//end BufferedImage
protected int randomNumber(int min, int max) {
int temp = min + (int) (Math.random() * ((max - min) + 1));
return temp;
}//end randomNumber
private PuzzlePiece[] createClip() {
int cw, ch;
int w, h;
w = image.getWidth(null);
h = image.getHeight(null);
cw = w / X_PIECES;
ch = h / Y_PIECES;
// Generate a list of cell bounds
List<Rectangle> lstBounds = new ArrayList<>(25);
for (int y = 0; y < h; y += ch) {
for (int x = 0; x < w; x += cw) {
lstBounds.add(new Rectangle(x, y, cw, ch));
}
}
BufferedImage clip = image;
setLayout(new GridBagLayout());
for (int x = 0; x < X_PIECES; x++) {
for (int y = 0; y < Y_PIECES; y++) {
// Get a random index
int index = randomNumber(0, lstBounds.size() - 1);
// Remove the bounds so we don't duplicate any positions
Rectangle bounds = lstBounds.remove(index);
PuzzlePiece piece = new PuzzlePiece(clip, bounds);
puzzle[x * X_PIECES + y] = piece;
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.fill = GridBagConstraints.BOTH;
add(piece, gbc);
piece.invalidate();
piece.repaint();
}//end nested for
}//end for
invalidate();
repaint();
return puzzle;
}//end createClip
}
Now I know you eventually going to ask about how to move a piece, GridBagLayout has this wonderful method called getConstraints which allows you to retrieve the constraints used to layout the component in question. You could then modify the gridx and gridy values and use setConstraints to update it (don't forget to call invalidate and repaint ;))
I'd recommend having a read of How to Use GridBagLayout for more information ;)
Eventually, you'll end up with something like:

Categories

Resources