Java swing/awt component to draw chessboard [closed] - java

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I don't have much experienc with swing/awt.
My problem is:
I need to draw something like chessboard (NxN).
In general I need to get access to every cell to make changes (when program is running e.g. I click button and something is happen with cells on that board).
It will be greate if a Component let me to set in cell a Image.
I try to use GridLayout but I get nothing what satisfy me.
Do you have any idea how to simply resolve that problem?

I made a Chess game myself in Java back sometime and found the code I used.
So here is something to start you off:
ChessBoardTest:
public class ChessBoardTest {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try {
Image blackBlock=ImageIO.read(new File("c:/bblock.jpg"));
Image whiteBlock=ImageIO.read(new File("c:/wblock.jpg"));
Board board = new Board(whiteBlock,blackBlock);
//add pieces to board
board.addPiece(new ImageIcon("c:/castle.jpg"), "A1");//just one example
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Board.java:
import java.awt.*;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/*
* #author David Kroukamp
*/
public class Board extends JFrame {
//intialize variables
private Image boardImage1;
private Image boardImage2;
//intialize components
private JPanel centerPanel = new JPanel();
private JPanel southPanel = new JPanel();
private JPanel westPanel = new JPanel();
//initialze arrays to hold panels and images of the board
private JLabel[] labels = new JLabel[64];
private ImagePanel[] panels = new ImagePanel[64];
public Board(Image boardImage1, Image boardImage2) {
this.boardImage1 = boardImage1;
this.boardImage2 = boardImage2;
createAndShowGUI();//call method to create gui
}
private void createAndShowGUI() {
setTitle("Chess board example");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
addComponentsToPane(getContentPane());
setSize(800, 600);
setLocationRelativeTo(null);
setVisible(true);
}
/**
* Adds all the necessary components to the content pane of the JFrame, and
* adds appropriate listeners to components.
*/
private void addComponentsToPane(Container contentPane) {
GridLayout gridLayout = new GridLayout(8, 8);
centerPanel.setLayout(gridLayout);
//call mehod to add labels to south panel
addLabelsToSouthPanel();
//call method to add oanels to west panel
addLabelsToWestPanel();
//call method to add panels and labels to the center panel which holds the board
addPanelsAndLabels();
//add all panels to frame
contentPane.add(centerPanel, BorderLayout.CENTER);
contentPane.add(southPanel, BorderLayout.SOUTH);
contentPane.add(westPanel, BorderLayout.WEST);
}
private void addLabelsToSouthPanel() {
GridLayout gridLayout = new GridLayout(0, 8);
southPanel.setLayout(gridLayout);
JLabel[] lbls = new JLabel[8];
String[] label = {"A", "B", "C", "D", "E", "F", "G", "H"};
for (int i = 0; i < 8; i++) {
lbls[i] = new JLabel(label[i] + "");
southPanel.add(lbls[i]);
}
}
private void addLabelsToWestPanel() {
GridLayout gridLayout = new GridLayout(8, 0);
westPanel.setLayout(gridLayout);
JLabel[] lbls = new JLabel[8];
int[] num = {8, 7, 6, 5, 4, 3, 2, 1};
for (int i = 0; i < 8; i++) {
lbls[i] = new JLabel(num[i] + "");
westPanel.add(lbls[i]);
}
}
private void addPanelsAndLabels() {
//call methd to create panels with backgound images and appropriate names
addPanelsAndImages();
for (int i = 0; i < panels.length; i++) {
labels[i] = new JLabel();
//used to know the postion of the label on the board
labels[i].setName(panels[i].getName());
panels[i].add(labels[i]);
//adds panels created in addPanelsAndImages()
centerPanel.add(panels[i]);
}
}
//this method will create panels with backround images of chess board and set its name according to 1-8 for rows and A-H for coloumns
private void addPanelsAndImages() {
int count = 0;
String[] label = {"A", "B", "C", "D", "E", "F", "G", "H"};
int[] num = {8, 7, 6, 5, 4, 3, 2, 1};
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
if ((col + row) % 2 == 0) {//even numbers get white pieces
panels[count] = new ImagePanel(boardImage1);
} else {//odd numbers get black pieces
panels[count] = new ImagePanel(boardImage2);
}
panels[count].setName(label[col] + num[row]);
count++;
}
}
}
//method sets image of a label at a certain position in the board according to the block name i.e D4
public void addPiece(ImageIcon img, String block) {
for (int s = 0; s < labels.length; s++) {
if (labels[s].getName().equalsIgnoreCase(block)) {
labels[s].setIcon(img);
}
}
}
//nested class used to set the background of frame contenPane
class ImagePanel extends JPanel {
private Image image;
/**
* Default constructor used to set the image for the background for the
* instance
*/
public ImagePanel(Image img) {
image = img;
}
#Override
protected void paintComponent(Graphics g) {
//draws image to background to scale of frame
g.drawImage(image, 0, 0, null);
}
}
}
HTH to get you started.

