I was created some program for my school that should contains n*n buttons.
The buttons should be in Matrix layout with n rows and n cols.
So i created the panel, and I created a class named Position that extends JButtons - the buttons I want to add to the panel.
I added layout to the panel:
this.setLayout(new GridLayout(n,n));
And then I am creating n*n Positions buttons and adding them to the panel.
The problem is, that all the buttons are adding to the same place (top left of the screen) - even that I can click them in the places they should be! (see screen shot where n is 4)
I can click on the grey area (empty) even the button is not there:]1
The panel constructor:
public GamePanel(int n) {
super();
this.n = n;
positions = new Position[n][n];
this.setLayout(new GridLayout(n,n));
currX = new Random().nextInt(n);
currY = new Random().nextInt(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
Position p = new Position(i, j);
this.add(p);
positions[i][j] = p;
}
}
The constructor of Position class:
public class Position extends JButton {
private int x;
private int y;
private boolean visited = false;
public Position(int x, int y) {
super("");
this.x = x;
this.y = y;
this.setPreferredSize(new Dimension(50,50));
}
The Frame:
public class Game extends JFrame {
private GamePanel gamePanel;
public Game(int n){
super();
gamePanel = new GamePanel(n);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
this.add(gamePanel,BorderLayout.CENTER);
this.add(new JTextField(),BorderLayout.NORTH);
this.pack();
this.setVisible(true);
}
}
Where can be my mistake?
So, after putting your incomplete example back together, I got...
Then I noticed the x/y properties in your Position buttons, which made me thing that you've probably included getX and getY methods, something like...
public class Position extends JButton {
private int x;
private int y;
private boolean visited = false;
public Position(int x, int y) {
super("");
this.x = x;
this.y = y;
this.setPreferredSize(new Dimension(50, 50));
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Which generated...
So the answer is, include a fully runnable example which demonstrates your problem. This is not a code dump, but an example of what you are doing which highlights the problem you are having. This will result in less confusion and better responses
And don't override getX and getY of the JButton, instead, change the methods to something like getGridX and getGridY
Related
I'm trying to create a JPanel that shows buttons forming a square of X size. I want to have the coordinates in a class that extends JButton, but when doing the extension some serious visual problems appear in the frame. If I remove it and use a normal JButton it doesn't happen.
I didn't find another public question with a similar problem. Can someone help me please?
Edit: Thanks to the comments noticed that I accidentally overridden the 'getX' and 'getY' methods of the Container superclass with my extension, that caused problems when it came to locating the JButtons and displaying them in the frame. Thanks.
import java.awt.GridLayout;
import javax.swing.*;
public class mainclass extends JFrame{
private int size= 10;
private class Button extends JButton{
private int x;
private int y;
public Button(int x, int y) {
super();
this.x= x;
this.y= y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
public mainclass(){
GridLayout gl= new GridLayout(size,size);
JPanel buttonsPane= new JPanel(gl);
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
Button temp= new Button(row,col);
temp.setVisible(true);
buttonsPane.add(temp);
buttonsPane.revalidate();
buttonsPane.repaint();
}
}
buttonsPane.setVisible(true);
getContentPane().add(buttonsPane);
setSize(700,700);
setLocationRelativeTo(null);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setTitle("Buscaminas");
this.setVisible(true);
}
public static void main(String[] args) {
mainclass mc = new mainclass();
mc.setVisible(true);
}
}
I'm writing a program that displays a circle every time you click the Jpanel. I have it all set up and I want to be able to use the drawCircle method I created in my circle class to draw the circles in the paintComponent method. I'm storing all of the circles created in a linked list. Then I interate through each Circle in the list and try to use the method in my Circle class called drawCircle().
For some reason, if I try to use c1.drawCircle() in a for loop in the My panel class it only draws the last circle that was created. But if I just use g.fillOval(with the correct parameters grabbing the values from the Circle class) in the for loop it works properly and displays all the circles. Why is it doing this and how do I go about using the method in the Circle class properly
I'm unsure what to try right now.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.LinkedList;
public class MouseTest {
private int borderWidth = 20;
private JFrame frame;
private boolean tracking;
private boolean start;
private boolean clearBol;
private int xstart;
private int ystart;
private int xend;
private int yend;
private LinkedList<Circle> circles;
public MouseTest() {
tracking = false;
start = false;
circles = new LinkedList<Circle>();
frame = new JFrame();
frame.setBounds(250, 98, 600, 480);
frame.setTitle("Window number three");
Container cp = frame.getContentPane();
JButton clear = new JButton("Clear");
JToggleButton circleButton = new JToggleButton()("Circles");
JToggleButton drawButton = new JToggleButton("Draw");
ButtonGroup circleOrDraw = new ButtonGroup();
MyPanel pane = new MyPanel();
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
clearBol = true;
frame.repaint();
}
});
JPanel top = new JPanel();
top.setLayout(new FlowLayout());
top.add(clear);
circleOrDraw.add(circleButton);
circleOrDraw.add(drawButton);
top.add(circleOrDraw);
cp.add(top, BorderLayout.NORTH);
cp.add(pane, BorderLayout.CENTER);
pane.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
xstart = e.getX();
ystart = e.getY();
start = false;
}
public void mouseReleased(MouseEvent e) {
xend = e.getX();
yend = e.getY();
if (xend < xstart) {
int tmp = xstart;
xstart = xend;
xend = tmp;
}
if (yend < ystart) {
int tmp = ystart;
ystart = yend;
yend = tmp;
}
start = true;
frame.repaint();
}
});
pane.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
if (tracking) {
int x = e.getX();
int y = e.getY();
msg("(" + x + ", " + y + ")");
}
}
});
frame.setVisible(true);
} // constructor
public static void main(String[] arg) {
MouseTest first = new MouseTest();
} // main
public void msg(String s) {
System.out.println(s);
}
public void trackMouse() {
tracking = !tracking;
} // trackMouse
public class Circle extends JPanel {
Graphics g;
int x;
int y;
int r;
Color color;
public Circle(Graphics g, int x, int y, int r) {
this.g = g;
this.x = x;
this.y = y;
this.r = r;
int red = (int) (256 * Math.random());
int green = (int) (256 * Math.random());
int blue = (int) (256 * Math.random());
this.color = new Color(red, green, blue);
}
public void drawCircle() {
int x2 = x - (r / 2);
int y2 = y - (this.r / 2);
g.setColor(color);
g.fillOval(x2, y2, this.r, this.r);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
public int getR() {
return r;
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
if (start) {
circles.add(new Circle(g, xend, yend,
(int) ((250 * Math.random() + 4))));
//Area where I'm having issues
for (Circle c1 : circles) {
msg("" + c1.getX());
// this method that I created in the circle class will only draw the first circle
//c1.drawCircle();
int r = c1.getR();
int x = c1.getX();
int y = c1.getY();
g.setColor(c1.getColor());
g.fillOval((c1.getX() - (r / 2)), (c1.getY() - (r / 2)),
r, r); // this will display all the circles
}
int size = circles.size();
msg(size + " Size");
msg("" + circles.getLast().getX());
}
if (clearBol) {
super.paintComponent(g);
circles.clear();
clearBol= false;
}
Thank you!
Most of the structure of your class needs to be changed
Your MyPanel should have a better name to give its functionality, maybe something like DrawingPanel.
The DrawingPanel is then responsible for managing the Circles to be painted. So typically you would just use an ArrayList to hold the Circle information.
Then you would add a method to the class, like addCircle(...) to add the Circle information to the ArrayList and then invoke repaint().
Then in your paintComponent(...) method the first thing you do is invoke super.paintComponent(...) to clear the panel. Then you iterate through the ArrayList and paint all the Circles. There will be no need for the Boolean values to check the state of the class. The ArrayList will either have circles or it won't.
You would also need a method like clearCircles(). This would simply remove all the Circles from the ArrayList and invoke repaint() on itself.
Your Circle class should NOT extend JPanel. It should just be a class that contains the information need to paint the circle: x/y location, size of circle and color of circle.
Now your frame is responsible of displaying your DrawingPanel and the buttons.
When you click the "Clear" button you simply invoke the clearCircles() method of the DrawingPanel.
For your MouseListener you simply invoke the addCircle(...) method of your DrawingPanel once you have all the information needed to create a Circle instance.
For a complete working example that incorporates all these suggestions check out the DrawOnComponent example found in Custom Painting Approaches
I use a JPanel with GridLayout and I put JLabel inside. Everithing works. But I want to use my own class (extends JLabel) there is a problem.
When I use a JLabel I have this rendering:
And when I use my own JLabel I have that:
Here is my code from my JLabel custom :
public class LabelCustom extends JLabel{
int x;
int y;
public LabelCustom(int x, int y) {
super();
this.x = x;
this.y = y;
this.setBackground(Color.white);
this.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
And how I use it :
JPanel j = new JPanel();
j.setLayout(new GridLayout(nbCaseY, nbCaseX));
for(int i=0; i<nbCaseY; i++) {
HashMap<Integer, JLabel> ligne = new HashMap();
for(int y=0; y<nbCaseX; y++) {
LabelCustom p = new LabelCustom(i, y);
p.addMouseListener(ml);
//p.setBounds(100+ y*(hauteur), 100 + i*( hauteur), hauteur, hauteur);
p.setPreferredSize(new Dimension(hauteur, hauteur));
//p.setBounds(100+ y*( (width-200-2*hauteur)/nbCaseX), 100 + i*( (height-200)/nbCaseY), ((width-200-2*hauteur)/nbCaseX), ((height-200)/nbCaseY));
p.setTransferHandler(new TransferHandler("icon"));
p.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
p.setOpaque(true);
p.setVisible(true);
j.add(p);
ligne.put(y, p);
}
Frame.p.getListeNiveau().get(0).ajouterLigne(ligne);
}
JLabel already has a getX and getY method which is to position the label on the screen, you've (unwittingly) overridden this functionality and are now returning unrelated information.
It's not for x and y position. It is for an id of hashmap, i think it is useful ;)
So, instead of using getX/Y, I suggest making a ID class, which carries the information you need (possibly overriding the equals and hashcode methods to make it easier to do comparisons) and using that instead (providing a getID and setID methods)
I am having some trouble getting both the squares I created in the program, and the ImageIcon imported to show up on my JPanel. I have been at this for a while now, and still am unable to figure out what I can do to make them show up, and allows the player image to move. Here is the first piece of my code which is the Maze class:
public class Maze extends JPanel{
int[][][] mazeArray; //will be defined in the loop depending on how many rectangles are spawned, also for making sure the player can't walk over the walls (first is what number wall it is, second is the x coordiante of the wall, and third is the y coordinate of the wall)
//depending on whether or not the rctangle is vertical or horizontal it will use both values for its height and width (vertical would have sideX for the height, and sideY for the width; this would be the opposite for the horizontal rectangle)
int sideX = 50; //x side length
int sideY = 50; //y side length
int x;
int y;
//setters and getters for use later (for changing the rctangles location and size)
public void setSideX(int sideX){
this.sideX = sideX;
}
public int getSideX(){
return sideX;
}
public void setSideY(int sideY){
this.sideY = sideY;
}
public int getSideY(){
return sideY;
}
public void setCoordinates(int x, int y){
this.x = x;
this.y = y;
}
public void setX(int x){
this.x = x;
}
public int getX(){
return x;
}
public void setY(int y){
this.y = y;
}
public int getY(){
return y;
}
//end setters and getters
public void generateMaze(){
//the left side of the maze
for(int i = 0; i < 10; i++){ //ten blocks on the left side
setX(0); //x is always 0 for the left side
setY(getY() + 50); //adds 50 to the previous Y coordinate amount, m making it go down the whole left side
}
setY(0); //set y back to zero to be able to start the right column of blocks
//the right side of the maze
for(int i = 0; i < 10; i++){
setX(500); //x is always 500 for the right side
setY(getY() + 50); //does the same as it did on the left side, except on the right
}
setY(0); //set y to zero again
setX(50); //start x at 50 since there is no need to remake the corners
for(int i = 0; i < 8; i++){ //only goes up to 8 this this time because the corners of the maze can be ignored
setY(0); //just in case y changes back
setX(getX() + 50); //x increases by 50 each time
}
setY(500);
setX(50);
for(int i = 0; i < 8; i++){ //same as above except for the bottom
setY(500);
setX(getX() + 50);
}
//the maze walls are now generated
}
public void paintComponent(Graphics g){ //for painting the rectangles
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(getX(), getY(), sideX, sideY); //uses x and y coordinates defined in the generateMaze loop, and the uses whatever current value for the two side, depending on what type of rectangle it is
}
}
This is what I am using to create the mazes walls. Now comes the Player class which deals with the player image, player coordinates, and the player's movement speed:
public class Player {
//Player starts in the top left corner
int playerX = 50;
int playerY = 50;
int moveSpeed = 5; //I can edit move speed here
Image character;
//getters and setters to utilize the player's location and image
public Player(){ //constructor for initial starting points
playerX = 50;
playerY = 50;
ImageIcon player = new ImageIcon("E://Workspace//Maze//images//Player.jpg");
character = player.getImage();
}
public void setPlayerX(int playerX){
this.playerX = playerX;
}
public int getPlayerX(){
return playerX;
}
public void setPlayerY(int playerY){
this.playerY = playerY;
}
public int getPlayerY(){
return playerY;
}
public void setMoveSpeed(int moveSpeed){
this.moveSpeed = moveSpeed;
}
public int getMoveSpeed(){
return moveSpeed;
}
public Image getPlayerImage(){
return character;
}
}
Next is where I think the problem is occurring for the player's image (for the maze I think it is something in the Maze class itself, although it could be a problem in the Layout class as well):
public class Layout extends JPanel implements ActionListener { //GUI with a non null FlowLayout
Maze m = new Maze();
Player p = new Player();
//500 x 500 seemed like a good size for the maze game
int x = 500;
int y = 500;
Image player;
JPanel panel;
public Layout() {
panel = new JPanel();
panel.setLayout(new FlowLayout()); //same as the JFrame
panel.addKeyListener(new Move(p));
panel.setFocusable(true);
panel.setBackground(Color.YELLOW); //background of the maze
m.generateMaze(); //create the maze
}
//for use in setting and getting the borders of the game
public void setX(int x){
this.x = x;
}
public int getX(){
return x;
}
public void setY(int y){
this.y = y;
}
public int getY(){
return y;
}
public JPanel getPanel(){
return panel;
}
#Override //so it can repaint as needed
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(p.getPlayerImage(), p.getPlayerX(), p.getPlayerY(), this);
}
public void actionPerformed(ActionEvent ae){
repaint();
}
}
class Move implements KeyListener { //for player movement
final Player p;
Move(Player p){
this.p = p;
}
public void keyPressed(KeyEvent press) { //for the movement in the game
//I used both keys so that if the player woukld like to use WASD or the arrow keys either will work
if(press.getKeyCode() == KeyEvent.VK_W || press.getKeyCode() == KeyEvent.VK_UP){
//move up
p.setPlayerY(p.getPlayerY() - p.getMoveSpeed());
}
else if(press.getKeyCode() == KeyEvent.VK_S || press.getKeyCode() == KeyEvent.VK_DOWN){
//move down
p.setPlayerY(p.getPlayerY() + p.getMoveSpeed());
}
else if(press.getKeyCode() == KeyEvent.VK_A || press.getKeyCode() == KeyEvent.VK_LEFT){
//move left
p.setPlayerX(p.getPlayerX() - p.getMoveSpeed());
}
else if(press.getKeyCode() == KeyEvent.VK_D || press.getKeyCode() == KeyEvent.VK_RIGHT){
//move right
p.setPlayerX(p.getPlayerX() + p.getMoveSpeed());
}
}
public void keyReleased(KeyEvent release) {
//nothing is needed here
}
public void keyTyped(KeyEvent e) {
//does nothing if a key is type (no need for it)
}
}
Lastly is the class that runs it, although I don't think there is any issue here, but just in case I will throw it in here anyway:
public class Play extends JPanel {
public static void main(String[]args) {
play();
}
public static void play() {
JFrame f = new JFrame();
Layout l = new Layout();
JPanel j = l.getPanel();
f.setTitle("Maze Game for final project");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(l.getX(), l.getY()); //size can be changed in layout
f.setVisible(true);
f.add(j); //adds the panel
}
}
I am trying to be able to have the player's image spawn at 50, 50 on start up, and then also have the walls spawn at start up as well. However currently the only thing that is showing up for the JPanel is the yellow background. Help would be greatly appreciated!
New updated code here:
public static void play() {
JFrame f = new JFrame();
Layout l = new Layout();
f.setTitle("Maze Game for final project");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(l.getX(), l.getY()); //size can be changed in layout
f.add(new Layout()); //adds the panel
f.setVisible(true);
}
and also for the Layout constructor
public Layout() {
setLayout(new FlowLayout());
addKeyListener(new Move(p));
setFocusable(true);
setBackground(Color.YELLOW);
m.generateMaze();
}
I can't say that I've gone through all of your code, but one thing did strike me:
Your Layout class extends JPanel and overrides paintComponet, but you never use this class as a JPanel. Instead you use some other JPanel variable within it called panel. Get rid of that variable and instead use the JPanel that is the Layout class itself, and at least some of your problems may be fixed.
e.g.,
public class Layout extends JPanel implements ActionListener {
Maze m = new Maze();
Player p = new Player();
int x = 500;
int y = 500;
Image player;
// JPanel panel;
public Layout() {
// panel = new JPanel();
// panel.setLayout(new FlowLayout()); //same as the JFrame
// panel.addKeyListener(new Move(p));
// panel.setFocusable(true);
// panel.setBackground(Color.YELLOW); //background of the maze
setLayout(new FlowLayout());
addKeyListener(new Move(p));
setFocusable(true);
setBackground(Color.YELLOW);
m.generateMaze();
}
public void setX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
// public JPanel getPanel() {
// return panel;
// }
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(p.getPlayerImage(), p.getPlayerX(), p.getPlayerY(), this);
}
public void actionPerformed(ActionEvent ae) {
repaint();
}
}
Another problem is your use of KeyListeners since Key Bindings would be much preferable here, but I'll leave that for your next question.
Also, you're adding your JPanel to the JFrame after calling setVisible(true) on the JPanel -- don't do this. Call setVisible(true) only after adding all components.
It worked an hour ago, but I must have done something to the code and I have no idea what. My JTextFields don't show up, but if I set them to editable, they're still there. The first JTextField does show up, but looks weird. Any ideas what's wrong? (I call my JTextFields "Square"). Size = 10
package gui;
import javax.swing.*;
import engine.GameEngine;
import java.awt.*;
import java.util.*;
public class MineFieldGUI extends JFrame {
private GameEngine engine;
Square[][] field;
int size = 10;
public MineFieldGUI(GameEngine minefield) {
super("MineField");
this.engine = minefield;
this.size = minefield.getSize();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setSize(300, 350);
Locale.setDefault(new Locale("en"));
setLayout(new BorderLayout());
JMenuBar menubar = new JMenuBar();
setJMenuBar(menubar);
JMenu helpMenu = new JMenu("Help");
menubar.add(helpMenu);
helpMenu.add(new HelpMenu(this));
//***THE MINE-FIELD***
JPanel panel = new JPanel(new GridLayout(size,size));
field = new Square[size][size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
field[i][j] = new Square(i, j);
panel.add(field[i][j]);
}
}
add(panel, BorderLayout.CENTER);
setVisible(true);
}
public void setColor(int x, int y){
field[x][y].setBackground(Color.lightGray);
}
public void setText(int x, int y, String text){
field[x][y].setText(text);
}
public String getText(int x, int y){
return field[x][y].getText();
}
}
My textFields:
package gui;
import java.awt.Color;
import javax.swing.JTextField;
public class Square extends JTextField {
int posX;
int posY;
public Square(int x, int y) {
super("");
posX = x;
posY = y;
this.setEditable(false);
this.setBackground(Color.lightGray);
}
public int getX(){
return posX;
}
public int getY(){
return posY;
}
}
Remove the methods getX and getY which are being used by the layout manager to position the Square components. This will let the layout manager correctly position the buttons.