tldr; How do you use a MouseEvent on a JFrame object(specifically JLabel) to update the displayed image in the JFrame
I am trying to create a program where an image is broken into tiles and on click of one of those tiles, the program moves the tile to the open space in the image. (See Sliding Puzzle for more information).
I currently am able to select an image, break the image into tiles, and "randomly" remove one of the tiles.
My next step would be, on click of one of the tiles, to swap it with the empty tile (I will work on the "eligibility" of tiles to be swapped at a later time, but for now, just want to be able to swap the tile selected with the current blank tile)
To create my image for a 3x3 grid, I split a bufferedImage into 9 equal pieces, "randomly" blank one of the images, and then display the images in jLabels using GridLayout to line them up.
When I add mouseListeners to each jLabel, I am able to see that I am entering the MouseListener as I can see the console log message "Clicked" as shown below, however, am not able to update the image as desired.
How can I use a MouseEvent on these JFrame JLabels to call a method within ImageContainer(i.e. move()) and update the displayed image?
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
public class ImageJumble extends JPanel {
static int difficulty = 0;
ImageContainer imageContainer;
JFrame jFrame = new JFrame("Image Jumble");
private void run() {
SwingUtilities.invokeLater(this::displayImage);
}
public static void main(String[] args) {
System.out.print("Please enter the difficulty level (1-3): ");
Scanner scanner = new Scanner(System.in);
difficulty = scanner.nextInt();
new ImageJumble().run();
}
private void displayImage() {
JFileChooser fc = new JFileChooser();
fc.setDialogTitle("Please choose an image...");
FileNameExtensionFilter filter = new FileNameExtensionFilter("JPEG", "jpeg", "jpg", "png", "bmp", "gif");
fc.addChoosableFileFilter(filter);
BufferedImage image = null;
if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
File selectedFile = fc.getSelectedFile();
try {
image = ImageIO.read(selectedFile);
} catch (IOException ex) {
ex.printStackTrace();
}
}
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jFrame.setSize(image.getWidth(), image.getHeight());
jFrame.setVisible(true);
jFrame.setLayout(new GridLayout(difficulty,difficulty,0,0));
imageContainer = new ImageContainer(image,difficulty);
createImage();
}
private void createImage() {
imageContainer.randomize();
JLabel[] jLabels = new JLabel[difficulty * difficulty];
for(int i = 0; i < jLabels.length; i++) {
JLabel jLabel = new JLabel(new ImageIcon(imageContainer.getBufferedImages().get(i)));
jFrame.add(jLabel);
jLabel.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("Clicked!");
imageContainer.move(i);
jFrame.removeAll();
createImage();
}
});
}
}
}
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class ImageContainer {
private List<BufferedImage> bufferedImages = new ArrayList<>();
private int blankLocation = 0;
public ImageContainer(BufferedImage image, int difficulty) {
BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
g.drawImage(image, 0, 0, null);
int width = bi.getWidth();
int height = bi.getHeight();
int swidth = width / difficulty;
int sheight = height / difficulty;
for (int i = 0; i < difficulty; i++) {
for (int j = 0; j < difficulty; j++) {
BufferedImage bimg = bi.getSubimage(j * swidth, i * sheight, swidth, sheight);
bufferedImages.add(bimg);
}
}
}
public List<BufferedImage> getBufferedImages() {
return bufferedImages;
}
public void setBufferedImages(List<BufferedImage> bufferedImages) {
this.bufferedImages = bufferedImages;
}
public void randomize() {
int size = bufferedImages.size();
int width = bufferedImages.get(0).getWidth();
int height = bufferedImages.get(0).getHeight();
blankLocation = new Random().nextInt(size);
bufferedImages.set(blankLocation, new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB));
}
public void move(int i) {
bufferedImages.set(blankLocation,bufferedImages.get(i));
blankLocation = i;
}
}
This answer is based on this previous answer, adapted to your code.
It is a one-file mre : the entire code can be copy-pasted to ImageJumble.java file, and run.
It supports DnD from any grid location to any other. You may want to change it. Please note the comments:
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class ImageJumble extends JPanel {
private static int difficulty = 3;
private static final String FLOWER = "http://www.digitalphotoartistry.com/rose1.jpg";
private static final int GAP = 4;
private JPanel content;
private void run() {
SwingUtilities.invokeLater(this::displayImage);
}
public static void main(String[] args) {
new ImageJumble().run();
}
private void displayImage() {
BufferedImage bi = null;
try {
bi = ImageIO.read(new URL(FLOWER));
} catch (IOException ex) {
ex.printStackTrace();
}
content = new JPanel(new GridLayout(difficulty,difficulty, GAP,GAP));
createImage(bi);
JFrame jFrame = new JFrame("Image Jumble");
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jFrame.add(content);
jFrame.pack();
jFrame.setVisible(true);
}
private void createImage( BufferedImage bi) {
ImageContainer imageContainer = new ImageContainer(bi,difficulty);
imageContainer.randomize();
for(int i = 0; i < difficulty * difficulty; i++) {
content.add(new DragDropPane(imageContainer.getBufferedImages().get(i)));;
}
}
}
class ImageContainer {
private final List<BufferedImage> bufferedImages = new ArrayList<>();
private int blankLocation = 0;
public ImageContainer(BufferedImage image, int difficulty) {
BufferedImage bi = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
g.drawImage(image, 0, 0, null);
int width = bi.getWidth();
int height = bi.getHeight();
int swidth = width / difficulty;
int sheight = height / difficulty;
for (int i = 0; i < difficulty; i++) {
for (int j = 0; j < difficulty; j++) {
BufferedImage bimg = bi.getSubimage(j * swidth, i * sheight, swidth, sheight);
bufferedImages.add(bimg);
}
}
}
public List<BufferedImage> getBufferedImages() {
return bufferedImages;
}
public void randomize() {
Collections.shuffle(bufferedImages);//shuffle images
int size = bufferedImages.size();
int width = bufferedImages.get(0).getWidth();
int height = bufferedImages.get(0).getHeight();
blankLocation = new Random().nextInt(size);
bufferedImages.set(blankLocation, new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB));
}
}
class DragDropPane extends JPanel implements DragGestureListener, DragSourceListener {
private JComponent dragable;
private final BufferedImage bi;
public DragDropPane(BufferedImage bi) {
setBackground(Color.BLACK);
this.bi = bi;
var label = new JLabel(new ImageIcon(bi), JLabel.CENTER);
setContent(label);
new MyDropTargetListener(this);
DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(
this, DnDConstants.ACTION_COPY, this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(bi.getWidth(), bi.getHeight());
}
public void setContent(JComponent component) {
removeAll();
dragable = component;
add(component);
repaint();
}
//-->DragGestureListener implementation
#Override
public void dragGestureRecognized(DragGestureEvent dge) {
// Create our transferable wrapper
Transferable transferable = new TransferableComponent(dragable);
// Start the "drag" process...
DragSource ds = dge.getDragSource();
ds.startDrag(dge, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR), transferable, this);
remove(dragable);
revalidate(); repaint();
}
//-->DragSourceListener implementation
#Override
public void dragEnter(DragSourceDragEvent dsde) {}
#Override
public void dragOver(DragSourceDragEvent dsde) {}
#Override
public void dropActionChanged(DragSourceDragEvent dsde) {}
#Override
public void dragExit(DragSourceEvent dse) {}
#Override
public void dragDropEnd(DragSourceDropEvent dsde) {
// If the drop was not successful, we need to
// return the component back to it's previous
// parent
if (!dsde.getDropSuccess()) {
setContent(dragable);
}
}
}
class MyDropTargetListener extends DropTargetAdapter {
private final DragDropPane target;
public MyDropTargetListener(DragDropPane target) {
this.target = target;
new DropTarget(target, DnDConstants.ACTION_COPY, this, true, null);
}
#Override
public void drop(DropTargetDropEvent event) {
try {
var tr = event.getTransferable();
var component = (JComponent) tr.getTransferData(TransferableComponent.component);
if (event.isDataFlavorSupported(TransferableComponent.component)) {
event.acceptDrop(DnDConstants.ACTION_COPY);
target.setContent(component);
event.dropComplete(true);
} else {
event.rejectDrop();
}
} catch (Exception e) {
e.printStackTrace();
event.rejectDrop();
}
}
}
class TransferableComponent implements Transferable {
protected static final DataFlavor component =
new DataFlavor(JComponent.class, "A Component");
protected static final DataFlavor[] supportedFlavors = {
component
};
private final JComponent componentToTransfer;
public TransferableComponent(JComponent componentToTransfer) {
this.componentToTransfer = componentToTransfer;
}
#Override
public DataFlavor[] getTransferDataFlavors() {
return supportedFlavors;
}
#Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(component);
}
#Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
if (flavor.equals(component)) return componentToTransfer;
else throw new UnsupportedFlavorException(flavor);
}
}
Don't remove/add components. Instead just swap the Icon.
Use a JPanel with a GridLayout that contains a JLabel in each grid
Add an ImageIcon to each JLabel (except for one)
Add a MouseListner to each JLabel.
In the mouseClicked event you get the label that was clicked and remove the ImageIcon and add the Icon to the empty label.
So when you create the board you could have a variable like emptyLabel which would be initialized to the label without the Icon. Then the logic in the mouseClicked might be something like:
JLabel clicked = (JLabel)e.getSource();
emptyLabel.setIcon( clicked.getIcon() );
emptyLabel = clicked;
Create a custom JLabel class to hold the position (i):
class MyImageLabel extends JLabel {
private int position;
public MyImageLabel(Icon image,int position) {
super(image);
this.position=position;
}
public int getPosition()
{
return position;
}
}
Adapt createImage to instantiate this class instead of JLabels and in the mouseListener you can call getPosition():
for(int i = 0; i < jLabels.length; i++) {
MyImageLabel jLabel = new MyImageLabel(new ImageIcon(imageContainer.getBufferedImages().get(i)),i);
jFrame.add(jLabel);
jLabel.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("Clicked!");
imageContainer.move(jLabel.getPosition());
jFrame.removeAll();
createImage();
}
});
}
My advice is not to call .add and .removeAll on the JFrame object but create a new JPanel with the GridLayout and use jframe.getContentPanel().add(labelsPanel). If it doesn't refresh you can then call revalidate() on your JPanel.
Related
I'm completely new to Java and my project is to make a postcard generator with the keyboard.
My problem now is that I don't know how to make the images stay in the Frame when a new Key is pressed. Im sure I need an ArrayList but I don't know where it belongs in the code.
I would appreciate any help :)
public class Funktionier extends Canvas implements KeyListener {
private static final long serialVersionUID = 2576012469492443014L;
public JFrame frame;
private Image []pngs;
private int currentImage;
private Random random;
private int x;
private int y;
public Funktionier(int width, int height)
{
pngs = new Image[26];
for (int i=0; i<26; i++) {
try {
pngs[i] = ImageIO.read(new File("./res/JAVA-"+(char) ('A'+i)+".png"));
} catch (IOException e) {
e.printStackTrace();
}
}
frame = new JFrame ();
JTextField field = new JTextField (30);
field.setBounds(219, 10, 437, 20);
frame.add(field);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Deine Karte");
frame.setResizable(false);
frame.setSize(width, height);
field.addKeyListener(this);
frame.add(this);
this.addKeyListener(this);
this.requestFocus();
frame.setVisible(true);
//currentImage = 0;
random = new Random ();
randomXY ();
}
public static void main (String[] args) {
new Funktionier (874,620);
}
public void randomXY () {
x= random.nextInt(getWidth()-130);
y= random.nextInt(getHeight()-110);
}
public void paint (Graphics g)
{
g.drawImage(pngs[currentImage], x, y, pngs[currentImage].getWidth(null), pngs[currentImage].getHeight(null), null);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyChar() < 'a' || e.getKeyChar() > 'z') return;
currentImage= e.getKeyChar()-'a' ;
randomXY ();
repaint ();
}
}
You should draw on a JPanel and not a Canvas so make class Funktionier extend JPanel and not Canvas.
You should override method paintComponent() and not method paint(). The first thing you need to do in your overridden paintComponent() method is to call super.paintComponent().
Each time paintComponent() is called, you need to draw everything because each time paintComponent() is called, you're starting with a blank JPanel. So don't just draw the "current" image. Also draw all the images you drew up to the current image.
Refer to Painting in AWT and Swing and also Performing Custom Painting
EDIT
Explanations after the code.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;
public class Funktionier extends JPanel implements DocumentListener, Runnable {
private static final long serialVersionUID = 4909941254467865823L;
private static final Image[] PNGS;
private JFrame frame;
private List<ImagLocn> imagesToDraw;
private Random rand;
static {
PNGS = new Image[26];
for (int i = 0; i < 26; i++) {
try {
PNGS[i] = ImageIO.read(new File("JAVA-" + (char) ('A' + i) + ".png"));
}
catch (IOException xIo) {
throw new RuntimeException(xIo);
}
}
}
public Funktionier(int width, int height) {
imagesToDraw = new ArrayList<>();
rand = new Random();
setPreferredSize(new Dimension(width, height));
}
#Override // javax.swing.event.DocumentListener
public void insertUpdate(DocumentEvent docEvent) {
if (docEvent.getLength() > 0) {
Document doc = docEvent.getDocument();
int length = doc.getLength();
try {
String text = doc.getText(0, length);
text = text.strip();
length = text.length();
String lastLetter = text.substring(length - 1, length);
int index = lastLetter.charAt(0) - 'A';
if (index >= 0 && index < PNGS.length) {
imagesToDraw.add(new ImagLocn(PNGS[index],
rand.nextInt(getWidth()),
rand.nextInt(getHeight())));
repaint();
}
}
catch (BadLocationException xBadLocation) {
throw new RuntimeException(xBadLocation);
}
}
}
#Override // javax.swing.event.DocumentListener
public void removeUpdate(DocumentEvent docEvent) {
// Do nothing.
}
#Override // javax.swing.event.DocumentListener
public void changedUpdate(DocumentEvent docEvent) {
// Do nothing.
}
#Override // java.lang.Runnable
public void run() {
showGui();
}
#Override // javax.swing.JComponent
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (ImagLocn il : imagesToDraw) {
g.drawImage(il.getImage(), il.getX(), il.getY(), null);
}
}
private JPanel createTextFieldPanel() {
JPanel textFieldPanel = new JPanel();
JTextField field = new JTextField(30);
Document doc = field.getDocument();
doc.addDocumentListener(this);
if (doc instanceof AbstractDocument) {
AbstractDocument absDoc = (AbstractDocument) doc;
absDoc.setDocumentFilter(new DocuFltr());
}
textFieldPanel.add(field);
return textFieldPanel;
}
private void showGui() {
frame = new JFrame("Deine Karte");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createTextFieldPanel(), BorderLayout.PAGE_START);
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Funktionier(500, 500));
}
}
class DocuFltr extends DocumentFilter {
#Override
public void insertString(FilterBypass fb,
int offset,
String string,
AttributeSet attr) throws BadLocationException {
if (string.matches("^[A-Za-z]+$")) {
fb.insertString(offset, string.toUpperCase(), attr);
}
}
#Override
public void replace(FilterBypass fb,
int offset,
int length,
String text,
AttributeSet attrs) throws BadLocationException {
if (text.matches("^[A-Za-z]+$")) {
fb.replace(offset, length, text.toUpperCase(), attrs);
}
}
}
class ImagLocn {
private Image image;
private int x;
private int y;
public ImagLocn(Image img, int anX, int aY) {
image = img;
x = anX;
y = aY;
}
public Image getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Here is how it looks when I run the above code.
Refer to Laying Out Components Within a Container. Don't use setBounds() to place your components on the screen. Use a layout manager. The default layout manager for the content pane of a JFrame is BorderLayout.
I use a document filter to ensure that only letters of the alphabet can be entered into the JTextField. The document filter also converts lower case letters to upper case.
I implement a document listener rather than a KeyListener. In the document listener, each time another letter is entered into the JTextField, I add another image to the list of images that need to be drawn.
As I wrote in my original answer, I override method paintComponent() and always draw the entire list of images.
I placed all the PNG images in the working directory, i.e. the value returned by System.getProperty("user.dir"). I did this only to make things easier for myself. You can put them anywhere you like. Just make sure you use the correct path to the files in your code.
So basically I'm trying to create a reversi game. First of all I created a board populated by buttons and attached ID's to them, so I can access them afterwards if needed. Now I am trying to draw a game piece on each of the buttons, however I can't getGraphics() of the button since I read that is a bad idea and also returns null. Keep in mind that I want to keep all of my entities separate: the board, the cell and the piece, since I developing this using MVC pattern.
board.java
import java.awt.GridLayout;
import javax.swing.JPanel;
public class Board extends JPanel {
private static final int sizeOfBoard = 8;
public Board() {
int id =0;
setLayout(new GridLayout(sizeOfBoard,sizeOfBoard));
for (int i = 0; i < sizeOfBoard; i++) {
for (int j = 0; j < sizeOfBoard; j++) {
Cell cell = new Cell(id++);
Disk disk = new Disk();
cell.add(disk);
add(cell);
}
}
setSize(600,500);
setVisible(true);
}
cell.java
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.Painter;
public class Cell extends JButton{
private int id;
private boolean taken;
private String colour;
private Painter painter;
public Cell(int id){
this.id = id;
}
public int getId(){
return id;
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
}
}
disk.java
import java.awt.Graphics;
import javax.swing.JComponent;
public class Disk extends JComponent{
#Override
public void paintComponent ( Graphics g ) {
super.paintComponent(g);
g.drawOval(50,50,50,50);
}
}
TL;DR How should I rewrite my code so it would have an oval on each button.
Thanks in advance.
The simplest solution: create your oval or disk images in a BufferedImage, put it into an ImageIcon, and simply swap Icons on your JButton or JLabel via its setIcon(myIcon) method. I'd create 3 ImageIcons if this were my GUI, a blank one for the initial state, and then two different colored ones for the occupied states.
For example:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class ReversiPanel extends JPanel {
private static final int SIDES = 8;
private static final int ICON_LENGTH = 60;
private static final Color BG = Color.BLACK;
private static final Color LABEL_COLOR = Color.GREEN.darker();
private JLabel[][] labelGrid = new JLabel[SIDES][SIDES];
private Icon blankIcon;
private Icon blackIcon;
private Icon whiteIcon;
public ReversiPanel() {
blankIcon = createIcon(new Color(0, 0, 0, 0));
blackIcon = createIcon(Color.BLACK);
whiteIcon = createIcon(Color.WHITE);
setBackground(BG);
setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
setLayout(new GridLayout(SIDES, SIDES, 1, 1));
MyMouse myMouse = new MyMouse();
for (int i = 0; i < labelGrid.length; i++) {
for (int j = 0; j < labelGrid[i].length; j++) {
JLabel label = new JLabel(blankIcon);
label.setOpaque(true);
label.setBackground(LABEL_COLOR);
label.addMouseListener(myMouse);
labelGrid[i][j] = label;
add(label);
}
}
}
private Icon createIcon(Color color) {
BufferedImage img = new BufferedImage(ICON_LENGTH, ICON_LENGTH, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(color);
int gap = 4;
int w = ICON_LENGTH - 2 * gap;
int h = w;
g2.fillOval(gap, gap, w, h);
g2.dispose();
return new ImageIcon(img);
}
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
JLabel label = (JLabel) e.getSource();
Icon icon = label.getIcon();
if (icon == blankIcon) {
label.setIcon(blackIcon);
} else if (icon == blackIcon) {
label.setIcon(whiteIcon);
} else {
label.setIcon(blankIcon);
}
}
}
private static void createAndShowGui() {
ReversiPanel mainPanel = new ReversiPanel();
JFrame frame = new JFrame("ReversiPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
I'm not sure how I would fix the errors in my program and how I would highlight the option the user is hovering on. I want it to highlight the code for each position, i.e position 1 would be highlighted(as a different color) to start game,etc. and up/down would change position and I would change the position with up ,down, left, right. This is what I have so far. At the moment its bugged and when compiled with my window it comes out as:
Which works for the main game and altered for this titleboard, what am I doing wrong and how do I fix it?
TitleBoard class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
//sound + file opening
import java.io.*;
import javax.sound.sampled.*;
public class TitleBoard extends JPanel implements ActionListener{
private ArrayList<String> OptionList;
private Image background;
private ImageIcon bgImageIcon;
private String cheatString;
private int position;
private Timer timer;
public TitleBoard(){
setFocusable(true);
addKeyListener(new TAdapter());
bgImageIcon = new ImageIcon("");
background = bgImageIcon.getImage();
String[] options = {"Start Game","Options","Quit"};
OptionList = new ArrayList<String>();
optionSetup(options);
position = 1;
timer = new Timer(8, this);
timer.start();
/*
1 mod 3 =>1 highlight on start
2 mod 3 =>2 highlight on options
3 mod 3 =>0 highlight on quit
*/
try{
Font numFont = Font.createFont(Font.TRUETYPE_FONT,new File("TwistedStallions.ttf"));
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(numFont);
setFont(numFont.deriveFont(24f)); //adjusthislater
}catch(IOException|FontFormatException e){
e.printStackTrace();
}
}
private void optionSetup(String[] s){
for(int i=0; i<s.length;i++) {
OptionList.add(s[i]);
}
}
public void paint(Graphics g){
super.paint(g);
Graphics g2d = (Graphics2D)g;
g2d.drawImage(background,0,0,this);
for (int i=0;i<OptionList.size();i++){
g2d.drawString(OptionList.get(i),200,120+120*i);
}/*
g2d.drawString(OptionList.get(1),400,240);
g2d.drawString(OptionList.get(2),400,360);
//instructions on start screen maybe??
//800x500
//highlighting*/
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent e){
repaint();
}
public class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_UP||
e.getKeyCode() == KeyEvent.VK_RIGHT){
position++;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN||
e.getKeyCode() == KeyEvent.VK_LEFT){
position--;
}
}
}
}
Window Class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Window extends JFrame{
public Window(){
int width = 800, height = 600;
//TO DO: make a panel in TITLE MODE
///////////////////////////////////
//panel in GAME MODE.
add(new TitleBoard());
//set default close
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width,height);
//centers window
setLocationRelativeTo(null);
setTitle("Title");
setResizable(false);
setVisible(true);
}
public static void main(String[] args){
new Window();
}
}
There are any number of ways you might achieve this, for example, you could use some kind of delegation model.
That is, rather then trying to mange of each element in a single method (or methods), you could devise a delegate which provide a simple interface method that the paint method would call and it would know how to do the rest.
For example, Swing uses this type of concept with it's cell renderers for JList, JTable and JTree.
For example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MyAwesomeMenu {
public static void main(String[] args) {
new MyAwesomeMenu();
}
public MyAwesomeMenu() {
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 List<String> menuItems;
private String selectMenuItem;
private String focusedItem;
private MenuItemPainter painter;
private Map<String, Rectangle> menuBounds;
public TestPane() {
setBackground(Color.BLACK);
painter = new SimpleMenuItemPainter();
menuItems = new ArrayList<>(25);
menuItems.add("Start Game");
menuItems.add("Options");
menuItems.add("Exit");
selectMenuItem = menuItems.get(0);
MouseAdapter ma = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
String newItem = null;
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
if (bounds.contains(e.getPoint())) {
newItem = text;
break;
}
}
if (newItem != null && !newItem.equals(selectMenuItem)) {
selectMenuItem = newItem;
repaint();
}
}
#Override
public void mouseMoved(MouseEvent e) {
focusedItem = null;
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
if (bounds.contains(e.getPoint())) {
focusedItem = text;
repaint();
break;
}
}
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "arrowDown");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "arrowUp");
am.put("arrowDown", new MenuAction(1));
am.put("arrowUp", new MenuAction(-1));
}
#Override
public void invalidate() {
menuBounds = null;
super.invalidate();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (menuBounds == null) {
menuBounds = new HashMap<>(menuItems.size());
int width = 0;
int height = 0;
for (String text : menuItems) {
Dimension dim = painter.getPreferredSize(g2d, text);
width = Math.max(width, dim.width);
height = Math.max(height, dim.height);
}
int x = (getWidth() - (width + 10)) / 2;
int totalHeight = (height + 10) * menuItems.size();
totalHeight += 5 * (menuItems.size() - 1);
int y = (getHeight() - totalHeight) / 2;
for (String text : menuItems) {
menuBounds.put(text, new Rectangle(x, y, width + 10, height + 10));
y += height + 10 + 5;
}
}
for (String text : menuItems) {
Rectangle bounds = menuBounds.get(text);
boolean isSelected = text.equals(selectMenuItem);
boolean isFocused = text.equals(focusedItem);
painter.paint(g2d, text, bounds, isSelected, isFocused);
}
g2d.dispose();
}
public class MenuAction extends AbstractAction {
private final int delta;
public MenuAction(int delta) {
this.delta = delta;
}
#Override
public void actionPerformed(ActionEvent e) {
int index = menuItems.indexOf(selectMenuItem);
if (index < 0) {
selectMenuItem = menuItems.get(0);
}
index += delta;
if (index < 0) {
selectMenuItem = menuItems.get(menuItems.size() - 1);
} else if (index >= menuItems.size()) {
selectMenuItem = menuItems.get(0);
} else {
selectMenuItem = menuItems.get(index);
}
repaint();
}
}
}
public interface MenuItemPainter {
public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused);
public Dimension getPreferredSize(Graphics2D g2d, String text);
}
public class SimpleMenuItemPainter implements MenuItemPainter {
public Dimension getPreferredSize(Graphics2D g2d, String text) {
return g2d.getFontMetrics().getStringBounds(text, g2d).getBounds().getSize();
}
#Override
public void paint(Graphics2D g2d, String text, Rectangle bounds, boolean isSelected, boolean isFocused) {
FontMetrics fm = g2d.getFontMetrics();
if (isSelected) {
paintBackground(g2d, bounds, Color.BLUE, Color.WHITE);
} else if (isFocused) {
paintBackground(g2d, bounds, Color.MAGENTA, Color.BLACK);
} else {
paintBackground(g2d, bounds, Color.DARK_GRAY, Color.LIGHT_GRAY);
}
int x = bounds.x + ((bounds.width - fm.stringWidth(text)) / 2);
int y = bounds.y + ((bounds.height - fm.getHeight()) / 2) + fm.getAscent();
g2d.setColor(isSelected ? Color.WHITE : Color.LIGHT_GRAY);
g2d.drawString(text, x, y);
}
protected void paintBackground(Graphics2D g2d, Rectangle bounds, Color background, Color foreground) {
g2d.setColor(background);
g2d.fill(bounds);
g2d.setColor(foreground);
g2d.draw(bounds);
}
}
}
For here, you could add ActionListener
When a GUI needs a button, use a JButton! The JButton API allows the possibility to add icons for many different circumstances. This example shows different icons for the standard icon, the hover icon, and the pressed icon. Your GUI would obviously use icons with text on them for the required effect.
The icons are pulled directly (hot-linked) from Example images for code and mark-up Q&As.
Standard
Hover over triangle
Press triangle
Code
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.net.URL;
public class IconHoverFocusIndication {
// the GUI as seen by the user (without frame)
// swap the 1 and 0 for single column
JPanel gui = new JPanel(new GridLayout(1,0,50,50));
public static final int GREEN = 0, YELLOW = 1, RED = 2;
String[][] urls = {
{
"http://i.stack.imgur.com/T5uTa.png",
"http://i.stack.imgur.com/IHARa.png",
"http://i.stack.imgur.com/wCF8S.png"
},
{
"http://i.stack.imgur.com/gYxHm.png",
"http://i.stack.imgur.com/8BGfi.png",
"http://i.stack.imgur.com/5v2TX.png"
},
{
"http://i.stack.imgur.com/1lgtq.png",
"http://i.stack.imgur.com/6ZXhi.png",
"http://i.stack.imgur.com/F0JHK.png"
}
};
IconHoverFocusIndication() throws Exception {
// adjust to requirement..
gui.setBorder(new EmptyBorder(15, 30, 15, 30));
gui.setBackground(Color.BLACK);
Insets zeroMargin = new Insets(0,0,0,0);
for (int ii = 0; ii < 3; ii++) {
JButton b = new JButton();
b.setBorderPainted(false);
b.setMargin(zeroMargin);
b.setContentAreaFilled(false);
gui.add(b);
URL url1 = new URL(urls[ii][GREEN]);
BufferedImage bi1 = ImageIO.read(url1);
b.setIcon(new ImageIcon(bi1));
URL url2 = new URL(urls[ii][YELLOW]);
BufferedImage bi2 = ImageIO.read(url2);
b.setRolloverIcon(new ImageIcon(bi2));
URL url3 = new URL(urls[ii][RED]);
BufferedImage bi3 = ImageIO.read(url3);
b.setPressedIcon(new ImageIcon(bi3));
}
}
public JComponent getGUI() {
return gui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
IconHoverFocusIndication ihfi =
new IconHoverFocusIndication();
JFrame f = new JFrame("Button Icons");
f.add(ihfi.getGUI());
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See https://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
this is my first Java GUI program, and really only my second java program, so take it easy on me :) My program is a result of a lot of googling and reading java docs. My problem is that I have a sprite sheet of 52 cards, and am attempting to save these cards individually to a Buffered Image array using subImage, and just for testing purposes, display all 52 in a window. The File is in the correct directory I made sure of that. I believe that my problem lies with my use of Jlabels, or simply a foolish mistake. Anyways, here is my class that does the sprite sheet splitting
package gui;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class crdimgs extends JPanel {/**
*
*/
static final long serialVersionUID = 1L;
public final int width = 10;
public final int height = 20;
public int rows = 13;
public int cols = 5;
public BufferedImage image;
File cardimg = new File("Cards.jpg");
BufferedImage cards[];
public void loadsplit(File loadimage){
try{
image = ImageIO.read(loadimage);
} catch(Exception error){
System.out.print("error");
}
cards = new BufferedImage[cols*rows];
}
public crdimgs() {
loadsplit(cardimg);
setLayout(new GridLayout(rows, cols, 1, 1));
int x = 0;
int y = 0;
int subimg = 0;
for( int i = 0; i < rows; i++)
{
JPanel panel = new JPanel();
cards[subimg] = new BufferedImage(width, height, 5);
cards[subimg] = image.getSubimage(x, y, width, height);
panel.add(new JLabel(new ImageIcon(cards[subimg])));
add(panel);
x+=width;
subimg++;
}
y+=height;
x=0;
}
}
}
And my Main class
package gui;
import javax.swing.JFrame;
import java.awt.Color;
public class cards extends JFrame {
private static final long serialVersionUID = 1L;
public cards(){
setTitle("Poker");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(1000, 700);
setLocationRelativeTo(null);
this.getContentPane().setBackground(Color.GREEN);
setVisible(true);
setResizable(false);
add(new crdimgs());
}
public static void main(String[] args){
new cards();
}
}
Errors I receive at the moment are:
errorException in thread "main" java.lang.NullPointerException
at gui.crdimgs.<init>(crdimgs.java:53)
at gui.cards.<init>(cards.java:22)
at gui.cards.main(cards.java:28)
Likely your image is null, possibly because you're looking in the wrong place for it, but to find out, check out which line is 53.
Suggestions:
Start small and then build on. Don't try to do complex image manipulation until you first successfully read and show a single image.
Check where Java is looking for the image, because likely it isn't where you think it is. Put System.out.println(System.getProperty("user.dir")); in your code to find out.
Call setVisible(true) after adding all components to the JFrame.
Improve your exception display code by printing the stack trace: error.printStackTrace() (thanks Mad!).
For example:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
public class PlayingCardTest {
public static void main(String[] args) {
String pathToDeck = "http://www.jfitz.com/cards/classic-playing-cards.png";
try {
final List<ImageIcon> cardImgList = CreateCards.createCardIconList(pathToDeck);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Moving Cards");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CardGameTable(cardImgList, frame));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
} catch (MalformedURLException e) {
e.printStackTrace();
System.exit(-1);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
#SuppressWarnings("serial")
class CardGameTable extends JLayeredPane {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private static final Color BASE_COLOR = new Color(0, 80, 0);
private static final int CARD_COUNT = 20;
private static final int WIDTH_SHOWING = 20;
private JPanel basePane = new JPanel(null);
public CardGameTable(List<ImageIcon> cardImgList, final JFrame frame) {
basePane.setSize(getPreferredSize());
basePane.setBackground(BASE_COLOR);
add(basePane, JLayeredPane.DEFAULT_LAYER);
final MyMouseAdapter myMouseAdapter = new MyMouseAdapter(this, basePane);
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
for (int i = 0; i < CARD_COUNT; i++) {
JLabel card = new JLabel(cardImgList.remove(0));
card.setSize(card.getPreferredSize());
int x = (PREF_W / 2) + WIDTH_SHOWING * (CARD_COUNT - 2 * i) / 2 -
card.getPreferredSize().width / 2;
int y = PREF_H - card.getPreferredSize().height - WIDTH_SHOWING * 2;
card.setLocation(x, y);
basePane.add(card);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
class MyMouseAdapter extends MouseAdapter {
private JLabel selectedCard = null;
private JLayeredPane cardGameTable = null;
private JPanel basePane = null;
private int deltaX = 0;
private int deltaY = 0;
public MyMouseAdapter(JLayeredPane gameTable, JPanel basePane) {
this.cardGameTable = gameTable;
this.basePane = basePane;
}
#Override
public void mousePressed(MouseEvent mEvt) {
Component comp = basePane.getComponentAt(mEvt.getPoint());
if (comp != null && comp instanceof JLabel) {
selectedCard = (JLabel) comp;
basePane.remove(selectedCard);
basePane.revalidate();
basePane.repaint();
cardGameTable.add(selectedCard, JLayeredPane.DRAG_LAYER);
cardGameTable.revalidate();
cardGameTable.repaint();
deltaX = mEvt.getX() - selectedCard.getX();
deltaY = mEvt.getY() - selectedCard.getY();
}
}
#Override
public void mouseReleased(MouseEvent mEvt) {
if (selectedCard != null) {
cardGameTable.remove(selectedCard);
cardGameTable.revalidate();
cardGameTable.repaint();
basePane.add(selectedCard, 0);
basePane.revalidate();
basePane.repaint();
selectedCard = null;
}
}
#Override
public void mouseDragged(MouseEvent mEvt) {
if (selectedCard != null) {
int x = mEvt.getX() - deltaX;
int y = mEvt.getY() - deltaY;
selectedCard.setLocation(x, y);
cardGameTable.revalidate();
cardGameTable.repaint();
}
}
}
class CreateCards {
private static final int SUIT_COUNT = 4;
private static final int RANK_COUNT = 13;
public static List<ImageIcon> createCardIconList(String pathToDeck)
throws MalformedURLException, IOException {
BufferedImage fullDeckImg = ImageIO.read(new URL(pathToDeck));
int width = fullDeckImg.getWidth();
int height = fullDeckImg.getHeight();
List<ImageIcon> iconList = new ArrayList<ImageIcon>();
for (int suit = 0; suit < SUIT_COUNT; suit++) {
for (int rank = 0; rank < RANK_COUNT; rank++) {
int x = (rank * width) / RANK_COUNT;
int y = (suit * height) / SUIT_COUNT;
int w = width / RANK_COUNT;
int h = height / SUIT_COUNT;
BufferedImage cardImg = fullDeckImg.getSubimage(x, y, w, h);
iconList.add(new ImageIcon(cardImg));
}
}
Collections.shuffle(iconList);
return iconList;
}
}
Which shows:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Cards extends JFrame {
private GridLayout grid1;
JButton []bt=new JButton[52];
ImageIcon tail=new ImageIcon(getClass().getResource("b1fv.png"));
ImageIcon ori;
public Cards(){
grid1=new GridLayout(7,9,2,2);
setLayout(grid1);
for(int i=0;i<bt.length;i++){
ImageIcon c=new ImageIcon(getClass().getResource(i+1+".png"));
bt[i]=new JButton(c);
bt[i].addActionListener(new RatingMouseListener(i));
add( bt[i]);
}
}
public static void main(String[] args){
Cards frame=new Cards();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1400,700);
frame.setVisible(true);
}
private class RatingMouseListener implements ActionListener {
private int index=0;
public RatingMouseListener(int index) {
this.index = index;
}
public void actionPerformed(ActionEvent e) {
System.out.println("Mouse entered for rating " + index);
ori=new ImageIcon(getClass().getResource(index+1+".png"));
if (bt[index].getIcon()==ori)
bt[index].setIcon(tail);
else
bt[index].setIcon(ori);
}
}
}
When I run this, I expect that the ori and the tail should exchange. But they don't. Can someone help me?
This would be best done via a description tag.
Basically, set the description to the images like below, then swap them if they have the same description.
ori.setDescription("ori");
tail.setDescription("tail");
if ("ori".equals((ImageIcon)bt[index].getIcon()).getDescription())
// The rest is how you had it.
I'm guessing that you want to have playing cards that flip when clicked (but I'm not sure). Again, I recommend that you create your ImageIcons once and at the start of the program. Then you can easily compare if one icon is the same as another by using the equal(...) method or even in this situation the == operator. For example, please have a look at and run this code for an example of what I mean:
import java.awt.GridLayout;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
public class CardsDeck {
public static final String RANKS = "a23456789tjqk";
public static final String SUITS = "cdhs";
public static final String CARDS_IMG_PATH = "http://math.hws.edu/javanotes/source/cards.png";
private static final int BACK_RANK = 2;
private static final int BACK_SUIT = SUITS.length();
private static final String ICON = "icon";
private JPanel panel = new JPanel();
private List<ImageIcon> iconList = new ArrayList<ImageIcon>();
private ImageIcon cardBack;
public CardsDeck() {
try {
URL imgUrl = new URL(CARDS_IMG_PATH);
BufferedImage img = ImageIO.read(imgUrl);
double cardWidth = (double) img.getWidth() / RANKS.length();
double cardHeight = (double) img.getHeight() / (SUITS.length() + 1);
int w = (int) cardWidth;
int h = (int) cardHeight;
for (int rank = 0; rank < RANKS.length(); rank++) {
for (int suit = 0; suit < SUITS.length(); suit++) {
int x = (int) (rank * cardWidth);
int y = (int) (suit * cardHeight);
BufferedImage subImg = img.getSubimage(x, y, w, h);
ImageIcon icon = new ImageIcon(subImg);
iconList.add(icon);
}
}
int x = (int) (BACK_RANK * cardWidth);
int y = (int) (BACK_SUIT * cardHeight);
BufferedImage subImg = img.getSubimage(x, y, w, h);
cardBack = new ImageIcon(subImg);
int hgap = 5;
int vgap = hgap;
panel.setLayout(new GridLayout(SUITS.length(), RANKS.length(), hgap, vgap));
panel.setBorder(BorderFactory.createEmptyBorder(vgap, hgap, vgap, hgap));
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
JLabel label = (JLabel) e.getSource();
Icon currentIcon = label.getIcon();
if (currentIcon.equals(cardBack)) {
Icon icon = (Icon) label.getClientProperty(ICON);
label.setIcon(icon);
} else {
label.setIcon(cardBack);
}
}
};
Collections.shuffle(iconList);
for (int i = 0; i < iconList.size(); i++) {
JLabel label = new JLabel(cardBack);
label.putClientProperty(ICON, iconList.get(i));
label.addMouseListener(mouseListener);
panel.add(label);
}
} catch (MalformedURLException e) {
e.printStackTrace();
System.exit(-1);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
private JComponent getPanel() {
return panel;
}
private static void createAndShowGui() {
CardsDeck cardsDeck = new CardsDeck();
JFrame frame = new JFrame("CardsDeck");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(cardsDeck.getPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
If run, it will show a 13 x 4 array of cards that can be flipped by clicking on them: