Note: this question may look a bit like another I've posted a few weeks ago. Back then I was not working with adding the buttons as arrays, thats what makes it more difficult for me this time.
I'm working with a chessgame, and I have been able to set up a board of 64 squares on my own. However it seems to be a little too complicated for me to manage adding the colors to the squares.
My code looks like this:
Chess.java
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Chess implements config {
public static void main(String[] args) {
int[] squareArray;
squareArray = new int[65];
int i = 1;
JFrame frame = new JFrame("Chessboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(ROWS, COLS, 2, 2));
for (i = 1; i < 65; i++) {
squareArray[i] = i;
frame.add(new JButton("" + squareArray[i]));
}
frame.setSize(800, 800);
frame.setVisible(true);
}
}
Piece.java
import java.awt.Color;
import javax.swing.JFrame;
public class Piece extends JFrame implements config {
public Piece (int n) {
setBackground(calcColor(n));
}
public void Pieces() {
new Pieces();
//This class contains nothing at the moment.
}
Color calcColor(int n) {
boolean everysecondSquare = (n % 2 == 0);
boolean everysecondRow = ((n / ROWS) % 2 == 0);
return (everysecondSquare != everysecondRow ? P1Color : P2Color);
}
}
config.java
import java.awt.Color;
public interface config {
public int ROWS = 8;
public int COLS = 8;
Color P1Color = (new Color(245,222,179));
Color P2Color = (new Color(244,164,96));
}
I'm very aware that this probably is pretty bad coded as I am very new to Java. I would be very happy and thankful if someone could help me out with the colors here as I have been stuck for several days now without getting any further. I don't expect someone to finish the code for me, but merely help me on the way to get there. :)
What about this?
for (i = 1; i < 65; i++) {
squareArray[i] = i;
JButton b=new JButton("" + squareArray[i]);
b.setBackground(desiredColorHere);
frame.add(b);
}
Related
I am attempting to overlay the text on a JButton over an ImageIcon that is behind it. However, when the imageIcon is added, the text dissapears. Is there any way to specify the order in which it displays?
Below, i have tried to separately add the images and text to see if that would affect it, but no luck.
Can anyone help me out?
private void initButtons() {
int locationX = 0, locationY = 525;
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
boardArray[x][y] = new ChessButton();
boardArray[x][y].setSize(75, 75);
boardArray[x][y].setLocation(locationX, locationY);
boardArray[x][y].setXAndY(x, y);
if ((x % 2 == 0 && y % 2 == 1) || (x % 2 == 1 && y % 2 == 0)) {
boardArray[x][y].setColour("white");
boardArray[x][y].setIcon(new ImageIcon("Assets/white_null_null.png"));
} else {
boardArray[x][y].setColour("black");
boardArray[x][y].setIcon(new ImageIcon("Assets/black_null_null.png"));
}
//this adds the images in an alternating pattern
chessFrame.add(boardArray[x][y]);
locationX = locationX + 75;
}
locationX = 0;
locationY = locationY - 75;
}
}
void initPieces() {
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
if ((x % 2 == 0 && y % 2 == 1) || (x % 2 == 1 && y % 2 == 0)) {
boardArray[x][y].setFont(new Font("Arial Unicode MS", Font.PLAIN, 40));
boardArray[x][y].setText("\u2654");//sets a particular chess piece as text, just testing it now.
} else {
boardArray[x][y].setFont(new Font("Arial Unicode MS", Font.PLAIN, 40));
boardArray[x][y].setText("\u2654");//sets a particular chess piece as text, just testing it now.
//this is suposed to overlay the image over the text, but it is not.
}
}
}
}
First of all, I see you're calling this method: boardArray[x][y].setLocation(locationX, locationY);
.setLocation(...) indicates you're using a null layout, please read Null layout is evil and Why is it frowned upon to use a null layout in Swing? to know why you should avoid its use.
For creating a Chess board, I'd be using GridLayout, please read how to use the different layout managers
Now, to overlay text over the icon, you only need to call JButton#setHorizontalAlignment(...) method and pass SwingConstants.CENTER as the parameter.
For example:
import java.awt.Color;
import java.awt.Font;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class ButtonWithImageAndText {
private JFrame frame;
private JButton button;
private Icon icon;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new ButtonWithImageAndText().createAndShowGui());
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
try {
icon = new ImageIcon(ImageIO.read(getClass().getResource("up.jpg")));
} catch (IOException e) {
e.printStackTrace();
}
button = new JButton();
button.setIcon(icon);
button.setText("Click me!");
button.setHorizontalTextPosition(SwingConstants.CENTER);
button.setFont(new Font("Arial", Font.PLAIN, 40));
button.setForeground(Color.RED);
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
Which gives the following output:
For your future questions, please read how to make a valid Minimal, Complete and Verifiable Example (MCVE) that demonstrates your issue and your best try to solve it yourself, the code I posted is a good example of it, as you can copy-paste it and see the same result as I
Use the setComponentZOrder(...) method of the Container class. This will enable you to set the Z-index of the components to set them in what ever order you like. Look also this
so im trying to create a program in java which will create a 10 by 10 matrix, with each element displaying either a 1 or a 0 randomly. Here is what i have so far:
package random.matrix;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
class ex2 extends JFrame {
class Random {
GridLayout setLayout= new GridLayout(10, 10);
for (int i = 0; i < 10; i++) {
int number = (int) (Math.random() * 2);
String str = Integer.toString(number);
add(new JLabel(str, JLabel.CENTER));
}
}
public static void main(String[] args) {
JFrame frame = new ex2();
frame.setTitle("RandomMatrix");
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
As far as I can tell, this program should run perfectly. However, every time I try, it says something along the lines of "illegal start of type," referring specifically to the for loop line. Can anyone help me troubleshoot this? I've never encountered an error quite like this one.
You need to place your code in a code block such as a method or constructor rather than the class block of an inner class
/**
* TODO: Refactor later NOT to extend from JFrame
*/
class MyFrame extends JFrame {
void initComponents() {
GridLayout setLayout = new GridLayout(10, 10);
for (int i = 0; i < 10; i++) {
...
}
}
...
}
You can't have arbitrary statements inside a class definition. Perhaps you want to put it in the constructor?
class Random {
public Random() {
GridLayout setLayout = new GridLayout(10, 10);
for (int i = 0; i < 10; i++)
{
int number = (int) (Math.random() * 2);
String str = Integer.toString(number);
setLayout.add(new JLabel(str, JLabel.CENTER));
}
}
}
Or, you could just create another method and place it in there.
I want to imitate a table with scroll bar, but there is a problem with width.
Here is an extremely simplified code (but it is complete application, so you can compile it easilly and see everything at first hand).
package view;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import net.miginfocom.layout.AC;
import net.miginfocom.layout.CC;
import net.miginfocom.layout.LC;
import net.miginfocom.swing.MigLayout;
public class AppView
{
private final JFrame main_frame;
public AppView()
{
main_frame = new JFrame();
main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main_frame.setTitle("Example");
JPanel main_panel = new JPanel() {
private static final long serialVersionUID = 1L;
public Dimension getPreferredSize()
{
return new Dimension(300, 200);
}
};
main_panel.setLayout(new MigLayout("fill"));
JPanel table_panel = new JPanel();
table_panel.setLayout(new MigLayout(new LC(), new AC().gap("0"), new AC().gap("0")));
JScrollPane scroll_pane = new JScrollPane(table_panel);
scroll_pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
int[] width_arr = {20, 20, 20, 20, 20};
for (int i = 0; i < 60; i++) {
for (int j = 0; j < width_arr.length; j++) {
if (j == width_arr.length - 1)
table_panel.add(new JLabel(i + 1 + ", " + (j + 1)), new CC().width(width_arr[j] + "%").wrap());
else
table_panel.add(new JLabel(i + 1 + ", " + (j + 1)), new CC().width(width_arr[j] + "%"));
}
}
main_frame.getContentPane().add(main_panel, BorderLayout.CENTER);
main_panel.add(scroll_pane, new CC().grow());
main_frame.pack();
main_frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new AppView();
}
});
}
}
As you can see, I create a table_panel and wrap it with scroll_pane. Then I add 60 rows with 5 JLabels in each row. The problem is that if I specify each column's width so that total row width is 100%, width of scroll element starts to increase rapidly.
Here are two screenshots - one for case when horizontal scroll is disabled and another for case when horizontal scroll is enabled.
My suggestion about such behavior is that width of JScrollPane element is extremely large, but it seems that this suggestion is incorrect, because if I define width for each column so that total width is 98%, everything works fine.
Please, help me with understanding these weird things. Thanks in advance.
[UPDATE]
I decided to use another approach to achieve what I need. This approach is based on grid functionallity. There is a small condition - all width values should be multiple of 5. I suppose this condition is not limiting, because it's hard to imagine situations, where you need more than 5% precision.
First, I add 20 invisible elements (for further calls of span() method):
Box empty;
for (int i = 0; i < 20; i++) {
empty = new Box(BoxLayout.X_AXIS);
empty.setVisible(false);
if (i == 19)
table_panel.add(empty, "wrap");
else
table_panel.add(empty);
}
Without these elements, span() method will have no effect.
Here is full code sample:
package view;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import net.miginfocom.layout.AC;
import net.miginfocom.layout.CC;
import net.miginfocom.layout.LC;
import net.miginfocom.swing.MigLayout;
public class AppView
{
private final JFrame main_frame;
public AppView()
{
main_frame = new JFrame();
main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main_frame.setTitle("Example");
JPanel main_panel = new JPanel() {
private static final long serialVersionUID = 1L;
public Dimension getPreferredSize()
{
return new Dimension(300, 200);
}
};
main_panel.setLayout(new MigLayout("fill"));
JPanel table_panel = new JPanel();
table_panel.setLayout(new MigLayout(new LC().fill().debug(1).hideMode(2), new AC().gap("0"), new AC().gap("0")));
JScrollPane scroll_pane = new JScrollPane(table_panel);
scroll_pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
Box empty;
for (int i = 0; i < 20; i++) {
empty = new Box(BoxLayout.X_AXIS);
empty.setVisible(false);
if (i == 19)
table_panel.add(empty, "wrap");
else
table_panel.add(empty);
}
int[] width_arr = {20, 20, 20, 20, 20};
for (int i = 0; i < 60; i++)
for (int j = 0; j < width_arr.length; j++) {
if (j == width_arr.length - 1)
table_panel.add(new JLabel(i + 1 + ", " + (j + 1)), new CC().span(width_arr[j] / 5).wrap());
else
table_panel.add(new JLabel(i + 1 + ", " + (j + 1)), new CC().span(width_arr[j] / 5));
}
main_frame.getContentPane().add(main_panel, BorderLayout.CENTER);
main_panel.add(scroll_pane, new CC().grow());
main_frame.pack();
main_frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new AppView();
}
});
}
}
This works practically fine, and horizontal scroll isn't required anymore, but there is the problem with width of invisible boxes - their width is not constant and equal for all boxes, it depends on JLabels width. So proportions are not correct.
And here are some screenshots, illustrating that:
1) Simplest case: five columns, 20% width each, works fine.
2) More complicated example: three columns - 10%, 40%, 50%. Proportions are invalid, because second column isn't 4 times wider than first.
Well, now I have no idea what to do next. And all my attempts to find something on the Internet were in vain.
Ok, so I'm trying to add an array of 64 JButtons to a JFrame with and 8 by 8 grid layout (chess board type thing). Here's the relevant code section:
public class othello implements ActionListener{
int [][] board = new int[8][8];
JFrame window = new JFrame();
JButton[] buttons = new JButton[64];
public othello(){
window.setSize(400,400);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new GridLayout(8,8));
window.setVisible(true);
for (int i=0;i<64;i++){
buttons[i] = new JButton("");
buttons[i].addActionListener(this);
window.add(buttons[i]);
}
for (int i=0;i<8;i++){
for (int j=0;j<8;j++){
board[i][j]=2;
}
}
board[3][3]=0;board[4][4]=0;
board[3][4]=1;board[4][3]=1;
}
public void actionPerformed(ActionEvent e){
for (int i=0;i<8;i++){
for (int j=0;j<8;j++){
if(e.getSource()==buttons[i]){
buttons[i].setEnabled(false);
board[i][j]=1;
check();
}
}
}
}
public static void main (String[] args){
new othello();
}
}
What this code results in is a seemingly random number of buttons actually being added. Occasionally it adds all 64, more commonly it adds perhaps half or so, it always starts properly but stops at an arbitrary point (I tested by having the button labels count up).
I added some println's to see if the loop itself was actually completing, no problem there, it's going round the loop all 64 times, it just stops adding buttons at some point.
I'm something of a beginner at Java so I'm sure it's something really simple and stupid, but I currently have no idea what's going wrong. Can anyone help?
Edited for more code.
Have you initializated the array? like
JButton[] buttons = new JButtons[x];
make some prints to check in what number the loop stops.
You should be adding to a ContentPane not directly to a JFrame.add()
Like all other JFC/Swing top-level containers, a JFrame contains a
JRootPane as its only child. The content pane provided by the root
pane should, as a rule, contain all the non-menu components displayed
by the JFrame.
Are you setting the layout manager to something other than the default?
The default content pane will have a BorderLayout manager set on it.
Refer to RootPaneContainer for details on adding, removing and setting
the LayoutManager of a JFrame.
the proper idiomatic code to add contents is as follows:
window.getContentPane().add(child);
Refer to the Javadoc for details on proper use.
Maybe you are not using the event dispatch thread to manipulate the UI?
From the Swing Tutorial:
The event dispatch thread, where all event-handling code is executed.
Most code that interacts with the Swing framework must also execute on
this thread.
Try to run your UI construction code using SwingUtilities.invokeAndWait().
Edit: the corrected source code would be:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class othello implements ActionListener
{
int[][] board = new int[8][8];
JFrame window = new JFrame();
JButton[] buttons = new JButton[64];
public othello()
{
try
{
SwingUtilities.invokeAndWait(new Runnable()
{
public void run()
{
window.setSize(400, 400);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new GridLayout(8, 8));
window.setVisible(true);
for (int i = 0; i < 64; i++)
{
buttons[i] = new JButton("");
buttons[i].addActionListener(othello.this);
window.getContentPane().add(buttons[i]);
}
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
board[i][j] = 2;
}
}
board[3][3] = 0;
board[4][4] = 0;
board[3][4] = 1;
board[4][3] = 1;
}
});
}
catch (Exception e)
{
// TODO Handle exception
e.printStackTrace();
}
}
public void actionPerformed(ActionEvent e)
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
if (e.getSource() == buttons[i])
{
buttons[i].setEnabled(false);
board[i][j] = 1;
// check();
}
}
}
}
public static void main(String[] args)
{
new othello();
}
}
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;