There is actually quite a reasonable example online on roseindia.

Related

What is wrong with the .add in my GUI program?

I am trying to make a GUI with a Grid layout that presents 3 random non repeatable cards within a file. I named all the cards 1-53.png and am trying to insert it into the panels of left, center, and right. When I try adding the files into my panels, there is an error withe the .add, and I do not know how to fix it.
I have already tried to change the .add and the index. I even tried to turn the int into a component, but nothing works.
public class Question_2 {
static String location = "cards/";
public static void main(String[] args) {
JFrame frmMyWindow = new frmMyWindow("Random Cards");
frmMyWindow.setSize(300, 200);
frmMyWindow.setLocationRelativeTo(null);
frmMyWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmMyWindow.setVisible(true);
}
}
class frmMyWindow extends JFrame {
JLabel lblName, l;
JPanel panelMain, panelLeft, panelCenter, panelRight;
JFrame f;
public frmMyWindow(String Cards) {
super("Random Cards");
lblName = new JLabel("Cards");
panelMain = new JPanel(new GridLayout(1, 3, 10, 10));
setLayout(new BorderLayout(20, 10));
add(lblName, BorderLayout.NORTH);
add(panelMain, BorderLayout.CENTER);
panelLeft = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 10));
panelCenter = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));
panelRight = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 10));
panelMain.add(panelLeft);
panelMain.add(panelCenter);
panelMain.add(panelRight);
panelLeft.setBorder(new TitledBorder("Card 1"));
panelCenter.setBorder(new TitledBorder("Card 2"));
panelRight.setBorder(new TitledBorder("Card 3"));
int index = (int) Math.round(Math.random() * 53);
int index2 = (int) Math.round(Math.random() * 53);
int index3 = (int) Math.round(Math.random() * 53);
while (index == index2) {
index2 = (int) Math.round(Math.random() * 53);
}
while (index3 == index2 || index3 == index)
;
{
index3 = (int) Math.round(Math.random() * 53);
}
String image = index + ".png";
String image2 = index2 + ".png";
String image3 = index3 + ".png";
panelLeft.add(index);
panelCenter.add(index2);
panelRight.add(index3);
}
}
I want the program to present 3 random cards into the panels, but there is an error with the .add.
The problem is indeed to the add method and how you call it. Container#add method takes as arguments Components. You call it with int arguments.
I even tried to turn the int into a component, but nothing works.
The simplest way (I guess) to "add a number in a container" is to create a JLabel and add to it the number as text. By seeing your first attempt, I guess that you again messed up the methods. Probably in JLabels constructor. You did something like new JLabel(index) where index is an Integer. Which again fails because there is no constructor with int argument. The solution is to create a JLabel AND convert the integer to text:
panelLeft.add(new JLabel(String.valueOf(index)));
After that program can be compiled and run. However some notes are:
Always run your application using SwingUtilities#invokeLater since all Swing applications must run on their own thread.
public static void main(String[] args) {
SwingUtilities.invokeLater(()->{
JFrame frmMyWindow = new frmMyWindow("Random Cards");
frmMyWindow.setSize(300, 200);
frmMyWindow.setLocationRelativeTo(null);
frmMyWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmMyWindow.setVisible(true);
});
}
All class names "should" (well, its the standard convention) start with an Uppercase letter. Rename frmMyWindow to FrmMyWindow.

Adding a JScrollPane to an overriden JPanel

