Draw lines, circles anything (Java) - java

so i'm new in stackoverflow.
I am about to create a line, a triangle anything, but i'm just focusing on the line and in a good Object orient Programming.
So i create the class Point2D:
package draw;
/**
*
* #author Pedro
*/
public class Point2D {
private int x,y;
// Construtores
public Point2D(){
this(0,0);
}
public Point2D(int x, int y){
this.x=x;
this.y=y;
}
// Set's e Get's
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;
}
Later i create the class line using the class point2D to get the starting point and final point
package draw;
/**
*
* #author Pedro
*/
public class Linha extends Figura{
private Point2D pinicial;
private Point2D pfinal;
//construtores
public Linha(int xinicial, int yinicial, int xfinal, int yfinal){
pinicial=new Point2D(xinicial, yinicial);
pfinal=new Point2D(xfinal, yfinal);
}
public Linha(Point2D pinicial, Point2D pfinal){
this.pinicial=pinicial;
this.pfinal=pfinal;
}
//Get's e Set's
public Point2D getPinicial() {
return pinicial;
}
public void setPinicial(Point2D pinicial) {
this.pinicial = pinicial;
}
public Point2D getPfinal() {
return pfinal;
}
public void setPfinal(Point2D pfinal) {
this.pfinal = pfinal;
}
}
And then i created a Jframe with a button called "line" and put it a panel inside the jFrame that is the place where its going to get the line draw.
The problems is ... I dont know how to draw the line or how should i cal it.
Can you help me?

simply, in your JPanel class ovverride paintComponent() method:
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g)
g.drawLine(x1, y1, x2, y2);
}
}
Where x1, y1, x2, and y2, are the cords of your line.
If you ONLY want it to draw line AFTER the button is pressed, create a global boolean variable, in your main class, and when the button is pressed, set it to true, then when you create your JPanel do:
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
if (myBoolean) {
super.paintComponent(g)
g.drawLine(x1, y1, x2, y2);
}
}
}

