Java Swing - Position measure unit? - java

I'm making a chess game, and I'm using a chessboard that I made with paint at 480x480, and got the pieces from some sprite and made each one of them 60x60 and transparent background. I managed to put the chessboard and the pieces on screen, but the positions are messy. I'm using null layout. I did:
chessBoardLabel.setBounds(0, 0+25, 480, 480);
the +25 is because of the Frame's thing that is on top and looks like it is considered in positioning.
as for the piece, for example:
for (int i = 0; i <= 7; i++)
whitePawnArray[i] = new whitePawnPiece(i*60,420+25);
the parameters set the xPos and yPos. For the bounds function, I did:
whitePawnLabel.setBounds(this.xPos, this.yPos, this.xPos+60, this.yPos+60);
But this happens:
If I do that:
for (int i = 0; i <= 7; i++)
whitePawnArray[i] = new whitePawnPiece(i*40,280+15);
this happens:
First: what happened to the positioning? Why doesn't it follow what I intended it to be?
Second: what is the 8th piece doing in the middle of nowhere?
package chess.game;
import java.util.*;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class chessMain extends JFrame{
public static void main (String arguments[]){
//Create White
whitePiece white_piece = new whitePiece();
whitePawnPiece[] whitePawnArray = new whitePawnPiece[8];
for (int i = 0; i <= 7; i++) whitePawnArray[i] = new whitePawnPiece(i*40,280+15);
/*whiteTowerPiece[] whiteTowerArray = new whiteTowerPiece[2];
whiteTowerArray[0] = new whiteTowerPiece(0,420);
whiteTowerArray[1] = new whiteTowerPiece(420,420);
whiteHorsePiece[] whiteHorseArray = new whiteHorsePiece[2];
whiteBishopPiece[] whiteBishopArray = new whiteBishopPiece[2];
whiteKingPiece whiteKing = new whiteKingPiece();
whiteQueenPiece whiteQueen = new whiteQueenPiece();*/
//Create Black
JFrame frame = new JFrame();
JPanel panel;
//Initialize
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Chess");
frame.setSize (640,640);
frame.setResizable(false);
frame.setLayout(null);
panel = new JPanel();
panel.setLayout(null);
frame.getContentPane().add(panel);
//draw chessBoard
ImageIcon chessBoardIcon = new ImageIcon(frame.getClass().getResource("/chess/art/Chess_Art/chessBoard.png"));
JLabel chessBoardLabel = new JLabel(chessBoardIcon);
panel.add(chessBoardLabel);
chessBoardLabel.setBounds(0, 0+25, 480, 480);
frame.setComponentZOrder(chessBoardLabel, 1);
frame.setComponentZOrder(panel, 2);
//draw Pawn
for (int i = 0; i<=7; i++){
panel.add(whitePawnArray[i].whitePawnLabel);
whitePawnArray[i].draw();
frame.setComponentZOrder(whitePawnArray[i].whitePawnLabel, 0);
}
frame.setVisible(true);
}
}
public class whitePawnPiece extends whitePiece{
JLabel whitePawnLabel;
ImageIcon whitePawnIcon;
public whitePawnPiece(int x, int y){
whitePawnIcon = new ImageIcon(getClass().getResource("/chess/art/Chess_Art/white/whitePawnPiece.png"));
whitePawnLabel = new JLabel (whitePawnIcon);
//whitePawnLabel.setOpaque(true);
this.xPos = x;
this.yPos = y;
//this.draw();
}
#Override
public void move(int newX, int newY){
this.xPos = (newX/60)*60; //calcular nova pos
this.yPos = (newY/60)*60;
this.draw();
}
/*public void possibleMoves(){
selectorMark.drawNew(this.xPos, this.yPos);
selectorMark.drawNew(this.xPos - 60, this.yPos - 60);
if (this.yPos == 420) selectorMark.drawNew(this.xPos - 120, this.yPos - 120);
}*/
#Override
public void draw(){
//whitePawnIcon.paintIcon(null, chessGUI2.getGraphics(), xPos, xPos);
whitePawnLabel.setBounds(this.xPos, this.yPos, this.xPos+60, this.yPos+60); //x, y, width, height
}
}
public class whitePiece{
int xPos, yPos;
public void move(){}
public void draw(){}
}
First time putting whole code hope I edited it right hehe

