JButton and its Location methods acting very weird - java

my problem is, that when I create a JButton, whithin its constructor, I set its location to some relative coordinates, say x = 5, and y = 6, using the following code:
this.setLocation(new Point(x, y));
but after I am trying to get its location using the getLocation() method, it always returns 0,0. Please note that this happens for every JButton I am trying to place on a grid layout powered JFrame, and during the debugging process, I have also noted that their location is being properly instantiated.
Can someone explain to me why this happens, and if I can fix it somehow?
EDIT:
The constructor (The brick class that I made, extends JButton):
public Brick(int posx, int posy) {
this.setLocation(new Point(posx, posy));
this.setVisible(true);
}
I make about 100+ of them in 2 for loops:
for (int row = 0; row < 15; row++) {
for (int column = 0; column < 15; column++) {
Brick brickie = new Brick(row, column);
}
}
But afterwards, if I wanna pick a brick and check its location like this:
Point brickLocation = brickie.getLocation();
both brickLocation.x == 0 and brickLocation.y == 0

You are trying to change button location when it is automatically assigned by layout manager (your GridLayout). That is why you are always getting the same value back - layout just overwrites it.
To be able to change any component bounds/location (including buttons) manually - you have to set "null" as the container's layout. After that just change the location/size/bounds as you like and it will affect the components positions.
Also you don't need to use "setVisible(true)" - by default that flag is true for all components (even those that aren't displayed yet).

JComponent(s) can returns its coordinates, getBounds or getLocation only
if container is already visible on the screen
after pack()

Related

How to take a second actionPerformed for moving a chess piece?

I am making a chess game and need to figure out how to move the pieces. I have my pieces stored in an array squaresGrid[][] and I want to use the method moveTo to move the pieces. Currently this method simply marks a piece selected but I need it to take a second mouse click to choose the square to move the selected piece to but am not sure how best to do this.
public void actionPerformed(ActionEvent e)
{
for(int x = 0; x < 8; x++)
{
for(int y = 0; y < 8; y++)
{
if(e.getSource() == squaresGrid[x][y])
{
moveTo(e, squaresGrid[x][y]);
}
}
}
}
public void moveTo(ActionEvent e, JButton clicked)
{
clicked.setIcon(selected);
}
You don't do a "second actionPerformed". What you do is keep around state, and when a click happens, look at the state, and decide what the action should be.
For example, keep around a field called currentlySelected, pointing to the currently selected square (containing its coordinates, for example).
In the actionPerformed, when you receive a click, you look at currentlySelected.
If it is null, it means you are supposed to select the clicked square and put it in currentlySelected.
If it is not null, and the current click is in the same square, the user probably wants to de-select it. De-select and clear (put null) in currentlySelected.
If it is not null and not the same square, it means that you have to check if the move is legal. If it is legal, you can do the move, and clear currentlySelected. If it is not legal, you do what you think is the proper thing to do: perhaps de-select the original place and select the new one. Or just de-select and tell the user the move is not legal. Or keep it selected.
Remember to always clear your currentlySelected in the appropriate situations.
You don't need a second ActionListener or actionPerformed method, but rather you need a state-ful ActionListener, one that knows whether the button push represents the first push or the 2nd. A boolean variable could be all that is required for this. Another option is to use a variable to represent the first pushed location, set it equal to null initially and then set it equal to the position on the first push. On the 2nd push check if it is null or non-null and if non-null, the button push represents the 2nd push. Then set it back to null.
For example
public void actionPerformed(ActionEvent e) {
for(int x = 0; x < 8; x++) {
for(int y = 0; y < 8; y++) {
if(e.getSource() == squaresGrid[x][y]) {
if (gridLocation == null) {
// class to hold x and y location
gridLocation = new GridLocation(x, y);
} else {
// use gridLocation here
int firstX = gridLocation.getX();
int firstY = gridLocation.getY();
moveTo(e, x, y, firstX, firstY);
gridLocation = null;
}
}
}
}
}

Is it possible to make an Array of Rectangles in Java