I am trying to create a program that computes for the Round Robin algorithm. The logic works fine. My problem is with the overriden JPanel that I use to draw the timeline. The timeline goes on and on without definite line length. I want to add the overriden panel to a scroll pane so it can be scrollable.
SampleGPane.class
import java.awt.*;
import javax.swing.*;
public class
SampleGPane
{
/* Timeline elements */
Container timelineContainer;
JFrame timelineFrame = new JFrame ();
JPanel pnlDraw = new JPanel ();
JScrollPane timelineScroll;
public void
launchFrame ()
{
GPanel gpane = new GPanel ();
timelineContainer = timelineFrame.getContentPane ();
timelineScroll = new JScrollPane (gpane);
timelineContainer.add (timelineScroll);
timelineFrame.setSize (500, 250);
timelineFrame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
timelineFrame.setVisible (true);
}
private class
GPanel extends JPanel
{
#Override
public void
paintComponent (Graphics g)
{
super.paintComponent (g);
int runningLineX = 0;
int runningLineY = 0;
// g.drawLine (50, 50, orderCount * 5, 50);
runningLineX += 50;
runningLineY += 50;
for (int count = 0; count < 35; count++) {
g.drawString ("J" + (count + 1), runningLineX + 50, 25);
runningLineX += 50;
// runningLineY += 50;
g.drawLine (runningLineX, runningLineY, runningLineX + 50, runningLineY);
}
}
}
}
SampleGPane.class is called by SampleLaunch.class
public class
SampleLaunch
{
public static void main (String args[]) {
SampleGPane sgp = new SampleGPane ();
sgp.launchFrame ();
}
}
The problem is, the JScrollPane won't work. It doesn't seem to detect the line. How do I fix this?
You need to override the getPreferredSize() method of your custom panel to return a reasonable size.
The scrollbars will only appear when the preferred size of the component added to the viewport of the scroll pane is greater than the size of the scroll pane.
The timeline goes on and on without definite line length.
The line length will need to match your painting code. So you need parameters to control what to paint. These parameters will also be used in the calculation of the size of the component. In your example you iterate 35 times and increment the x by 50 so the width would be 1750 plus the starting x offset.

JFrame not centering properly

Here is my code:
import java.awt.Component;
import java.awt.Container;
import javax.swing.*;
public class GUIBuilder {
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
String[] labels = { "Name: ", "Fax: ", "Email: ", "Address: " };
int numPairs = labels.length;
JPanel p = new JPanel();
BoxLayout b = new BoxLayout(p, BoxLayout.Y_AXIS);
p.setLayout(b);
// Create and populate the panel.
JPanel p2 = new JPanel(new SpringLayout());
for (int i = 0; i < numPairs; i++) {
JLabel l = new JLabel(labels[i], JLabel.TRAILING);
p2.add(l);
JTextField textField = new JTextField(10);
l.setLabelFor(textField);
p2.add(textField);
}
p.add(p2);
// Lay out the panel.
makeCompactGrid(p2, numPairs, 2, // rows, cols
6, 6, // initX, initY
6, 6); // xPad, yPad
// Create and set up the window.
JFrame frame = new JFrame("SpringForm");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set up the content pane.
p.setOpaque(true); // content panes must be opaque
frame.setContentPane(p);
JButton enter = new JButton("Enter");
p.add(enter);
// Display the window.
frame.pack();
frame.setVisible(true);
}
/* Used by makeCompactGrid. */
private static SpringLayout.Constraints getConstraintsForCell(
int row, int col,
Container parent,
int cols) {
SpringLayout layout = (SpringLayout) parent.getLayout();
Component c = parent.getComponent(row * cols + col);
return layout.getConstraints(c);
}
/**
* Aligns the first <code>rows</code> * <code>cols</code>
* components of <code>parent</code> in
* a grid. Each component in a column is as wide as the maximum
* preferred width of the components in that column;
* height is similarly determined for each row.
* The parent is made just big enough to fit them all.
*
* #param rows number of rows
* #param cols number of columns
* #param initialX x location to start the grid at
* #param initialY y location to start the grid at
* #param xPad x padding between cells
* #param yPad y padding between cells
*/
public static void makeCompactGrid(Container parent,
int rows, int cols,
int initialX, int initialY,
int xPad, int yPad) {
SpringLayout layout;
try {
layout = (SpringLayout)parent.getLayout();
} catch (ClassCastException exc) {
System.err.println("The first argument to makeCompactGrid must use SpringLayout.");
return;
}
//Align all cells in each column and make them the same width.
Spring x = Spring.constant(initialX);
for (int c = 0; c < cols; c++) {
Spring width = Spring.constant(0);
for (int r = 0; r < rows; r++) {
width = Spring.max(width,
getConstraintsForCell(r, c, parent, cols).
getWidth());
}
for (int r = 0; r < rows; r++) {
SpringLayout.Constraints constraints =
getConstraintsForCell(r, c, parent, cols);
constraints.setX(x);
constraints.setWidth(width);
}
x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad)));
}
//Align all cells in each row and make them the same height.
Spring y = Spring.constant(initialY);
for (int r = 0; r < rows; r++) {
Spring height = Spring.constant(0);
for (int c = 0; c < cols; c++) {
height = Spring.max(height,
getConstraintsForCell(r, c, parent, cols).
getHeight());
}
for (int c = 0; c < cols; c++) {
SpringLayout.Constraints constraints =
getConstraintsForCell(r, c, parent, cols);
constraints.setY(y);
constraints.setHeight(height);
}
y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad)));
}
//Set the parent's size.
SpringLayout.Constraints pCons = layout.getConstraints(parent);
pCons.setConstraint(SpringLayout.SOUTH, y);
pCons.setConstraint(SpringLayout.EAST, x);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
For some reason, my JFrame frame isn't centering properly. Could anyone know what could be wrong here? This is my first time using SpringLayout, so I wonder if it could have anything to do with this. I used part of Oracle's examples on their website, so I would like to know how could I get my frame properly centered.
It's nothing to do with SpringLayout. The JFrame is being packed after the window has been centered which changes its size. Simply reverse the order of these 2 calls
frame.setLocationRelativeTo(null);
frame.pack()