Don't use CardLayout for this.
I'd use a JPanel that uses GridLayout to hold an 8x8 grid of chess square JPanels.
I'd place that in a JLayeredPane.
I'd add my pieces to the appropriate chess square JPanel.
When moving a piece, I'd lift it up to the drag layer of the JLayeredPane.
Also:
Don't draw directly on to a top-level window such as a JFrame.
Don't override the paint method.
Instead, if you must do drawing, override the paintComponent(Graphics g) of a JPanel or JComponent.
But again, if you create your chess board out of small JPanel chess squares, it is easy and natural to place pieces on the chess square and have it placed well.
For example, please check out my code here.

Related

JLabel duplicates itself

I'm trying to replicate an existing game for learning purposes. The code below creates a JFrame with squares that will be filled with labels and images, however, the "Start" label seems to replicate itself. I have some experience with Java, but I'm still a student. (Nearly no experience with Swing). I added the label to the frame instead of the panel because the squares I drew hide the label. Thanks :D
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Test{
public static void main(String[] args){
JFrame frame = new JFrame("Miau");
MyPanel panel = new MyPanel();
frame.setVisible(true);
frame.setSize(600,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
JLabel labelstart = new JLabel("Start");
frame.add(labelstart);
labelstart.setLocation(100, 100);
labelstart.setSize(30,14);
}
}
class MyPanel extends JPanel {
public void paint(Graphics g) {
g.setColor(Color.black);
//g.fillRect(10,10,570,100);
int posx = 10;
int posy = 120;
g.drawRect(10,10,570,100);
g.drawRect(posx,posy,570,430);
int size = 5;
int width = 570/size;
int height = 430/size;
for(int m=0;m<size;m++){
for(int n=0;n<size;n++){
g.drawRect(posx,posy,width,height);
posx += width;
}
posx = 10;
posy += height;
}
}
}
I found a valid solution to my problem. I used label.setBounds(positionx,positiony,boundx,boundy). I'm trying to make a simple game that uses a refreshing JPanel, and it's working.

Method mousePressed() in Java doesn't seem to be working

I am writing a program, and the mouse listener, mousePressed(), does not seem to respond. I have written a few GUI programs now, and having compared this code, I do not see any significant difference that would explain the lack of mouse listening. The following code is incomplete and has portions that are meant for testing functionality only, and some of it may not make sense. I just need to know why mousePressed() is not working.
/**This class creates a panel that draws a polygon with as many vertices as the user desires. It will have a button that tells the component to close the
polygon. Vertices are chosen with clicks of the mouse on the drawing surface.*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PolygonDraw extends JPanel implements ActionListener{
DrawPanel drawingSurface;
int[][] coordinates, oldCoordinates;
int indices = 1;
static int x = 50;
public PolygonDraw(){
//create painting panel.
setLayout(new BorderLayout());
drawingSurface = new DrawPanel();
add(drawingSurface, BorderLayout.CENTER);
JButton closePoly = new JButton("Close the Polygon");
closePoly.addActionListener(this);
JButton clear = new JButton("Clear");
clear.addActionListener(this);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(0,1));
buttonPanel.setBorder(BorderFactory.createEtchedBorder());
buttonPanel.add(clear);
buttonPanel.add(closePoly);
add(buttonPanel, BorderLayout.SOUTH);
}
private class DrawPanel extends JPanel{
public void DrawPanel(){
addMouseListener(new MouseAdapter(){
/**
This creates an array containing coordinates for every mouse press. Logic in this allows for the creation of array that get larger and larger as more
vertices are created by the user.
*/
public void mousePressed(MouseEvent evt){//compile list of vertices
//create the last element in the array.
//create an array with i elements
/*coordinates = new int[indices][2];
coordinates[indices - 1][0] = evt.getX();
coordinates[indices - 1][1] = evt.getY();
if (oldCoordinates != null){
for (int i = 0; i < indices - 1; i++){
coordinates[i][0] = oldCoordinates[i][0];
coordinates[i][1] = oldCoordinates[i][1];
}
}
oldCoordinates = coordinates;
indices++;*/
x += 5;
repaint();
}
});
}
public void paintComponent(Graphics g){//draw lines between vertices, finish polygon, and fill polygon in with a color.
//int x, y;
//super.paintComponent(g);
/*g.setColor(Color.BLACK);
for(int i = 0; i <= indices; i++){
x = coordinates[i][0];
y = coordinates[i][1];
g.fillOval(x + 2, y + 2, 4, 4);
}
*/
g.fillRect(x,50,50,50);
}
}
public void actionPerformed(ActionEvent evt){//Clear drawing area, or close vertices to make polygon.
}
}
public void DrawPanel() { is not a valid constructor, it's just a normal method.
You should be using something more like public DrawPanel() {, this way the MouseListener will be registered when you create a new instance of the class
Also, make sure you're calling super.paintComponent, otherwise you will end up with a bunch of other issues...
#Override
protected void paintComponent(Graphics g) {//draw lines between vertices, finish polygon, and fill polygon in with a color.
super.paintComponent(g);

GUI Using JFrame, & JPanel drawing custom shapes

Pretty much I create a Shape class, with Rectangle, Circle, Triangle extending Shape, and a Square class extending Circle. I have the code working with this main class, but I'm having a tough time converting it into GUI because I'm not sure how to do number 3 to make this come together and how to make a g.drawOval(with given x,y & radius) and draw triangle(given x,y, base and height).
Project6 class will have to extend the JFrame class
Project6 constructor will have to set up the GUI window.
A new abstract method: public void display(Graphics g); should be added to the base and derived classes.
A custom JPanel must be set up with a paintComponent method
The new display(Graphics g) method will have to draw the shapes on the GUI window and be called from a loop in the paintComponent method.
import javax.swing.*;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Project6 extends JFrame {
private Shape [] thearray = new Shape[100];
public static void main (String [] args) {
Project6 tpo = new Project6();
tpo.run();
}
public void run () {
int count = 0;
thearray[count++] = new Circle(20, 20, 40);
thearray[count++] = new Triangle(70, 70, 20, 30);
thearray[count++] = new Rectangle(150, 150, 40, 40);
thearray[count++] = new Square(100, 100, 50, 75);
for (int i = 0; i < count; i ++ ) {
thearray[i].display();
}
int offset = 0;
double totalarea = 0.0;
while (thearray[offset] != null) {
totalarea = totalarea + thearray[offset].area();
offset++;
}
System.out.println("The total area for " + offset + " Shape objects is " + totalarea);
}
public Project6() {
JFrame frame = new JFrame();
frame.setSize(800, 700);
frame.setTitle("Shapes: Circle, Triangle, Rectangle, Square");
frame.setLocationRelativeTo(null); //Center Frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static class MyPanel extends JPanel {
public static JPanel showJPanel(Graphics g) {
panel = new MyPanel();
return panel;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for(int i = 0; i < thearray.length && thearray[i] != null; i++) {
thearray[i].display();
Do I add something like this at the end of each of my classes? I.E. Circle, Square, Triangle, Rectangle class?
#Override
public void draw(Graphics g) {
g.drawRect(getXPos(), getYPos(), width, height);
}
I can't change the way the array is set up, but isn't this supposed to be the class that extends JFrame?
public Project6() {
JFrame frame = new JFrame();
frame.setSize(800, 700);
frame.setTitle("Shapes: Circle, Triangle, Rectangle, Square");
frame.setLocationRelativeTo(null); //Center Frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
I'm new to GUI so this is a little hard to do, but would this work for drawing the shapes? But I get an error saying nonstatic method get() cant be referenced from static context
class NewPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawLine(Triangle.getXPos(), 0, 0, Triangle.getYPos());
g.drawLine(Triangle.getXPos(), 0, Triangle.getXPos, Triangle.getYPos());
g.drawLine(Triangle.getXPos(), Triangle.getYPos, 0, Triangle.getYPos());
g.drawRect(Rectangle.getXPos(), Rectangle.getYPos(), Rectangle.getWidth(), Rectangle.getHeight());
g.drawRect(Square.getXPos(), Square.getYPos(), Square.getWidth(), Square.getHeight());
g.drawOval(Circle.getXPos(), Circle.getYPos(), Circle.getRadius(), 10);
for(int i = 0; i < thearray.length && thearray[i] != null; i++) {
thearray[i].display();
}
}
Your class extends a JFrame that is never displayed
You should draw your shapes in the paintComponent method of a JPanel, one that is added to your JFrame.
I would use an ArrayList<Shape>, not an array, since this way I'd be able to add as many or as few Shapes to my collection and not have to worry about null items.
I'd then iterate through the collection in the paintComponent method override and draw each Shape using a Graphics2D object.
Regarding your last question, "Do I add something like this at the end of each of my classes? ie(Circle, square, triangle, rectangle class?..." no, there's no need for a "draw" method since you'll be using the paintComponent method to do your drawing.

Multi-threaded bouncing balls, issue displaying balls

I'm trying to use multithreading to draw balls that bounce around inside a JFrame. I can get the coordinates of each ball to update and print out, but I can't get the balls to display. I'm not very strong in graphics, and I'm not quite sure what I'm missing. I think I need to add each instance of Ball to the panel I have inside my frame, but when I tried that it didn't make a difference. I also have a class used to view the JFrame, that I've omitted. What am I missing here?
Ball
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JPanel;
public class Ball extends JPanel implements Runnable {
JPanel pan;
private static int radius = 10;
private Color color;
private int xPos;
private int yPos;
private int dx;
private int dy;
Dimension d;
public Ball(JPanel p) {
Random r = new Random();
this.pan = p;
this.d = pan.getSize();
xPos = r.nextInt(d.width-50)+25;
yPos = r.nextInt(d.height-50)+25;
dx = r.nextInt(3)+1;
dy = r.nextInt(3)+1;
color = new Color(r.nextInt(255*255*255));
paintComponent(pan.getGraphics());
}
public void move() {
xPos += dx;
yPos += dy;
if (xPos+radius <= 0 || xPos+radius >= d.width)
dx = -dx;
if (yPos+radius <= 0 || yPos+radius >= d.height)
dy = -dy;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillOval(xPos-radius, yPos-radius, 2*radius, 2*radius);
g.dispose();
}
public void animate() {
paintComponent(pan.getGraphics());
move();
//pan.validate();//this didn't
//pan.repaint();// work
try {
Thread.sleep(40);
} catch (InterruptedException e) {}
}
public void run() {
while(true)
animate();
}
}
BallTracker
import java.util.ArrayList;
public class BallTracker {
private ArrayList<Ball> balls;
public BallTracker() {
balls = new ArrayList<Ball>();
}
public void addBall(Ball b) {
balls.add(b);
Thread t = new Thread(b);
t.start();
}
}
BallFrame
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BallFrame extends JFrame {
public static final int WIDTH = 500;
public static final int HEIGHT = 550;
private BallTracker tracker;
private JPanel ballPanel;
private JPanel buttonPanel;
public BallFrame() {
super("BallFrame");
tracker = new BallTracker();
// set up ball panel
ballPanel = new JPanel();
ballPanel.setSize(WIDTH, 500);
// listener to add a new ball to tracker
class bListener implements ActionListener {
public void actionPerformed( ActionEvent event ) {
Ball b = new Ball(ballPanel);
tracker.addBall(b);
}
}
// set up button panel
buttonPanel = new JPanel();
buttonPanel.setSize(WIDTH, 50);
JButton addBallButton = new JButton();
addBallButton.setText("Add ball");
addBallButton.addActionListener(new bListener());
buttonPanel.add(addBallButton);
// add panels to frame
add(buttonPanel, BorderLayout.SOUTH);
add(ballPanel, BorderLayout.CENTER);
setSize( WIDTH, HEIGHT );
}
}
It seems your ball extends jpanel and has a paint method, but your ballPanel would need to do the painting and your ball doesn't really seem to need to be a panel at all.
set up ball panel
ballPanel = new JPanel();
ballPanel.setSize(WIDTH, 500);
I was mainly looking for issues with the way I am trying to draw here, and why I don't see a ball
The Ball isn't added to any panel.
Even when you do add the ball to the panel, the Ball has no size, so there is nothing to paint.
Even if you did give the panel a size only one Ball would ever show up because you Ball panel is opaque.
Your code is attempting to paint the ball at a location within the ball panel. Instead you should be painting the ball at location (0, 0) within your ball panel and then set the location of the Ball panel relative to the parent container.
The parent container should be using a null layout so you can randomly set the location of your Ball panel.
I'm sure there are other issues as well...
I suggest you forget about multithreading and start with the basics of custom painting and using Timers.

Trying to add a dynamically positioned image in a JPanel on a button click

I am trying to add/draw a single Graphics object to an existing JPanel. I am generating 10 initial Graphics objects randomly sized and place in the panel, but would like to add additional drawn objects one a time, randomly sized and placed like the initial 10.
Currently, the AddNewDrawItem class is not rendering the new Graphics object.
Thank you for input.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class Painter{
private DrawingPanel dp = new DrawingPanel();
//constructor
public Painter(){
buildGUI();
}
private void buildGUI(){
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
frame.setTitle("Paint drawing demonstration");
JPanel headerPanel = new JPanel();
headerPanel.add(new JLabel("The drawing panel is below"));
JButton addNew = new JButton("Add New Graphic");
addNew.addActionListener(new addNewClickHandler());
headerPanel.add(addNew);
frame.add(BorderLayout.NORTH,headerPanel);
frame.add(BorderLayout.SOUTH,this.dp);
frame.pack();
frame.setVisible(true);
}
class DrawingPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.white);
int x, posx, posy, width, height;
for(x=0;x<=10;x++){
//even number differentiation
if(x % 2 == 0){
g.setColor(Color.red);
}else{
g.setColor(Color.blue);
}
Random rand = new Random();
posx = rand.nextInt(300);
posy = rand.nextInt(300);
width = rand.nextInt(40);
height = rand.nextInt(40);
//System.out.println("the ran x pos is: " + posx);
g.fillRect(posx, posy, width, height);
}//end for
}//end paintComponent
public Dimension getPreferredSize() {
return new Dimension(400,400);
}
}// end DrawingPanel
private class addNewClickHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
System.out.print("in addNew_click_handler click handler");//trace debug
AddNewDrawItem newItem = new AddNewDrawItem();
newItem.repaint();
System.out.print("after repaint() in addNew_click_handler click handler");//trace debug
}
}
class AddNewDrawItem extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.white);
int posx, posy, width, height;
Random rand = new Random();
posx = rand.nextInt(300);
posy = rand.nextInt(300);
width = rand.nextInt(40);
height = rand.nextInt(40);
g.setColor(Color.cyan);
g.fillRect(posx, posy, width, height);
}//end paintComponent
}//end AddNewDrawItem
public static void main(String args[]){
new Painter();
}
}//end class Painter
You've got some problems with your code, one of which is that you've got program logic in your paintComponent method: the code randomly changes values that are displayed within this method, meaning your display will change when it repaints, whether you want it to or not. To see that this is so, try to resize your GUI and you'll see some psychedelic changes in the drawn red and blue rectangles.
Now as to your current problem, the solution to it is similar to the solution to the problem I describe above. I suggest...
that you create an ArrayList<Rectangle2D>,
that you create your random rectangles in your class's constructor so that they're created only once, and then place them in the ArrayList above.
that you iterate through this ArrayList in your JPanel's paintComponent method, drawing them as you go. This way paintComponent does nothing but paint which is as it should be,
that you create a MouseAdapter-derived object and add it as a MouseListener and MouseMotionListener to your DrawingPanel
that you use the listener above to create a new Rectangle2D object and when done add it to the ArrayList and call repaint on the DrawingPanel
that you activate the mouse adapter via your button's action listener.
I'll stop there, but I think you get the idea, and if you don't, please ask any questions you may have.

Categories

Resources