Though the advice given in the other answer is too good, but just couldn't stop myself, from adding a word or two to the same, like, in order for the painting to take place, you need to call repaint(), from inside the actionPerformed attached to JButton.
As already stated by #camickr, the use of getPreferredSize() inside the extended class for Drawing, that will provide a valid staging area, where the drawing needs to be done. This example might can help too in this direction.
Moreover, in case you wanted to keep all the lines which have been drawn on the Board so far intact, then you can simply store them in a List and iterate on this List to draw them all again, whenever a new line is to be drawn.
A simple example is as follows:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class LineExample {
private DrawingBoard board;
private JButton drawLineButton;
private Random random;
private ActionListener buttonAction = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
int width = board.getWidth();
int height = board.getHeight();
Line line = new Line(random.nextInt(width),
random.nextInt(height),
random.nextInt(width),
random.nextInt(height));
board.setValues(line);
}
};
public LineExample() {
random = new Random();
}
private void displayGUI() {
JFrame frame = new JFrame("Drawing Lines Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel(new BorderLayout(5, 5));
board = new DrawingBoard(400, 400);
contentPane.add(board, BorderLayout.CENTER);
drawLineButton = new JButton("LINE");
drawLineButton.addActionListener(buttonAction);
contentPane.add(drawLineButton, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new LineExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
class DrawingBoard extends JPanel {
private int width;
private int height;
private List<Line> lines;
public DrawingBoard(int w, int h) {
width = w;
height = h;
lines = new ArrayList<Line>();
}
public void setValues(Line line) {
lines.add(line);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Line line : lines) {
int xs = line.getXStart();
int ys = line.getYStart();
int xe = line.getXEnd();
int ye = line.getYEnd();
g.drawLine(xs, ys, xe, ye);
}
}
}
class Line {
private Point startPoint;
private Point endPoint;
public Line(int xs, int ys, int xe, int ye) {
startPoint = new Point(xs, ys);
endPoint = new Point(xe, ye);
}
public int getXStart() {
return startPoint.getX();
}
public int getYStart() {
return startPoint.getY();
}
public int getXEnd() {
return endPoint.getX();
}
public int getYEnd() {
return endPoint.getY();
}
}
class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}

Related

How to clear components in JPanel?

I am new to Java programming. I developing a java app, which draws shapes (circles, lines, triangles, etc) on a windows frame. I define an abstract class Shapes.java to contain the framework for shapes:
public abstract class Shapes {
public abstract void draw(Graphics g);
}
Then, I define some classes such as Circle, Line, Triangle, and Rectangle which extend from the Shapes.java class.
public class Circle extends Shapes{
private int x;
private int y;
private int radius;
public Circle(int x, int y, int radius) {
this.x = x;
this.y = y;
this.radius = radius;
}
#Override
public void draw(Graphics g) {
g.drawOval(x-radius,y-radius,radius * 2, radius *2);
}}
In my Picture.java class, I settle a JFrame and add shapes on it:
public class Picture extends JFrame {
private static final long serialVersionUID = 1L;
private int width;
private int height;
private boolean isClear = false;
private ArrayList<Shapes> listShape = new ArrayList<Shapes>();
private class ShapesPanel extends JPanel{
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(isClear)
return;
else
for (Shapes s : listShape)
s.draw(g);
}
public void add(Shapes s){
listShape.add(s);
}
public Picture(int width, int height, String title) throws HeadlessException {
ShapesPanel mypanel = new ShapesPanel();
add(mypanel);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.width = width;
this.height = height;
this.setTitle(title);
}
public void draw(){
setLocationRelativeTo(null);
setSize(width, height);
setVisible(true);
repaint();
}
void clear(){//clear the componets in the JPanel
this.setIsClear(true);
this.validate();
this.repaint();
}
private void setIsClear(boolean b) {
// TODO Auto-generated method stub
this.isClear = b;
}
}
But when I invoke the clear() method in the main class, the program cannot repaint the new shapes again. How can I fix the bugs? Thanks.
public class MyPic {
public static void main(String[] args){
Picture pic = new Picture(420, 300, "shape demo");
Circle c1 = new Circle(320,80,80);
Rectangle r1 = new Rectangle(100,100,100,100);
Triangle t1 = new Triangle(100,100,200,100,150,50);
Line l1 = new Line(0,205,400,50);
pic.add(c1);
pic.add(r1);
pic.add(t1);
pic.add(l1);
pic.clear();
pic.draw();
pic.add(l1);//add l1 again
}
}
Okay, so by calling clear() you set a variable isClear to true. And then in your paintComponent you say:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(isClear)
return;
which means 'if isClear is true, don't paint anything' (which it is, you just set it to true with clear()). So, no wonder.
Anyway, I think in the clear method, you might want to do listShape.clear() instead of setting that boolean.

Why is java copying instead of creating a new Instant When i use different variables?

I made a fairly simple code and i got into an error which confused me.
So I have a class that creates two totally different variables and creating them using the new keyword
Player playerLeft = new Player(5,150);
Player playerRight = new Player( 150,150);
Player class:
import javax.swing.*;
import java.awt.*;
public class Player extends JComponent {
private int posY;
private int posX;
public Player(int x, int y) {
posX = x;
posY = y;
//repaint();
}
public float getMovementY() {
return movementY;
}
public void setMovementY(int movementY) {
this.movementY = movementY;
}
int movementY = 0;
public void paintComponent(Graphics g) {
Graphics2D _g2 = (Graphics2D) g;
Rectangle rect = new Rectangle(posX, posY, 20, 150);
_g2.fill(rect);
}
public void setLocation(int x, int y) {
posY = y;
posX = x;
repaint();
}
public void move() {
setLocation(posX, posY + movementY);
}
}
It's probably me not knowing something about Java but for me when I try to instantiate playerRight it just overwrites player left and drawsOut playerRight only.
Here is the complete code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Timer;
import java.util.TimerTask;
public class mainJFrame extends JFrame implements KeyListener {
int relativeTimeMillsec = 0;
Player playerLeft = new Player(5, 150);
Player playerRight = new Player(150, 150);
Timer timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
relativeTimeMillsec++;
refreshTimeText(relativeTimeMillsec);
calcMovements();
}
};
//components
JLabel timeCounterLabel = new JLabel("Time: " + 0, SwingConstants.CENTER);
public mainJFrame() {
createComponents();
addKeyListener(this);
}
public void createComponents() {
this.setTitle("The title");
this.setSize(800, 600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
timer.scheduleAtFixedRate(task, 0, 10);
JButton testButton = new JButton("Label");
testButton.setSize(100, 25);
testButton.setLocation(this.getWidth() / 2 - testButton.getWidth() / 2, this.getHeight() / 2 - testButton.getHeight() / 2);
timeCounterLabel.setSize(200, 25);
timeCounterLabel.setLocation(this.getWidth() / 2 - timeCounterLabel.getWidth() / 2, 10);
//playerRight = new Player(this.getWidth()-45,this.getHeight()/2);
// this.add(testButton);
this.add(timeCounterLabel);
this.add(playerLeft);
this.add(playerRight);
}
public void paintComponent(Graphics g) {
{
super.repaint();
}
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_S) {
playerLeft.movementY = +2;
} else if (e.getKeyCode() == KeyEvent.VK_W) {
playerLeft.movementY = -2;
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
playerRight.movementY = +2;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
playerRight.movementY = -2;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
private double calcRealRelativeTime(int _relTime) {
return relativeTimeMillsec / (double) 100;
}
private void refreshTimeText(int _relTime) {
timeCounterLabel.setText("Time: " + Math.round(calcRealRelativeTime(_relTime)));
}
private void calcMovements() {
playerLeft.move();
playerRight.move();
}
}
Understand that a JFrame's contentPane (the container that holds its components) uses BorderLayout by default, and this code:
this.add(timeCounterLabel);
this.add(playerLeft);
this.add(playerRight);
is adding all components to the same default BorderLayout.CENTER position, meaning any components added will replace components added previously.
But more importantly, yours is a common problem and stems from your having your Player class extend from a GUI component. Don't do this, as then you will have a great deal of difficulty drawing multiple Player objects and having them interact easily (as you're finding out). Instead have Player be a logical (non-component) class, and have only one class extend JPanel and do all the drawing. This class can hold Player objects, perhaps held in a collection such as an ArrayList<Player>, and then iterate through the collection within its paintComponent method.
Other issues:
Do not use java.util.Timer and java.util.TimerTask for Swing animations since these classes do not follow Swing threading rules. Use instead a javax.swing.Timer.
Learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others
If/when you do override a painting method such as paintComponent, be sure to call the super's method within your override, usually on the first line, so as not to break the painting chain. Also, use the #Override annotation before this method and any other methods that you think that you may be overriding so that the compiler catches possible errors with this.
For example (but not a complete example)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class SimpleAnimation extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 600;
private static final int TIMER_DELAY = 20;
private Player2 playerLeft = new Player2(5, 150, Color.RED);
private Player2 playerRight = new Player2(150, 150, Color.BLUE);
public SimpleAnimation() {
playerLeft.setySpeed(1);
playerRight.setySpeed(-1);
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
playerLeft.draw(g);
playerRight.draw(g);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
playerRight.move();
playerLeft.move();
repaint();
}
}
private static void createAndShowGui() {
SimpleAnimation mainPanel = new SimpleAnimation();
JFrame frame = new JFrame("SimpleAnimation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Player2 {
private static final int RECT_WIDTH = 20;
private static final int RECT_HEIGHT = 50;
private int x;
private int y;
private int ySpeed;
private Color color;
public Player2(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setySpeed(int ySpeed) {
this.ySpeed = ySpeed;
}
public int getySpeed() {
return ySpeed;
}
public void setLocation(int x, int y) {
setX(x);
setY(y);
}
public void move() {
setLocation(x, y + ySpeed);
}
public void draw(Graphics g) {
g.setColor(color);
g.fillRect(x, y, RECT_WIDTH, RECT_HEIGHT);
}
}

JAVA mouselistener gives incorrrect x and y coordinates

Here I have two classes, one including main function. I want to draw a rectangle which moves automatically. But the starting point of rectangle is not the same as the point i clicked with mouse. I could not figure out this problem. Can you help me?
This is the first class including main function
import java.awt.Graphics;
import java.awt.event.*;
import javax.swing.*;
public class BuyuyenSuDamlalari extends JPanel implements ActionListener {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(600,400);
BuyuyenSuDamlalari bsd1 = new BuyuyenSuDamlalari();
frame.setContentPane(bsd1);
BuyuyenSuDamlalariClickListener bscl = new BuyuyenSuDamlalariClickListener(bsd1);
bsd1.addMouseListener(bscl);
frame.setResizable(false);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
int x;
int y;
int radius;
int click;
public BuyuyenSuDamlalari() {
super();
setFocusable(true);
Timer zaman = new Timer(40, this); // bir saniyede 25 resim oluyor
zaman.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (click>0) {
g.drawRect(x, y, radius, radius);
}
}
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 void actionPerformed(ActionEvent arg0) {
radius++;
repaint();
}
public void setClick(int click) {
this.click = click;
}
}
This is the second class wihich includes motionListener
import java.awt.event.*;
public class BuyuyenSuDamlalariClickListener extends MouseAdapter {
private BuyuyenSuDamlalari bsd = new BuyuyenSuDamlalari();
private int x;
private int y;
public BuyuyenSuDamlalariClickListener(BuyuyenSuDamlalari bsd) {
super();
this.bsd = bsd;
}
public void mousePressed(MouseEvent e) {
if (e.getClickCount()>0) {
bsd.setX(e.getX()-25);
bsd.setY(e.getY()-25);
}
bsd.setClick(1);
}
}

Drawing Shape with ActionListener from Another Class

In my program, I am gonna ask for number of rectangles in JPanel and add them into the frame with create button. I want to call rectangles from another class. But I can not see my rectangles. When I write same paint method in my main class, I can see rectangles but they appers when I run the program. I want them to appear with actionlistener. What am I doing wrong? Here is my classes;
Rectangle Class:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class Rectangle extends JFrame {
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 int getW() {
return w;
}
public void setW(int w) {
this.w = w;
}
public int getH() {
return h;
}
public void setH(int h) {
this.h = h;
}
public Color getC() {
return c;
}
public void setC(Color c) {
this.c = c;
}
private int x,y,w,h;
private Color c;
private asgn3 a3;
public Rectangle() {
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(getX(), getY(), getW(), getH());
g.setColor(Color.red);
}
}
My main JFrame class:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Example extends JFrame implements ActionListener {
private JTextField recttext;
private JButton create;
private JLabel rectlabel,createlabel;
private int seat a;
private Rectangle[] rect;
public Example() {
setLayout(null);
recttext = new JTextField();
recttext.setSize(150, 40);
recttext.setLocation(100, 40);
add(recttext);
rectlabel = new JLabel("Rectangle number");
rectlabel.setSize(100, 20);
rectlabel.setLocation(102, 20);
add(rectlabel);
create = new JButton("Create");
create.setSize(70,30);
create.setLocation(670, 20);
add(create);
create.addActionListener(this);
setSize(800,800);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
}
public static void main(String[] args) {
new Example();
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(create)) {
a = Integer.parseInt(recttext.getText());
rect = new Rectangle[a];
for(int i=0;i<a;i++) {
rect[i]= new Rectangle();
}
for(int i=1;i<=a/10;i++) {
for(int j=i;j<11;j++) {
rect[i-1].setX((getWidth()/(a/10))*i+20);
rect[i-1].setY(100+j*50);
rect[i-1].setW(100);
rect[i-1].setH(50);
repaint();
}
}
}
}
}
When I write same paint method in my main class
What paint method? All your code does is create an Array of Rectangle objects. You have no code to do any painting.
The way painting works is that you override the paintComponent() of a JPanel. So you need to create a custom JPanel for your painting. Then you create an ArrayList of Rectangle objects. In the paintComponent() method you iterate through the ArrayList and paint each Rectangle.
Read the section from the Swing tutorial on Custom Painting for a simple example to get you started.
You can also check out the DrawOnComponent example found in Custom Painting Approaches. It demonstrates how you can dynamically add Rectangle objects to be painted. The key it so use the addRectangle(...) method each time you want to display another Rectangle.

JPanel size is not known on start

When I create a Board instance from my Square instance, I try to assign the size of the window to the integers x and y. I fail to do this because it seems like on start the size is 0. In the constructor in Board.java, x and y shouldn't be -50 like they end up now.
Square.java:
package Square;
import javax.swing.*;
public class Square extends JFrame {
public Square(){
add(new Board());
setSize(800, 800);
setVisible(true);
}
public static void main(String[] args){
new Square();
}
}
Board.java
package Square;
import javax.swing.*;
import java.awt.*;
public class Board extends JPanel{
int x,y;
public Board(){
x = width-50;
y = height-50;
}
public int width = (int) getSize().getWidth();
public int height = (int) getSize().getHeight();
public void paintComponent(Graphics g){
super.paintComponent(g);
g.fillRect(x,y, 100, 100);
}
}
Full Code for clarification:
Square.java
package Square;
import javax.swing.*;
public class Square extends JFrame {
public Square(){
Board board = new Board();
board.start();
add(board);
setTitle("Square");
setSize(800, 800);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String[] args){
Square square = new Square();
square.setVisible(true);
square.setLocation(2000, 150);
}
}
Board.java
package Square;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Board extends JPanel implements ActionListener{
Timer timer;
int x, y;
int velX = 0;
int velY = 0;
public Board(){
setFocusable(true);
timer = new Timer(1, this);
addKeyListener(new TAdapter());
}
class TAdapter extends KeyAdapter{
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
switch(keyCode){
case KeyEvent.VK_ESCAPE: x = width()/2-50; y = height()/2-50; break;
case KeyEvent.VK_RIGHT: velX = 1; break;
case KeyEvent.VK_DOWN: velY = 1; break;
case KeyEvent.VK_LEFT: velX = -1; break;
case KeyEvent.VK_UP: velY = -1; break;
}
}
public void keyReleased(KeyEvent e){
velX = 0;
velY = 0;
}
}
public int width(){ return (int) getSize().getWidth();}
public int height(){ return (int) getSize().getHeight();}
public void start(){
timer.setInitialDelay(100);
timer.start();
x = width()/2-50;
y = height()/2-50;
}
#Override
public void actionPerformed(ActionEvent e) {
x += velX;
y += velY;
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(x,y, 100, 100);
}
}
Put the calculation into your paintComponent method. In general you want to avoid having code in paintComponent that will slow it down, but these calls shouldn't give too much penalty. Also, if your program is re-sizable, you'll need to be able to re-calculate the sizes of things on the go like this:
public void paintComponent(Graphics g){
super.paintComponent(g);
int x = getWidth() - 50;
int y = getHeight() - 50;
g.fillRect(x, y, 100, 100);
}
but of course in your real program, you will want to avoid "magic" numbers
Another issue: don't call setSize() on your JFrame. Instead, if you want to specify a hard size, do so in the JPanel by overriding its getPreferredSize() method. This will also then give you the suggested parameters that can be used for your calculations.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class DrawRect extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = PREF_W;
private static final int DELTA = 50;
private static final Color RECT_COLOR = Color.red;
private static final int RECT_WIDTH = 100;
private static final int TIMER_DELAY = 15;
private int rectX = PREF_W - DELTA;
private int rectY = PREF_H - DELTA;
public DrawRect() {
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(RECT_COLOR);
g.fillRect(rectX, rectY, RECT_WIDTH, RECT_WIDTH);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
rectX--;
rectY--;
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("DrawRect");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new DrawRect());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Also, check out the key bindings animation code from this answer of mine.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
public class GamePanel extends JPanel {
private static final int ANIMATION_DELAY = 15;
private final int HEIGHT = 400;
private final int WIDTH = 600;
private Square square;
private EnumMap<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
private Map<Integer, Direction> keyToDir = new HashMap<>();
// !! private Circle circle;
private Timer animationTimer;
public GamePanel() {
for (Direction dir : Direction.values()) {
dirMap.put(dir, Boolean.FALSE);
}
keyToDir.put(KeyEvent.VK_UP, Direction.UP);
keyToDir.put(KeyEvent.VK_DOWN, Direction.DOWN);
keyToDir.put(KeyEvent.VK_LEFT, Direction.LEFT);
keyToDir.put(KeyEvent.VK_RIGHT, Direction.RIGHT);
// !! addKeyListener(new DirectionListener());
setKeyBindings();
setBackground(Color.white);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusable(true);
square = new Square();
animationTimer = new Timer(ANIMATION_DELAY, new AnimationListener());
animationTimer.start();
}
private void setKeyBindings() {
int condition = WHEN_IN_FOCUSED_WINDOW;
final InputMap inputMap = getInputMap(condition);
final ActionMap actionMap = getActionMap();
boolean[] keyPressed = { true, false };
for (Integer keyCode : keyToDir.keySet()) {
Direction dir = keyToDir.get(keyCode);
for (boolean onKeyPress : keyPressed) {
boolean onKeyRelease = !onKeyPress; // to make it clear how bindings work
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0,
onKeyRelease);
Object key = keyStroke.toString();
inputMap.put(keyStroke, key);
actionMap.put(key, new KeyBindingsAction(dir, onKeyPress));
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
square.display(g);
}
private class AnimationListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent evt) {
boolean repaint = false;
for (Direction dir : Direction.values()) {
if (dirMap.get(dir)) {
square.move(dir);
repaint = true;
}
}
if (repaint) {
repaint();
}
}
}
private class KeyBindingsAction extends AbstractAction {
private Direction dir;
boolean pressed;
public KeyBindingsAction(Direction dir, boolean pressed) {
this.dir = dir;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent evt) {
dirMap.put(dir, pressed);
}
}
private static void createAndShowGUI() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame("GamePanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
gamePanel.requestFocusInWindow();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
enum Direction {
UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0);
private int incrX;
private int incrY;
private Direction(int incrX, int incrY) {
this.incrX = incrX;
this.incrY = incrY;
}
public int getIncrX() {
return incrX;
}
public int getIncrY() {
return incrY;
}
}
class Square {
private int x = 0;
private int y = 0;
private int w = 20;
private int h = w;
private int step = 1;
private Color color = Color.red;
private Color fillColor = new Color(255, 150, 150);
private Stroke stroke = new BasicStroke(3f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND);
public void display(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(fillColor);
g2d.fillRect(x, y, w, h);
g2d.setStroke(stroke);
g2d.setColor(color);
g2d.drawRect(x, y, w, h);
g2d.dispose();
}
public void setStep(int step) {
this.step = step;
}
public void move(Direction dir) {
x += step * dir.getIncrX();
y += step * dir.getIncrY();
}
}
Hey your codestyle is horrible, but i try to help :). You can't get a size of an undrawn window. First Things first, your Constructor is wrong, you add the Board that actually create the Board Obj. Calling the Constructor of Board, which has no drawn parent yet and no x,y set. Try to initialize your variables in the Constructor. So just use width and height and fill the values in the constructor. Next, just tell your board its creation size by passing its parent size trough constructor variables.
I think you try to learn java and this is much more elegant. Furthermore, try to do all parent modification before adding some to it. So first setSize, add some Layout (Border/Flow/whatuwish) then get the frames ContentPane and add your Board component. To make things clear, you can't get e.g. the parent and parent size in Contructor because your board Obj isn't created and added yet. If you wish to getParent() and its size, create the Object add it to JFrame and than you can call getParent().getSize(). You get 0 because your JPanel isn't drawn at this time (before creation). If you wish to get the Parent Size just pass the JFrame Ref to Constructor or its size. Another Advise, don't create things in things in things, keep in mind with your code you create your JPanel as first Obj... Here is some example code:
Square:
public class Square extends JFrame {
public static void main(String[] args){
Square square = new Square();
square.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension d = new Dimension(800,800);
square.setPreferredSize(d);
square.setSize(d);
//too much, every Jframe has BorderLayout enabled
square.getContentPane().setLayout(new BorderLayout());
square.getContentPane().add(new Board(square), BorderLayout.CENTER);
square.pack();
square.setVisible(true);
}
}
Board:
public class Board extends JPanel{
int x,y;
JFrame parent;
public Board(JFrame parent){
int width = parent.getPreferredSize().width;
int height = parent.getPreferredSize().height;
x = width-50;
y = height-50;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.fillRect(x,y, 100, 100);
}
}
You can take x and y values after the panel has become visible, in the next EDT cycle, by using SwingUtilities.invokeLater, for example.

Categories