Adding image to a Button in JavaFX after Button is created - java

I am working on coding a MineSweeper game using JavaFx. I am having an issue with changing the Buttons to just include an image and not have text. A portion of my code is as follows:
ImageView bomb;
Image bombImage = new Image(MineSweeper.class.getResourceAsStream("images/bomb.png"));
bomb = new ImageView(bombImage);
boolean[][] mineField = new boolean[row][column];
for (int i = 0; i < numMines; i++) {
int indexRow = isMine.nextInt(row);
int indexCol = isMine.nextInt(column);
System.out.println("row: " + indexRow + ", column: " + indexCol);
mineField[indexRow][indexCol] = true;
}
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
System.out.println("" + mineField[i][j]);
if (mineField[i][j] == true) {
board[i][j].setText("");
board[i][j].setGraphic(bomb);
} else {
board[i][j].setText("Nope!");
}
}
}
This is not how the actual game will work. But I was wanting to check if I could add the image of the bomb to the buttons that contain a mine. When I run the code there is only one image of a mine that shows up and the other buttons just have empty text or say "Nope!." If I cannot figure out how to add an image to a button then I will not be able to actually continue with the programming of the game. I have decided that I want to build this game from scratch and not use Scene Builder. I appreciate any advice.

The reason for only one image is displayed that you cannot use the same ImageView as graphic for two Button objects.
An optional icon for the Labeled. This can be positioned relative to
the text by using
setContentDisplay(javafx.scene.control.ContentDisplay). The node
specified for this variable cannot appear elsewhere in the scene
graph, otherwise the IllegalArgumentException is thrown. See the class
description of Node for more detail.
Modify this line ...
board[i][j].setGraphic(bomb);
... to ...
board[i][j].setGraphic(new ImageView(bombImage ));
This will create a new ImageView object for all of your Buttons.

Related

Creating a clickable grid in Processing 3