I am trying to make a very simple grid in which a user can move through. Through my research i have concluded that the best way to achieve this would be using a two-dimensional array to represent the grid. However i am unsure of how to draw this array to a Jframe or Jpanel if i were to make an array of rectangles.
Many Stackoverflow questions seem to ask simmilar queries but unforunately i have found non that entirely explains how to draw a simple grid of rectangles.
You can make arrays out of everything. Notice how the way to implement an array is
*datatype* [] *arrayname* = new *datatype* [*lengthOfArray*];
Lets say the name of the class that contains the rectangles is RECTANGLE. So if you want an Array, that contains, lets say, 5 rectangles, it would look somewhat like that:
RECTANGLE [] rectangelArray = new RECTANGLE [5];
If you want to take that to a 2 dimensional Level, just add another bracket:
RECTANGLE [][] rectangelMatrix = new RECTANGLE [4][5];
Assuming that by "drawing to the JPanel" you mean that you want to put the rectangles onto the screen, you would then have a for-loop in a for-loop, that would for example call each rectangle to draw itself:
for(int i = 0; i<rectangleMatrix.length; i++){
for(int j = 0; j<rectangleMatrix[i].length; j++){
rectangleMatrix[i][j].draw();
}
}
rectangleMatrix.draw() calls a method that will draw the rectangle based on its coordinates and size. you could also in a similar fashion call a method that will read the information of each rectangle and then draw it based on that information. This will help you seperate between information and drawing purposes in your classes, which is always a good thing to do:
for(int i = 0; i<rectangleMatrix.length; i++){
for(int j = 0; j<rectangleMatrix[i].length; j++){
drawRectangle(rectangleMatrix[i][j]);
}
}
drawRectangle(RECTANGLE toDraw) is in the same class that you have the method with the for-loop in.
In your parent component of grid set layout like
gamePanel.setLayout(new GridLayout(ix, iy));
where ix and iy is dimension size
you also need array of cells private Cell[][] cells; in this case cell is simply
public class Cell extends JPanel{
//some game specific code, fields, constructors
}
now use it
for (int i = 0; i < ix; i++) {
for (int j = 0; j < iy; j++) {
progres.setValue(progres.getValue() + 1);
cells[i][j] = new Cell(i, j, passer);
gamePanel.add(cells[i][j]);
}
}
now if in constructor of cell you will set a border this.setBorder(new LineBorder(Color.GRAY)); grid will appear. in cell constructor or setter method you can also pass whole cells so each cell will be aware of another, and be able to interact with them. but be aware- if you pass it in loop that also create cells, you might encounter a null values.
this way you can use swing components so each cell can be clickable etc.
You can extend a JComponent and overriding its paint(Graphics) method to draw the grid using Graphics.drawLine.
If you need the grid cells to be interactive in some way, then you should probably just create components with rectangular borders and position them using a grid layout.

How to find out which textfield was typed into by the user in a Java JtextField?

