I've got a two dimension array of JLabel components and I want to get the place where the mouse clicked in the label like this.
Jlabel [x] [y] // I want this x & y
How should I do that?
I've tried this but I get nothing!
new MouseAdapter(){
public void mousePressed(MouseEvent e){
int a=e.getX();
int b=e.getY();
MainBoard.ML.label=MainBoard.disk1[a][b];
Color c=MainBoard.ML.label.getForeground();
if(color==1)
MainBoard.ML.label.setForeground(Color.black);
else
MainBoard.ML.label.setForeground(Color.white);
new Play(a,b,color);
new Player2(r);
MainBoard.disk1[a][b].addMouseListener(new ML1(a,b));
}
};
I want to get the x & y index of the label array.
Untested and uncompiled code to locate x and y you are seeking is below.
Note that method getX() of class MouseEvent gets the location of the mouse pointer on the computer screen and not the x from your array. Similarly for method getY(). That's why you get nothing.
In the below code I add the same MouseListener to all the JLabels.
The MouseEvent contains the JLabel that the mouse was clicked on and method getSource() of class MouseEvent returns it. Then you need to iterate through your array of JLabels and see which one matches the MouseEvent source.
int rows = // number of rows in 2D array
int cols = // number of cols in 2D array
final JLabel[][] labels = new JLabel[rows][cols]
MouseListener ml = new MouseAdapter() {
public void mousePressed(MouseEvent me) {
Object src = me.getSource();
int x = -1;
int y = -1;
for (int i = 0; i < labels.length(); i++) {
for (int j = 0; j < labels[i].length; j++) {
if (src == labels[i][j]) {
x = i;
y = j;
break;
}
}
if (x >= 0) {
break;
}
}
if (x > 0) {
System.out.printf("JLabel[%d][%d] was clicked.%n", x, y);
}
else {
System.out.println("Could not find clicked label.");
}
}
}
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
labels[row][col] = new JLabel(row + "," + col);
labels[row][col].addMouseListener(ml);
}
}
Related
I have a Board 14x14 which has JButtons and every Jbutton has a different color. When you click one of those buttons, it checks the neighbors with the same color and removes them. When it removes them, theres a blank space between the board so the above buttons, should move down to fill the blank space. I tried with GridLayout but I don't know how to move the above buttons.
This actually is a case where you can hardly use a layout manager at all.
A LayoutManager is supposed to compute the layout of all components at once. It is triggered by certain events (e.g. when the parent component is resized). Then it computes the layout and arranges the child components accordingly.
In your case, the situation is quite different. There is no layout manager that can sensibly represent the "intermediate" state that appears while the upper buttons are falling down. While the components are animated, they cannot be part of a proper layout.
The animation itself may also be a bit tricky, but can fortunately be solved generically. But you still have to keep track of the information about where each component (i.e. each button) is currently located in the grid. When one button is removed, you have to compute the buttons that are affected by that (namely, the ones directly above it). These have to be animated. After the animation, you have to assign the new grid coordinates to these buttons.
The following is a MCVE that shows one basic approach. It simply removes the button that was clicked, but it should be easy to generalize it to remove other buttons, based on other conditions.
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class FallingButtons
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int rows = 8;
int cols = 8;
GridPanel gridPanel = new GridPanel(rows, cols);
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
JButton button = new JButton(r+","+c);
gridPanel.addComponentInGrid(r, c, button);
button.addActionListener(e ->
{
Point coordinates = gridPanel.getCoordinatesInGrid(button);
if (coordinates != null)
{
gridPanel.removeComponentInGrid(
coordinates.x, coordinates.y);
}
});
}
}
f.getContentPane().add(gridPanel);
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class GridPanel extends JPanel
{
private final int rows;
private final int cols;
private final JComponent components[][];
GridPanel(int rows, int cols)
{
super(null);
this.rows = rows;
this.cols = cols;
this.components = new JComponent[rows][cols];
addComponentListener(new ComponentAdapter()
{
#Override
public void componentResized(ComponentEvent e)
{
layoutGrid();
}
});
}
private void layoutGrid()
{
int cellWidth = getWidth() / cols;
int cellHeight = getHeight() / rows;
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
JComponent component = components[r][c];
if (component != null)
{
component.setBounds(
c * cellWidth, r * cellHeight, cellWidth, cellHeight);
}
}
}
}
Point getCoordinatesInGrid(JComponent component)
{
for (int r=0; r<rows; r++)
{
for (int c=0; c<cols; c++)
{
if (components[r][c] == component)
{
return new Point(r, c);
}
}
}
return null;
}
void addComponentInGrid(int row, int col, JComponent component)
{
add(component);
components[row][col] = component;
layoutGrid();
}
JComponent getComponentInGrid(int row, int col)
{
return components[row][col];
}
void removeComponentInGrid(int row, int col)
{
remove(components[row][col]);
components[row][col] = null;
List<Runnable> animations = new ArrayList<Runnable>();
for (int r=row-1; r>=0; r--)
{
JComponent component = components[r][col];
if (component != null)
{
Runnable animation =
createAnimation(component, r, col, r + 1, col);
animations.add(animation);
}
}
for (Runnable animation : animations)
{
Thread t = new Thread(animation);
t.setDaemon(true);
t.start();
}
repaint();
}
private Runnable createAnimation(JComponent component,
int sourceRow, int sourceCol, int targetRow, int targetCol)
{
int cellWidth = getWidth() / cols;
int cellHeight = getHeight() / rows;
Rectangle sourceBounds = new Rectangle(
sourceCol * cellWidth, sourceRow * cellHeight,
cellWidth, cellHeight);
Rectangle targetBounds = new Rectangle(
targetCol * cellWidth, targetRow * cellHeight,
cellWidth, cellHeight);
Runnable movement = createAnimation(
component, sourceBounds, targetBounds);
return () ->
{
components[sourceRow][sourceCol] = null;
movement.run();
components[targetRow][targetCol] = component;
repaint();
};
}
private static Runnable createAnimation(JComponent component,
Rectangle sourceBounds, Rectangle targetBounds)
{
int delayMs = 10;
int steps = 20;
Runnable r = () ->
{
int x0 = sourceBounds.x;
int y0 = sourceBounds.y;
int w0 = sourceBounds.width;
int h0 = sourceBounds.height;
int x1 = targetBounds.x;
int y1 = targetBounds.y;
int w1 = targetBounds.width;
int h1 = targetBounds.height;
int dx = x1 - x0;
int dy = y1 - y0;
int dw = w1 - w0;
int dh = h1 - h0;
for (int i=0; i<steps; i++)
{
double alpha = (double)i / (steps - 1);
int x = (int)(x0 + dx * alpha);
int y = (int)(y0 + dy * alpha);
int w = (int)(w0 + dw * alpha);
int h = (int)(h0 + dh * alpha);
SwingUtilities.invokeLater(() ->
{
component.setBounds(x, y, w, h);
});
try
{
Thread.sleep(delayMs);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
return;
}
}
SwingUtilities.invokeLater(() ->
{
component.setBounds(x1, y1, w1, h1);
});
};
return r;
}
}
You could try using a 2-dimensional array of JButtons
JButton[][] buttons = new JButton[14][14];
for (int i=0; i < buttons.length; i++) {
for (int j=0; j < buttons[i].length; j++) {
buttons[i][j] = new JButton("Button [" + i + "][" + j + "]");
}
}
// Then do whatever,remove,change color,check next element in array
// and compare colors etc
buttons[2][3].setText("changed text");
If you want the above buttons to take more space to fill the empty space when you remove a component well, this is not possible using GridLayout, but you can add some empty components like JLabels to fill the space.
You can add a component in a container at a specific index for this purpose, by using Container's add (Component comp, int index) method.
This code snippet will replace a button at a specified index (45, just for example) with a blank component in a panel which has a GridLayout set:
JPanel boardPanel = new JPanel (new GridLayout (14, 14));
// ... add your buttons ...
// This code could be invoked inside an ActionListener ...
boardPanel.remove (45);
boardPanel.add (new JLabel (""), 45);
boardPanel.revalidate ();
boardPanel.repaint ();
This way, the rest of the components will not move, and you will just see a blank space replacing your button.
You can achieve more: if you add the empty label at index = 0, all the buttons will move to the right (remember that the number of components should not change, else the components will resize and you could obtain bad behaviour), and so on, you can "move" a single component by simply removing it and adding it at a different index.
Another way to go would be to store a 2-dimensional array of objects representing your model logic (you can store color and all the stuff you need), and painting them on your own by overriding paintComponent method.
For an example of a custom painting approach, take a look at this MadProgrammer's answer, where he shows how to highlight a specific cell in a grid (in this case he uses a List to store objects, but a 2d array will work as well).
I have 2 array's of buttons shown in two Jframes and I need to tell which one is being pressed, My current solution only detects a button press for the first window that is pressed so when you click a button on the first window you will not be able to click a button on the second windows until the program is restarted.
My code is
private void populateArray()
{
for(int wy = 0;wy<8;wy++)
{
for(int wx =0; wx<8;wx++)
{
WhiteButton[wx][wy] = new ReversiButton();
WhiteButton[wx][wy].addActionListener(this);
if((wx == 3)&&( wy ==3))
WhiteButton[wx][wy].change(1);
else if((wx == 4)&&(wy == 3))
WhiteButton[wx][wy].change(2);
else if((wx == 3)&&(wy == 4))
WhiteButton[wx][wy].change(2);
else if((wx ==4)&&(wy == 4))
WhiteButton[wx][wy].change(1);
}
}
for(int by = 0; by<8; by++)
{
for(int bx =0; bx<8;bx++)
{
BlackButton[bx][by] = new ReversiButton();
BlackButton[bx][by].addActionListener(this);
if((bx == 3)&&( by ==3))
BlackButton[bx][by].change(1);
else if((bx == 4)&&(by == 3))
BlackButton[bx][by].change(2);
else if((bx == 3)&&(by == 4))
BlackButton[bx][by].change(2);
else if((bx ==4)&&(by == 4))
BlackButton[bx][by].change(1);
}
}
}
private void initGUI()
{
WhiteFrame.setTitle("Reversi White Player");
BlackFrame.setTitle("Reversi Black Player");
WhiteFrame.setLayout(new BorderLayout());
WhiteLabel.setText("White Player - click place to put piece");
WhiteGrid.setLayout(new GridLayout(8,8));
for(int wy = 0;wy<8;wy++)
{
for(int wx =0; wx<8;wx++)
{
WhiteGrid.add(WhiteButton[wx][wy]);
}
}
WhiteButtons.setText("Greedy AI(play white)");
WhiteFrame.add(BorderLayout.NORTH,WhiteLabel);
WhiteFrame.add(BorderLayout.CENTER,WhiteGrid);
WhiteFrame.add(BorderLayout.SOUTH,WhiteButtons);
WhiteFrame.pack();
WhiteFrame.setVisible(true);
BlackFrame.setLayout(new BorderLayout());
BlackLabel.setText("Black player - not your turn");
BlackGrid.setLayout(new GridLayout(8,8));
BlackButton = Reverse.rotatearray(BlackButton);
for(int by = 0; by<8; by++)
{
for(int bx =0; bx<8;bx++)
{
BlackGrid.add(BlackButton[bx][by]);
}
}
BlackButtons.setText("Greedy AI(play black)");
BlackFrame.add(BorderLayout.NORTH, BlackLabel);
BlackFrame.add(BorderLayout.CENTER, BlackGrid);
BlackFrame.add(BorderLayout.SOUTH,BlackButtons);
BlackFrame.pack();
BlackFrame.setLocation(WhiteFrame.getX() + WhiteFrame.getWidth() + 10, WhiteFrame.getY());
BlackFrame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent ae)
{
for (int y = 0; y < GRIDSIZE; y++)
{
for (int x = 0; x < GRIDSIZE; x++)
{
if((ae.getSource()==WhiteButton[x][y]))
{
if(WhiteButton[x][y].is() ==0)
{
WhiteButton[x][y].change(1);
Game.search(WhiteButton, x, y, 1);
}
}
if((ae.getSource() == BlackButton[x][y]))
{
if(BlackButton[x][y].is() == 0)
{
BlackButton[x][y].change(2);
Game.search(BlackButton, x, y, 2);
}
}
}
}
}
How can i detect button presses from both JFrames?
You could define an action command for each button:
WhiteButton[wx][wy].setActionCommand(w + wx + "," + wy);
and call getActionCommand to retrieve this String. Alternatively, rig up a Map
Map<JButton,ButtonData> but2dat
and store coordinates and current state in an object of class ButtonData.
I created two-dimensional array of Button actor, then I added new ClickListener() {
touchDragged } as the following code:
buttons = new Button[3][3];
for (int row = 0; row < buttons.length; row++) {
for (int col = 0; col < buttons[0].length; col++) {
buttons[row][col] = new Button(drawable);
buttons[row][col].addListener(new ClickListener() {
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
for (int row = 0; row < buttons.length; row++) {
for (int col = 0; col < buttons[0].length; col++) {
if (buttons[row][col].isOver()) {
buttons[row][col].setColor(Color.GREEN);
}
}
}
}
}
}
the code inside touchDragged method if the buttons isOver the buttons colored GREEN (it works fine) as shown in image
Now, How can I remove Color.GREEN i.e. (Color.WHITE) from buttons in the same calling touchDragged method, I mean undo GREEN to WHITE if the isOver() still true??
this image clear my question :
like Alphabetty Game from king company, if you know it :).
Sorry, For bad English
You could use an if statement to check which colour the square is. If it is white, colour it green and vice versa.
I have something similar and for some reason you can't directly compare colours in an if statement, however changing them to an rgb int value solves this. You can choose from the various rgb options such as rgba8888 or argb8888 etc, choose one which will suit your needs. The simplest one would just be rgb888. It is a static method in the colour class, pass it a colour it will return an int.
if(Color.rgb888(button[row][col].getColor()) == Color.rgb888(Color.Green()))
{
button[row][col].setColor(Color.White());
}
1- Create List :
private List<Integer> list;
// In create OR show Method
list = new ArrayList<Integer>();
2- Create this line code (as ID for buttons[row][col]):
buttons[row][col].setName("" + id++);
3- Write this code inside your touchDragged .. after your loop:
if (buttons[row][col].isOver()) {
try {
if (list.contains(Integer.parseInt(buttons[row][col].getName()))) {
if(Integer.parseInt(buttons[row][col].getName()) == list.get(list.size() - 2)) {
stage.getRoot().findActor("" + list.get(list.size() - 1)).setColor(Color.WHITE);
list.remove(list.size() - 1);
}
} else {
buttons[row][col].setColor(Color.GREEN);
list.add(Integer.parseInt(buttons[row][col].getName()));
}
} catch (Exception e) {
System.out.println(e.getClass());
}
}
4- See the answer in this video
How would I create a 2d icon array and print it out in a JOptionPane box. so Far I have this, but when I print it out it shows a bunch of BlockEmpty.png
public class iconarray{
public static void main (String [] args)
{
Icon blockempty = new ImageIcon("BlockEmpty.png");
Icon Board [] [] = new Icon [8] [8];
String GameBoard = "";
for (int count2 = 2; count2 <= 7; count2++)
{
for (int count3 = 1; count3 <= 7; count3++)
{
Board[count2][count3] = blockempty;
}
}
for (int count2 = 2; count2 <= 7; count2++)
{
for (int count3 = 1; count3 <= 7; count3++)
{
GameBoard = GameBoard + Board[count2][count3];
}
GameBoard = GameBoard + "\n";
}
JOptionPane.showMessageDialog(null, "", "Connect 4", JOptionPane.PLAIN_MESSAGE, blockempty);
}
}
In order to display a Icon or Image, you first need some way to render it. Icons and Images don't have the means to render them selves (per se), but require another component that can render them.
Something else a lot of people forget, is JOptionPane is capable of display components.
For example:
Icon brick = new ImageIcon(BoardOption.class.getResource("/images.jpg"));
JPanel wall = new JPanel(new GridLayout(8, 8, 0, 0));
JLabel bricks[][] = new JLabel[8][8];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
bricks[y][x] = new JLabel(brick);
wall.add(bricks[y][x]);
}
}
JOptionPane.showMessageDialog(null, wall, "Another brick in the wall", JOptionPane.PLAIN_MESSAGE, null);
Take a look at How to use icons for more details.
I have a chessboard, made by overriding the paint() method of a class extending Panel. I highlight all the possible squares a chess piece can go to on the board, and store the pixel values of the upper left corners of the highlighted squares in the:
private ArrayList<Integer> highlightedSquares = new ArrayList<Integer>();
topLeftVal is an array with all of the top left corner values of the squares. In the mouseClicked method of the mouseAdapter, I want to know when a highlighted square (and only a highlighted square) is clicked, and then call repaint(). However, for some reason the program also accepts many squares that are not highlighted.
Here is the code (I apologize for the formatting):
public void mouseClicked(MouseEvent e){
clickPointX = e.getX();
clickPointY = e.getY();
//iterate through highlightedSquares and if the clicked pt is in one of them, repaint
int q = 0;
int xCoor = 0, yCoor = 0;
for(int a : highlightedSquares){
if(q % 2 == 0)
xCoor = a;
else{
yCoor = a;
if((xCoor <= clickPointX) && (clickPointX <= (xCoor + 80)) && (yCoor <= clickPointY) && (clickPointY <= (yCoor + 80))){ //I think this line is causing the problem?
_pixX=xCoor;
_pixY=yCoor;
for(int i = 0; i < topLeftVal.length;i++){
if(topLeftVal[i] == _pixX)
_x = i;
if(topLeftVal[i] == _pixY)
_y = i;
}
repaint();
break;
} //end of if inside else
} //end of else
q++;
} //end of foreach
} //end of mouseClicked
Here is an example implementation where I defined two classes -- Board and Square. Board is derived from JPanel. Square represents a single square on the board. My mouse click listener displays a message which indicates whether or not the clicked upon square is highlighted. Hopefully this will give you a good idea of how to modify your code to achieve the desired result.
public class TestMain {
public static void main(String[] args) throws Exception {
new TestMain().run();
}
public void run() {
// create and show a JFrame containing a chess board
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Board board = new Board();
board.getSquare(2, 4).setHighlighted(true);
board.getSquare(3, 4).setHighlighted(true);
window.getContentPane().add(board, BorderLayout.NORTH);
window.pack();
window.setVisible(true);
}
// *** Board represents the chess board
private class Board extends JPanel {
// *** the constructor creates the squares and adds a mouse click listener
public Board() {
setPreferredSize(new Dimension(squareSize * 8, squareSize * 8));
// create the squares
boolean rowStartRedFlag = true;
for (int row = 0; row < 8; row++) {
boolean redFlag = rowStartRedFlag;
for (int column = 0; column < 8; column++) {
squares [row] [column] = new Square(this, row, column, redFlag);
redFlag = !redFlag;
}
rowStartRedFlag = !rowStartRedFlag;
}
// add mouse click listener
this.addMouseListener(new MouseClickListener());
}
// *** mouse click listener
private class MouseClickListener extends MouseAdapter {
#Override
public void mouseClicked(MouseEvent e) {
Square square = getSquareAt(e.getX(), e.getY());
String msg = square.isHighlighted() ? "Square is highlighted" : "Square is not highlighted";
JOptionPane.showMessageDialog(null, msg);
}
}
// ** override paint
#Override
public void paint(Graphics g) {
draw ((Graphics2D) g);
}
// *** draw every square on the board
public void draw(Graphics2D g) {
for (int row = 0; row < squares.length; row++) {
for (int column = 0; column < squares [row].length; column++) {
squares [row] [column].draw(g);
}
}
}
// *** get square given row and column
public Square getSquare(int row, int column) {
return squares [row] [column];
}
// *** get square from coords
public Square getSquareAt(int x, int y) {
int column = getColumnAtX(x);
int row = getRowAtY(y);
return squares [row] [column];
}
// *** get column # given x
public int getColumnAtX(int x) {
int column = x / squareSize;
return Math.min(Math.max(column, 0), 7);
}
// *** get row # given x
public int getRowAtY(int y) {
int row = y / squareSize;
return Math.min(Math.max(row, 0), 7);
}
// ** get left x given column
public int getLeftFromColumn(int column) {
return column * squareSize;
}
// ** get top y give row
public int getTopFromRow(int row) {
return row * squareSize;
}
// *** get size of square side
public int getSquareSize() {
return squareSize;
}
private int squareSize = 25; // length of square side
private Square [][] squares = new Square [8][8];
}
// *** Squalre represents one square on the board
private class Square {
// ** constructor creates the square
public Square(Board board, int row, int column, boolean redFlag) {
this.board = board;
this.column = column;
this.row = row;
if (redFlag) {
color = Color.RED;
colorHighlighted = Color.PINK;
} else {
color = Color.BLACK;
colorHighlighted = Color.LIGHT_GRAY;
}
}
// ** set highlight flag
public void setHighlighted(boolean value) {
highlighted = value;
}
// *** see if square is highlighted
public boolean isHighlighted() {
return highlighted;
}
// *** draw the square
public void draw(Graphics2D g) {
Color fillColor = highlighted ? colorHighlighted : color;
g.setColor(fillColor);
int x = board.getLeftFromColumn(column);
int y = board.getTopFromRow(row);
int size = board.getSquareSize();
g.fillRect(x, y, size, size);
}
private Board board;
private Color color;
private Color colorHighlighted;
private int column;
private boolean highlighted = false;
private int row;
}
}