Unable to remove JLabel from JPanel

I have a chessboard with 64 JPanels representing each square on the board. The pieces are represented using JLabels which are placed on the JPanels. I am trying to remove all the JLabels off the board. I am confused why this doesn't work:
private void removePieces()
{
for(int i = 0; i < 64; i ++)
{
Component c = chessBoard.getComponent(i);
if(c instanceof JLabel)
{
Container parent = c.getParent();
parent.remove((JLabel)c);
parent.revalidate();
parent.repaint();
}
}
}
chessboard is the big JPanel with the 64 JPanels inside it. After some debugging it looks like the if loop is never being entered. I don't understand why it wouldn't enter the if loop if one of the components is a JLabel?
Looks like your trying to remove your JPanels from your chessboard if they are JLabels (which obviously makes no sense, and is why the if code is never firing). Instead you want to remove the chessBoard's components' JLabel component. Example below.
private void removePieces() {
for(int i = 0; i < 64; i ++) {
if(chessBoard.getComponent(i) instanceof JPanel) {
JPanel c = (JPanel)chessBoard.getComponent(i);
c.removeAll();
c.revalidate();
c.repaint();
}
}
}
I am using removeAll() because I am presuming your JPanels have no other components in them other than the potential JLabels.
Why remove the labels, rather than simply set the icon to null or text to ""?
E.G. using text for the pieces.
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.*;
import javax.swing.border.LineBorder;
class ChessBoard2 {
static ChessMoveMouseListener cmml = new ChessMoveMouseListener();
/** Unicode strings for chess pieces & empty string for blank squares. */
static String[][] pieces = {
{"\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659"},
{"\u265A", "\u265B", "\u265C", "\u265D", "\u265E", "\u265F"},
{""}
};
static int[] order = new int[]{2, 4, 3, 0, 1, 3, 4, 2};
static int[] pawns = new int[]{5, 5, 5, 5, 5, 5, 5, 5};
static int[] blank = new int[]{0, 0, 0, 0, 0, 0, 0, 0};
static int white = 0;
static int black = 1;
static int space = 2;
public static JLabel getColoredLabel(String string, int color) {
JLabel l = new JLabel(string);
l.setFont(l.getFont().deriveFont(50f));
Color c = (color % 2 == 0 ? Color.WHITE : Color.LIGHT_GRAY);
l.setBackground(c);
l.setOpaque(true);
l.addMouseListener(cmml);
return l;
}
public static void addRowToContainer(
Container c,
int[] order,
int row,
int count) {
for (int ii : order) {
c.add(getColoredLabel(pieces[row][ii], count++));
}
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JPanel chessboard = new JPanel(new GridLayout(0, 8, 1, 1));
chessboard.setBackground(Color.BLACK);
chessboard.setBorder(new LineBorder(Color.BLACK));
int count = 0;
// black pieces..
addRowToContainer(chessboard, order, black, count);
addRowToContainer(chessboard, pawns, black, ++count);
// middle squares..
addRowToContainer(chessboard, blank, space, ++count);
addRowToContainer(chessboard, blank, space, ++count);
addRowToContainer(chessboard, blank, space, ++count);
addRowToContainer(chessboard, blank, space, ++count);
// white pieces..
addRowToContainer(chessboard, pawns, white, ++count);
addRowToContainer(chessboard, order, white, ++count);
JOptionPane.showMessageDialog(null, chessboard,
"Click two squares to move from/to",
JOptionPane.INFORMATION_MESSAGE);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
class ChessMoveMouseListener extends MouseAdapter {
String s = null;
#Override
public void mouseClicked(MouseEvent e) {
JLabel l = (JLabel) e.getSource();
if (s == null) {
if (l.getText().trim().length() > 0) {
s = l.getText();
l.setText("");
}
} else {
l.setText(s);
s = null;
}
}
}
Think, when you're doing:
Component c = chessBoard.getComponent(i);
you're getting one of the JPanels, that contains your JLabels. And of course they are not instances of JLabel.
So you need to get JLabel from that JPanel and then remove it.

Points not being properly read by MouseListener

I'm having a problem where I can't properly access my instance Point data.
I create an multi-dimensional array of GridPanels, and instantiate each with a Point.
When first created, everything works as expected.
pic1 http://img.skitch.com/20100218-fciwr7t73ci2gajafmfxa2yf9q.jpg
When I click on a GridPanel however, the Listener class always receives the Point from the last GridPanel that was created ( (3, 3) in this case.)
When I pass an int instead of a Point however, the int for the GridPanel that was clicked is shown (like you'd expect).
Anyone know what's going on here?
Thanks
import javax.swing.JFrame;
/**
* Driver class.
*/
public class Test {
/**
* The main method.
* #param args Command line arguments.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("TEST");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TestPanel panel = new TestPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
import java.awt.GridLayout;
import java.awt.Point;
import javax.swing.JPanel;
/**
* Creates a 4 by 4 grid of GridPanels.
*/
public class TestPanel extends JPanel {
static final int ROW_SIZE = 4;
static final int COL_SIZE = 4;
private GridPanel[][] g = new GridPanel[ROW_SIZE][COL_SIZE];
public TestPanel() {
Point coords = new Point();
setLayout(new GridLayout(ROW_SIZE, COL_SIZE));
for (int i = 0; i < ROW_SIZE; i++) {
for (int j = 0; j < COL_SIZE; j++) {
coords.setLocation(i, j);
g[i][j] = new GridPanel(coords);
add(g[i][j]);
}
}
}
}
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* Contains the MouseListener.
*/
public class GridPanel extends JPanel {
private JLabel label;
private Point p;
public GridPanel(Point p) {
this.p = p;
label = new JLabel("" + p);
add(label);
setBackground(Color.WHITE);
setPreferredSize(new Dimension(200, 50));
addMouseListener(new SelectListener());
}
private class SelectListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
label.setText("" + p);
}
}
}
The problem is that you are re-using the same point, stored in coords. You need to create a new point for each grid element. It looks to you as if each panel has a different point value stored in it because each panel has a different label. But in the line
label = new JLabel("" + p);
you are creating a String that contains the current value of p. But p can change later, and the label won't change with it.
So the easiest fix for your problem is to change the line
this.p = p;
to
this.p = new Point(p); // Create a defensive copy.
It looks like you may be currently somewhat confused about the difference between objects and fields. For example,
Point p = new Point(3, 4);
Point p2 = p;
p.x = 7;
System.out.println(p2.x);
will yield 7, as there is only one point being manipulated, though it's pointed to by two fields. Using = doesn't create a copy of the point.
(Apologies if I'm explaining things you already know!)
The point is and object so it is passed by reference. This means all your panels reference the same Point. Since you are changing the location on it all the time - the last will be shown.
You have to create new Point every time in the loop:
public TestPanel() {
setLayout(new GridLayout(ROW_SIZE, COL_SIZE));
for (int i = 0; i < ROW_SIZE; i++) {
for (int j = 0; j < COL_SIZE; j++) {
g[i][j] = new GridPanel(new Point(i, j));
add(g[i][j]);
}
}
}
i change setPreferredSize(new Dimension(w, h)); this is done.
but in my program i need change my frame size every time. so how can fit gridpanel in that case.... if frame size (1200,800) or (1170,920) i am not using JLabel here.
thankyou for answering
in place of this frame.pack(); i use frame.setSize(W,H);
in a gridpanel add
setPreferredSize(new Dimension(x,y));
setBorder(BorderFactory.createLineBorder(Color.red));
i remove JLabel
where x = w / col_size; y = h / row_size;
now when i run Test.java grid are not fitted in my frame;

Categories

Resources