I'm trying to make a grid of squares that change their fill (from black to white and vice-versa) when clicked. I'm able to turn the entire grid on or off currently, but I'm unable to figure out how to specify which particular square should be toggled when the mouse clicks within its borders. I've created buttons using mouseX and mouseY coordinates before, but they were for specific objects that I could adjust manually. I can't figure out how to do this using for loops and arrays.
I've been told to create a boolean array and pass the value of that array to the grid array, but again, I don't know how to specify which part of the array it needs to go to. For example, how do I change the fill value of square [6][3] upon mousePressed?
Here is my code so far:
int size = 100;
int cols = 8;
int rows = 5;
boolean light = false;
int a;
int b;
void setup() {
size (800, 600);
background (0);
}
void draw() {
}
void mousePressed() {
light = !light;
int[][] box = new int[cols][rows];
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
box[i][j] = i;
int a = i*100;
int b = j*100;
if (light == true) {
fill(255);
} else {
fill(0);
}
rect(a, b, 100, 100);
println(i, j);
}
}
}
First of all, you are currently recreating the entire board whenever the mouse is pressed. You must retain that info between mouse clicks, so make box a global array up there with the others. Further, it's sufficient to make it a boolean array if all you care about is the on/off state of each square:
boolean[][] isSquareLight = new boolean[cols][rows];
Instead of
if (light == true) {
you should then just check
if (isSquareLight[i][j] == true) {
(note that the == true is redundant).
Now, you've already written code that finds the coordinates for each box: You're passing it to rect!
rect(a, b, 100, 100);
All that is left to do is check whether the mouse is inside this rect, i.e. whether mouseX is between a and a+100 (and similar for mouseY) - if that's the case, then the user clicked in the box given by the current (i, j), so you can just negate isSquareLight[i][j] (before checking it like above) and it will work.
There are ways to calculate this without looping through the entire grid every time, but maybe the above helps you find the path yourself instead of just getting the code made for you.
PS: The int a; int b; at the top does nothing and can be removed. You are using the local variables a and b in your function, which is correct.

libGDX : Paint And Remove Color From Actor with touchDragged

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

Changing the position of images on the JFrame

So I am making this ABC learning game , What I want to do is if I click on the A button more than once then , the three Images will change their position, What I want to do is this
![enter image description here][1]
When I click on A button, the three image will appear on the screen, the first is apple as I set it that way in the loop, but the second two images will appear randomly, though sometimes one o them is apple again, I could fix that.
My Question is, how can I change that position of the Apple to the second and second image to the first and third image to the second position if the "A" button is clicked more than once.
SO, the result will be the apple will change position based on the click "A" button and other two picture changes their position and chosed randomly from the array.
So, here is my code for the JPanel, where everything takes place.Most of the code is explained in the comments
import java.awt.*;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.awt.event.*;
import java.text.AttributedCharacterIterator;
import java.util.Random;
import javax.swing.ImageIcon;
/**
*
* #author Dip
*/
public class AbcGeniusPanel extends JPanel implements ActionListener {
//Declare the necessary Variables here
private JButton[] buttons; //create an array for buttons
private BorderLayout layout; //Declare object of BorderLayout
private Image image = null;
private boolean showImage = false;
//Initialize all the variables here
static int index = 0;
int randNumber = 0, id = 0;
int q = 0, w = 0;
int buttonClick = 0;
//Store all the imahges that will appear on the screen into an String type array
private static String[] imageList = {"src/Images/1.png", "src/Images/2.png", "src/Images/3.png", "src/Images/4.png", "src/Images/5.png", "src/Images/6.png", "src/Images/7.png", "src/Images/8.png", "src/Images/9.png", "src/Images /10.png",
"src/Images/11.png", "src/Images/12.png", "src/Images/13.png", "src/Images /14.png", "src/Images/15.png",
"src/Images/16.png", "src/Images/17.png", "src/Images/18.png", "src/Images /19.png", "src/Images/20.png",
"src/Images/21.png", "src/Images/22.png", "src/Images/23.png", "src/Images /24.png", "src/Images/25.png",
"src/Images/26.png"
};
//Define the constructor here
public AbcGeniusPanel() {
ImageIcon[] alphabets = new ImageIcon[26];
setBackground(Color.yellow);
//Load the images for alphabet images into the alphabets array using a for loop
for (int i = 0; i < alphabets.length; i++) {
alphabets[i] = new ImageIcon("C:\\Users\\Dip\\Desktop\\Java Projects\\AbcGeniusApp\\src\\Alphabets\\" + (i + 1) + ".png");
}
//Create a JPnael object
JPanel panel = new JPanel();
//Set a layoutManager on the panel
//panel.setLayout(new FlowLayout(FlowLayout.CENTER)); //This is not workling good
panel.setLayout(new GridLayout(2, 13, 5, 5)); //This is good for now
//Create an array for holdoing the buttons
buttons = new JButton[26];
//This Loop will Store the buttons in the buttons array attatching each image for each button
//Try passing Images inside the JButton parameter later.
for (int i = 0; i < 26; i++) {
buttons[i] = new JButton(alphabets[i]);
}
// Now Setting up a new Borderlayout so that we can set the whole gridLayout at the botton of the panel
setLayout(new BorderLayout(2, 0));
//add the panel to the Border layout
add(panel, BorderLayout.SOUTH);
//Add evenHandling mechanism to all the buttons
for (int k = 0; k < 26; k++) {
buttons[k].addActionListener(this);
}
for (int count1 = 0; count1 < 26; count1++) {
panel.add(buttons[count1]);
}
}
//This Method will generate a random Number and return it
public int random_number() {
int rand_num;
Random generator = new Random(System.currentTimeMillis());
rand_num = generator.nextInt(26);
return rand_num;
}
//This method will draw the font on the Panel
public void paintComponent(Graphics g) {
Font font; //Declare Font object here
font = new Font("Wide Latin", Font.BOLD, 22); //Set font
super.paintComponent(g); //Ensure the drawing in super class
g.setFont(font); //Set the font
g.setColor(Color.RED);
String text = "CLICK ON THE RIGHT IMAGE!"; //Display the text
g.drawString(text, 255, 20);
}
//To draw the picture on the screen we need to override the paint Method
#Override
public void paint(Graphics g) {
super.paint(g);
//Here, x and y will determine the x and y position os each image
int x = 0, y = 0;
// the varibale q is declared above
for (q = 0; q < 3; q++) //This loop will generate three images on the screen
{
if (showImage) {
x = x + 265; //X-Position of the image
y = 90; //Y-Position of the image
//q is declared as q=0, so this will always be true
if (w == 1 || q == 0) {
g.drawImage(image, x, y, image.getWidth(null), image.getHeight(null), null); //This method will put the image on the screen
showImage = true;
w = 0;
}
while (true) //this loop will run anyway
{
//go inside this loop only when the generated random
//doesn't match with the index of the button that was pressed
while ((randNumber = random_number()) != index) {
index = randNumber; //Now put the randomVlaue in the index
this.image = new ImageIcon(imageList[randNumber]).getImage();
showImage = true;
//make w=1 so that we can break from the outer loop
w = 1;
//break from the inner loop
break;
}
//Since we have made the w=1, so we are breaking out of the outer loop
if (w == 1) {
break;
}
}
}
}
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
id = 0;
while (true) {
//id is set to zero, for example if the button A (buttons[0])is not pressed then it will go below
//to increase id until it matches the index of the button that we pressed
if (source == buttons[id]) {
//get the image of that same index of the buttons and then set the showImage true
//SO the the paint function above can draw the image
this.image = new ImageIcon(imageList[id]).getImage();
showImage = true;
//save the index of the button that is presed in another variable
//then break from the while loop
index = id;
break;
} else {
id++;
//This is necessary to make sure that id will cross 26
//becasue we have only 26 letters or the array index is 26
//so highest value can be 26 only
id = id % 26;
}
}
repaint();
}
}
Add 3 JLabels or JButtons (whatever will be displaying the images) into a JPanel container. The JPanel will likely use a GridLayout(1, 3, horizontal_gap, 0) layout.
Place all images as ImageIcons into an ArrayList.
Shuffle the ArrayList when needed
After shuffling place the Icons into the JLabels/JButtons in a for loop using the setIcon(...) method.
Note that
your JPanel should override paintComponent, not paint. The paint method is responsible for painting a component's children and borders, and it does not use double buffering by default, making a more dangerous method to override.
Putting in a while (true) loop into your Swing GUI without regard to threading is extremely dangerous.
Putting this into a painting method such as paint is GUI suicide. Never do this since a painting method is a major determinant in the perceived responsiveness of your program. If you slow it down, the program will be perceived as being slow and poorly responsive, and thus it must be lean and fast as possible, and you should have painting and only painting code within it.
Your paint method has program logic in it, something that also shouldn't be done. You don't have full control over whether or even if a painting method will be called, and so program logic should never be placed inside one of these.
As MadProgrammer well notes, don't use the src path for your images as this won't exist once you build your program into a jar file. Better to Create a resource directory in the jar file, and to refer to your images as resources, not as files.

Selecting a JLabel by knowing its Name

If I have many JLabels on the screen and I know their names how would I go about selecting finding them?
For example I know that I previously (dynamically) created a new JLabel with the name 2340. Is there something like
JLabel image = findJlabel ("2340");
In order to select the JLabel component?
Thanks,
Neco
EDIT: Just want to show how I am creating these JLabels
// Initially creates all the imagelabels
public static void createImageLabels (){
int xcord, ycord;
JLabel image;
String imageLabelName;
xcord = 0;
ycord = yOffset;
for (int row = 0 ; row < map.length; row++) {
xcord = 0;
for (int col = 0 ; col < map[0].length; col++) {
imageLabelName = Integer.toString(row);
imageLabelName += Integer.toString(col);
image = new JLabel(new ImageIcon(space));
image.setName(imageLabelName);
image.setLocation(xcord, ycord);
image.setSize(24, 24);
imagePanel.add(image);
System.out.println ("Created a Jlabel Named "+imageLabelName);
xcord += 24;
}
ycord += 24;
}
}
I create a tile of imageIcons on the screen and then later on if I want to change the image displayed by them I want to select it and change it.
Well, assuming you have different names for all labels, i would recommend you using HashMaps.
HashMap<String, JLabel> labels = new HashMap<String,JLabel>();
Inside you "for" sicle, use:
labels.put("1233", new JLabel(new ImageIcon(space)));
To use your the label you want, use:
labels.get("1233");
For more information, check:
http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html
If you only want to find the component with the concept of the current container it easy, if you want to search child or parent containers, it becomes little more complicated...
public JLabel findLabelByName(Container parent, String name) {
JLabel found = null;
if (name != null) {
for (Component child : parent.getComponents()) {
if (child instanceof JLabel) {
JLabel label = (JLabel)child;
if (name.equals(label.getName()) {
found = label;
break;
}
}
}
}
return found;
}
Now, if you want to search up or down the container hierarchy, you would need to perform a recursive call to this method, passing in the new parent, but I'm sure you can figure that out, don't want to rob you of all the fun ;)
In order to select the JLabel component?
how are you 'selecting' the label?
if it's via the mouse, just add a mouseListener and use getSource()

SWT Button Grid

It's a problem that it's annoying me for 3 days now.
I have to rewrite the UI of a little tictactoe(Gomoku of n x n) game.
the problem is that when i created the swing GUI , i made a new class that inherits JButton properties and added an int for rows and an int for columns. I cannot do that with SWT(no inheritance). is there a way for me to add the values of i and j to the button.
Here is the example in Swing:
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
final MyJButton button = new MyJButton(i, j);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
MoveResult move = game.move(button.getRow(), button.getCol());
switch (move) {
case ValidMove:
button.setBackground(game.getCurrentPlayer().getColor());
game.changePlayer();
break;
}
}
}
}
}
}
I give the i and j for the game class which give it to a table clas to check the move.
if (table.getElement(x, y) != PieceType.NONE) return MoveResult.InvalidMove;
private PieceType[][] table;
is there a way to do the same in SWT, any indication is welcomed .
this is what i made
buttonpanel = new Composite(shell, SWT.NONE);
buttonpanel.setLayout(new org.eclipse.swt.layout.GridLayout(cols, true));
buttonTable = new Button[rows][cols];
for (int i = 0; i < rows; ++i){
for (int j = 0; j < cols; ++j) {
gridData.heightHint = 45;
gridData.widthHint = 45;
Button button = new Button(buttonpanel, SWT.PUSH);
button.setLayoutData(gridData);
buttonTable[i][j] = button;
buttonTable[i][j].addSelectionListener(new buttSelectionListener());
// buttonpanel.pack();
}
}
I see two solutions :
use Button's setData method (defined in the Widget superclass) to associate an object containing your x and y (you'll found those data in the event object provided to your listener)
use different listeners for each button
In your case, the first solution seems the most natural one.
This means creating a class holding x and y (let's call it Cell), and doing
button.setData(new Cell(i, j));
and in you listener using
game.move(e.data.x, e.data.y);
Options include:
Subclass Button, and override its checkSubclass() method to indicate that you're taking responsibility for not subclassing harmfully.
Make each Button a Composite, which allows subclassing, and put a Button in the Composite.
Make a separate listener for each button.
In a single listener, search through the buttonTable for the button that calls the listener.

Categories

Resources