I have the following code:
int[] matrix = new int[9][9];
(for int x = 0; x <= 8; x++){
(for int y = 0; y <= 8; x++){
JtextField matrix[x][y] = new JtextField(“Matrix" x + y)
int[] coords = new int[2];
coords[0] = x;
coords[1] = y;
matrix[x][y].putClientProperty("coords", coords);
matrix[x][y].setText(game[x][y]);
}
}
After the loops end, I need a way of finding out which textfield the user typed into (the user also hits enter). So:
1. How do I check if a JtextField has been edited without knowing which one it is or its name?
2. How do I check which "coords" the textfield is positioned at? I have an idea of how to do it, but for some reason I cannot code it.
I feel like the answer is staring me right in the face, but its late, I'm tired, and I'm getting flustered. Thanks!
The answer depends on what you want to achieve.
If you're only interested in the end result, you could use an ActionListener (for when the user hits Enter) and a FocusListener for when they don't and leave the field any way (assuming you want to know this)
When the respective event occurs, you can inspect the source of the event by using getSource. Now this returns Object, but you can use instanceof to determine if the object can be cast to a JTextField...
For example...
Object source = evt.getSource();
if (source instanceof JTextField) {
JTextField field = (JTextField)source;
int[] coords = field.getClientProperty("coords");
}
Take a look at How to write an Action Listener and How to write a Focus Listener for more details.
Depending on your needs, you could also take a look at Validating Input

Rendering from a List<> array

I am trying to render to a JPanel from a list array. I've created my own 2D renderer, but when I try and add to the list using the RenderAdd function, it either doesn't add, or the list array doesn't allow the list to be read...
He's the code which starts it.
JFrame frame = new JFrame();
frame.setSize(900, 500);
frame.setVisible(true);
Render render = new Render(new RenderDimension(frame.getX(),frame.getY(),frame.getWidth(),frame.getHeight()), frame);
BufferedImage zombie = new ImageLoader().readImage("zombie");
BufferedImage player = new ImageLoader().readImage("player");
render.RenderAdd(new RenderImage(new RenderDimension(100, 100, player.getWidth(), player.getHeight()), player));
render.RenderAdd(new RenderImage(new RenderDimension(0, 0, zombie.getWidth(), zombie.getHeight()), zombie));
render.start();
render.RenderAdd(new RenderImage(new RenderDimension(200, 100, player.getWidth(), player.getHeight()), player));
'render' is the main Render class in the rendering part. Then, RenderAdd adds a RenderImage which has RenderDimension which is the x and y of the object, and the image width and height. Then also takes a BufferedImage as a parameter.
Although, every time I try running the program, it comes with a blank screen
Now, in the Render class, there is another class which extends a thread. This is the class which takes the frame as a parameter, deletes the contents and starts painting to the getContentPane(). This next code is inside the paintComponent() function in the renderthread class.
Unfortunately, nothing paints, but is does process because I've tried with System.out.print("h") which repeatedly prints itself.
for (RenderImage r : render.getList()){
int x = r.getSize().getX();
int y = r.getSize().getY();
int wi = r.getSize().getWidth();
int hi = r.getSize().getHeight();
if (x + wi >= -1 && x + wi <= d.getWidth()){
if (y + hi >= -1 && y + hi <= d.getHeight()){
g.drawImage(r.getImage(), x, y, null);
}
}
}
frame.getContentPane().add(p);
frame.getContentPane().validate();
frame.getContentPane().repaint();
I think the problem is that the list won't add, so here's that part.
List<RenderImage> render = new ArrayList<RenderImage>();
public List<RenderImage> getList(){
return render;
}
public void RenderAdd(RenderImage renders){
render.add(renders);
}
It's difficult to know with the example code you've given us.
Scenario #1, overriding JComponent#paintComponent
If you are doing this inside your paintComponent method
for (RenderImage r : render.getList()){
int x = r.getSize().getX();
int y = r.getSize().getY();
int wi = r.getSize().getWidth();
int hi = r.getSize().getHeight();
if (x + wi >= -1 && x + wi <= d.getWidth()){
if (y + hi >= -1 && y + hi <= d.getHeight()){
g.drawImage(r.getImage(), x, y, null);
}
}
}
frame.getContentPane().add(p);
frame.getContentPane().validate();
frame.getContentPane().repaint();
Then DON`T.
Calling any method that updates the UI in any way from within a paint method will only result in disaster. This is simply triggering another repaint request to be added to the Event Dispatching Thread, which will call you paintComponent method and you can say good by to your CPU and program responsiveness.
Also, make sure, when updating the UI from a different Thread other then the EDT, make sure you sync the request back to the EDT using SwingUtilities#invokeLater or SwingUtilities.invokeAndWait
Also, make sure you are calling super.paintComponent
Scenario #2, using JComponent#getGraphics
The question that comes to mind is, where does g come from in your example.
If you're using JComponent#getGraphics, then don't. This is simple a snapshot of the graphics between repaints, as soon as the next repaint occurs, it will be erased.
Create a custom component from something like JPanel and override it's paintComponent method and update the component with your RenderImage loop (just leave out the code that changes the UI)
Also, make sure that all repaint requests are made from within the context of EDT

In Java, is there a way to obtain the component where an event is being handled?

Suppose I have 4 squares colored blue, white, red and green (myComponent) associated with the mouse press event. At one point, the mouse is pressed over one of them - say, the yellow one - and the event is activated.
Now, the control flux is inside the event handling function. How do I get the MyComponent - the yellow square - that caused this from here?
EDIT
I have another question. Is there a way to tell the position of the component? My problem is a bit more complicated than what I said.
Basically, I have a grid full of squares. When I click one of the squares, I have to know which one it is, so I can update my matrix. The thing is, if I calculate it myself, it only works on a given resolution.
I have a GridBagLayout, and inside it are the myComponents. I have to know which one of the components exactly - like, component[2][2] - caused the interruption.
I mean, I can tell which one of the components did it, but not where in the matrix it is located.
MouseEvent.getSource() returns the object on which the event initially occurred.
I have a GridBagLayout, and inside it
are the myComponents. I have to know
which one of the components exactly -
like, component[2][2] - caused the
interruption.
You could store the indices, e.g. (2,2), inside each myComponent when you add them to the matrix. That way, given the component, you can always identify its position in the matrix.
class MyComponent extends JButton
{
final int i; // matrix row
final int j; // matrix col
// constructor
MyComponent(String text, int i, int j)
{
super(text);
this.i = i;
this.j = j;
}
...
}
By adding a MouseListener (or alternatively, a MouseAdapter, if you don't need to override all the MouseListener' methods) to each of your colored boxes, when an event such as a mouse click occurs, theMouseListenerwill be called with a [MouseEvent`]3, which can be used to obtain the component that was clicked.
For example:
final MyBoxComponent blueBox = // ... Initialize blue box
final MyBoxComponent whiteBox = // ... Initialize white box
final MyBoxComponent redBox = // ... Initialize red box
final MyBoxComponent greenBox = // ... Initialize green box
MouseListener myListener = new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
// Obtain the Object which caused the event.
Object source = e.getSource();
if (source == blueBox)
{
System.out.println("Blue box clicked");
}
else if (source == whiteBox)
{
System.out.println("White box clicked");
}
// ... and so on.
}
};
blueBox.addMouseListener(myListener);
whiteBox.addMouseListener(myListener);
redBox.addMouseListener(myListener);
greenBox.addMouseListener(myListener);

Categories

Resources