Paint ArrayList of Shape Objects to Frame - java

I'm having difficulty with drawing Shapes (Circle & Rectangle) into a Frame.
I have created both a Circle and a Rectangle Class that implements the Shape Interface. I have then created DrawableCircle and DrawableRectangle Classes that extend the Circle and Rectangle Classes appropriately, and implement the Drawable Interface.
I am now trying to create a ShapesDriver Class which extends Frame and has within it the main method and paint(Graphics g) method. Within ShapesDriver I need to create an ArrayList of type Drawable. This ArrayList holds an instance of DrawableCircle and DrawableRectangle. In the paint method I have to iterate through the ArrayList and invoke the draw method for each shape.
This is where I am stuck...
Any help would be appreciated!
Shape Interface
public interface Shape {
public double area();
}
Circle Class
public class Circle implements Shape{
private int radius;
private double area;
public Circle(int r){
radius = r;
}
#Override
public double area() {
area = Math.PI * (radius * radius);
return area;
}
}
Rectangle Class
public class Rectangle implements Shape{
double height;
double width;
double area;
public Rectangle(double h, double w){
height = h;
width = w;
}
#Override
public double area() {
area = height * width;
return area;
}
}
Drawable Interface
import java.awt.Color;
import java.awt.Graphics;
public interface DrawableInterface {
public void setColor(Color c);
public void setPosition(int x, int y);
public void draw(Graphics g);
}
DrawableCircle
import java.awt.Color;
import java.awt.Graphics;
public class DrawableCircle extends Circle implements DrawableInterface{
private Color col;
private int posX;
private int posY;
public DrawableCircle(int r){
super(r);
}
#Override
public void setColor(Color c) {
col = c;
}
#Override
public void setPosition(int x, int y) {
posX = x;
posY = y;
}
#Override
public void draw(Graphics g) {
g.setColor(col);
g.drawOval(posX, posY, 15, 15);
}
}
DrawableRectangle
import java.awt.Color;
import java.awt.Graphics;
public class DrawableRectangle extends Rectangle implements DrawableInterface{
private Color col;
private int posX;
private int posY;
public DrawableRectangle(double h, double w){
super(h, w);
}
#Override
public void setColor(Color c) {
col = c;
}
#Override
public void setPosition(int x, int y) {
posX = x;
posY = y;
}
#Override
public void draw(Graphics g) {
g.setColor(col);
g.drawRect(posX,posY,10,10);
}
}
ShapesDriver
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
public class ShapesDriver extends Frame {
static ArrayList<DrawableInterface> shapesArr = new ArrayList<DrawableInterface>();
public ShapesDriver() {
super("Shapes Object Array");
setSize(400, 300);
setLocation(200, 200);
setVisible(true);
}
public static void main(String[] args) {
DrawableCircle c = new DrawableCircle(500);
c.setColor(Color.GREEN);
c.setPosition(25, 25);
DrawableRectangle r = new DrawableRectangle(100, 50);
r.setColor(Color.RED);
r.setPosition(75, 75);
shapesArr.add(c);
shapesArr.add(r);
ShapesDriver shapeFrame = new ShapesDriver();
shapeFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
#Override
public void paint(Graphics g) {
for (DrawableInterface s : shapesArr) {
super.paint(g);
s.draw(g);
}
}
}

"This is where I am stuck..." -- where are you stuck exactly?
Myself, I would:
use a Swing GUI not an AWT GUI since Swing is much more powerful and flexible than AWT. There's almost never a need to create AWT GUI's.
Your GUI class, ShapesDriver does nothing. It extends Frame, but you never create an instance of the ShapesDriver. Instead it has a main method where you create a separate Frame. In my GUI code, I'd create a true GUI class, that had instance fields and methods, and would be sure to create an instance of this class somewhere.
In my GUI class I'd have my ArrayList of Shape and my drawing method, and would loop through the ArrayList within the drawing method, drawing each shape as I looped.
Since I would favor using Swing, my GUI class would extend JPanel, and my drawing method would be a paintComponent(Graphics g) method. If you're required to use AWT, then you could instead use a Panel and draw in its paint(Graphics g) method.
I'd then have a main method that creates the GUI, makes it visible, and does nothing else.

Related

hello, I am trying to draw a circle by using paintComponent

circle class
This is a simple circle class with only with a constructor.
public class Circle {
private int radius;
public Circle(int radius) {
this.radius = radius;
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
public double getArea() {
return Math.PI * radius * radius;
}
#Override
public String toString() {
return "cicle [radius=" + radius + ", getRadius()=" + getRadius() + ", getArea()=" + getArea() + ", getClass()="
+ getClass() + ", hashCode()=" + hashCode() + ", toString()=" + super.toString() + "]";
}
}
Rock class
This is Rock class extends JPanel, that only have circle as variable. and overridden paintComponent.
import javax.swing.*;
import java.awt.*;
public class Rock extends JPanel {
private Circle circle;
public Rock(Circle circle) {
this.circle=circle;
}
public Circle getCircle() {
return circle;
}
public void setCircle(Circle circle) {
this.circle = circle;
}
#Override
public void paintComponent(Graphics j) {
super.paintComponent(j);
j.setColor(Color.black);
int radius=new Circle(100).getRadius();
j.fillOval(5, 5, radius, radius);
}
/*
* public void paintcomponent(Graphics g) { super.paintComponent(g);
* g.setColor(Color.black); int radius=new Circle(100).getRadius();
* g.fillOval(0, 0, radius, radius); }
*/
}
Gui Stuff
This is the class where I was trying to construct everything.
but when I added the Rock object to the layout, it would not appear.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class Gui extends JFrame implements ActionListener {
JFrame topFrame = null;
GridBagLayout grid=new GridBagLayout();
GridBagConstraints cons=new GridBagConstraints();
Graphics j;
Circle circle=new Circle(100);
Rock rock;
public Gui() {
rock=new Rock(circle);
RockGold h=new RockGold(circle);
JLabel lblResult=new JLabel(" Result ");
this.setLayout(grid);
cons=new GridBagConstraints();
cons.gridx=1;
cons.gridy=7;
cons.insets=new Insets(10,10,10,0);
this.add(rock,cons);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
Main
This is the main with frames settings.
import javax.swing.JFrame;
public class main {
public static void main(String[] args) {
Gui gui=new Gui();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(900, 900);
gui.setVisible(true);
}
}
Here are some tips on how to draw a circle.
create a class extending JPanel
create an instance of JFrame-- Do not subclass it
add the JPanel to the JFrame.
override paintComponent in your panel (like you have been doing).
simply call fillOval() or drawOval() with the appropriate arguments.
Note the use of rendering hints below.
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// the following will visually smooth the edges.
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.black);
g2d.fillOval(5,5, 100,100);
}
Please check out painting in the Java Tutorials

Why is only one ball being drawn? There should be many more

I'm trying to have an ArrayList of Ball objects, and I want to draw them to the screen, but only one of them gets drawn and I don't know why.
Ball class:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.util.Random;
public class Ball extends JPanel{
int sX,sY;
Color color;
int speed;
int height;
int width;
int velX=0;
int velY=0;
Random randInt;
JFrame window;
public Ball(int sX,int sY,int height,int width){
this.sX=sX;
this.sY=sY;
this.color=color;
this.speed=speed;
this.height=height;
this.width=width;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d=(Graphics2D)g;
g2d.setColor(color.RED);
Ellipse2D ellipse = new Ellipse2D.Double(sX,sY,width,height);
g2d.fill(ellipse);
}
public String getCoords(){
return "X: "+String.valueOf(sX)+" Y: "+String.valueOf(sY);
}
}
BallManager class (where it stores the arraylist of ball objects)
import javax.swing.*;
import java.util.ArrayList;
public class BallManager {
ArrayList<Ball> listOfBalls;
int width,height;
JFrame window;
Ball newBall;
public BallManager(JFrame window) {
this.listOfBalls=new ArrayList<Ball>();
this.window=window;
this.addBalls(100);
//this.drawBalls();
}
public void addBalls(int n){
for (int y=0;y<n;y+=20){
for(int x=0;x<n;x+=20){
this.listOfBalls.add(new Ball(x,y,10,10));
drawBalls();
}
}
System.out.println(listOfBalls.size());
}
public void drawBalls(){
for(Ball b:listOfBalls){
window.add(b);
System.out.println(b.getCoords());
}
}
}
Main class:
public class Main {
public static void main(String[] args){
JFrameWindow j= new JFrameWindow(300,500);
BallManager bm=new BallManager(j);
}
}
Window Class:
import javax.swing.*;
import java.awt.*;
public class JFrameWindow extends JFrame {
int width;
int height;
public JFrameWindow(int width,int height){
super("JFrame ballssssss");
this.width=width;
this.height=height;
this.setLocationRelativeTo(null);
this.setSize(this.width,this.height);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setVisible(true);
this.getContentPane().setBackground(Color.orange);
}
}
I have no clue what the problem is. It seems to me that the balls in the arraylist move in unison with each other but I don't know why.
You've got some things a little backwards:
The Ball class should not extend from JPanel nor any other Swing component. Instead it should be a logical class, one that knows the location, color of a ball and how to draw it, in a method, say public void draw(Graphics g).
There should be only one JPanel that holds the logical Balls in an ArrayList<Ball>, and draws them all within its paintComponent method via a for-loop.
This single JPanel should be added to the JFrame, BorderLayout.CENTER.
e.g.,
public class Ball {
private static final int RADIUS = 5;
private int x;
private int y;
private Color color;
// constructors
// getters / setters
// methods to move the ball
// or might use Graphics2D and rendering hints to smooth drawing
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(x - RADIUS, y - RADIUS, 2 * RADIUS, 2 * RADIUS);
}
}
and
class BallPanel extends JPanel {
private List<Ball> balls = new ArrayList<>();
// constructor -- fill the balls list
// other methods....
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Ball ball : balls) {
ball.draw(g);
}
}
}

Java: Calling repaint() in static context (Or how to avoid it)

I am working on a simple app Java/Swing, which involves having the user click on a box and drag it around. I am having troubles with understanding how the repaint method can be used. I created this example of the problem, in which a square is drawn and then on mousePressed it gets the x cordinates of the click, and displaces the original drawing by however much the pointer is moved.
I have read the commonly referred guides on drawing in Swing, but I haven't seen any answers to the question on how to write a program that incorporates both mouseMotion and mouseListener (which as far as I can tell means that the mouseListener must be implemented as its own class, as opposed to the common solution of incorporating it into the custom JPanel class) and also calls repaint() based on mouse actions.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.MouseInputAdapter;
class drawTest extends JPanel {
static int xpos_square = 200;
static int ypos_square = 200;
int width = 100;
int height = 100;
static int x_init;
static int y_init;
public drawTest(){
addMouseListener(new mouseListener());
addMouseMotionListener(new mouseListener());
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawSquare(g);
}
public void drawSquare(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(xpos_square, ypos_square, height, width);
}
public static void moveShape(int x, int y){
xpos_square += x-x_init;
ypos_square += y-y_init;
repaint();
}
public static void getChord(int x, int y){
x_init = x;
y_init = y;
}
}
class mouseListener extends MouseInputAdapter{
public void mousePressed(MouseEvent e){
drawTest.getChord(e.getX(),e.getY());
}
public void mouseDragged(MouseEvent e){
drawTest.moveShape(e.getX(),e.getY());
}
}
public class myTest {
JFrame myFrame = new JFrame();
JPanel myDrawing = new drawTest();
public myTest () {
myFrame.add(myDrawing);
myFrame.setSize(500,500);
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String []args){
new myTest();
}
}
The issue is of course that repaint() cannot be called in a static context. However, I don't see how I can avoid this, since if I want the position to smoothly update, it has to be called via the mouseDragged method.
How else could I use the repaint() method to redraw based on mouse movements?
So I figured out a way around it, using anonymous methods in addMouseListener. This bypasses the need for static methods in the call to repaint. If anyone else has a similar question, maybe they will find it helpful.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.MouseInputAdapter;
class DrawTest extends JPanel {
static int xpos_square = 200;
static int ypos_square = 200;
int width = 100;
int height = 100;
static int x_init;
static int y_init;
public DrawTest(){
addMouseListener(new mouseListener(){ public void mousePressed(MouseEvent e){
getClick(e.getX(),e.getY());
}});
addMouseMotionListener(new mouseListener(){ public void mouseDragged(MouseEvent e){
moveShape(e.getX(),e.getY());
}});
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawSquare(g);
}
public void drawSquare(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(xpos_square, ypos_square, height, width);
}
public void moveShape(int x, int y){
if((x >= xpos_square)&&(x <= xpos_square + width)&&(y >= ypos_square)&&(y <= ypos_square + height)){
xpos_square += x-x_init;
ypos_square += y-y_init;
x_init = x;
y_init = y;
repaint();
}
}
public void getClick(int x, int y){
x_init = x;
y_init = y;
}
}
public class MyTest {
JFrame myFrame = new JFrame();
JPanel myDrawing = new DrawTest();
public MyTest () {
myFrame.add(myDrawing);
myFrame.setSize(500,500);
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String []args){
new MyTest();
}
}

Painting a rectangle from an exterior class

I'm a beginner to Java 2D graphics, currently learning.
I have a class Surface, extending JPanel, that's overriding paintComponent method. It's where the program is supposed to draw things. An instance of Surface was added to a different class that extends JFrame. This class is called Main, it also included the main method.
I'm trying to do that Surface will call a method in the class DrawRect, and that method will create a rectangle in Surface, from the outside.
Here are my attempts:
// Class Main
package m;
import java.util.*;
import java.awt.*;
import java.awt.Event.*;
import javax.swing.*;
public class Main extends JFrame {
public static void main(String[] args) {
Main m = new Main();
}
public Main(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Bla");
setSize(500,500);
add(new Surface());
setVisible(true);
}
}
// Class Surface
package m;
import java.util.*;
import java.awt.*;
import java.awt.Event.*;
import javax.swing.*;
public class Surface extends JPanel {
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// What to do here?
}
}
package m;
import java.util.*;
import java.awt.*;
import java.awt.Event.*;
import javax.swing.*;
// Class DrawRect
public class DrawRect {
String color;
Surface surface;
public DrawRect(String color, Surface surface){
this.color = color;
this.surface = surface;
}
}
In other words, how can an exterior class draw something in another class? Thanks
One paint surface is one paint surface. You don't combine then. Even if you were to try and overlap them, you'd still be painting on one surface.
If you want to use a data model for another shape you could do something like this
public class MyRetangle{
int x = 10;
int y = 10;
int width = 100;
int height = 100;
Color color = Color.RED;
}
public class Surface extends JPanel {
MyRectangle rect = new MyRectangle(); // create an instance of your other class
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(rect.color); // use data from rect
g2.draw(new Rectangle.Double(rect.x, rect.y, rect.width, rect.height));
}
}
This is just an example. I don't know why you would ever do this, but you can see how to use data from another class as drawing data
Edit: to fit more towards your code
public class DrawRect{
int y;
int y;
int height;
int width;
Color color;
public DrawRect(int x, int y, int width, int height, Color color) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
}
}
public class Surface extends JPanel {
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
DrawRect rect = new DrawRect(20, 20, 100, 100, Color.RED);
g2.setColor(rect.color);
g2.draw(new Rectangle.Double(rect.x, rect.y, rect.width, rect.height));
}
}

Java infinite new objects

So what I want to achieve, is to create a simple program that lets the user create rectangles on the screen and then move them around.
I know that I can declare a new object in the code (i.e rectangle i = new rectangle(x,y,sizex,sizey)) however that will create only one, moreover it forces me to declare it in the code:
block1 = new block
block2 = new block
etc
Question is: How can I let the user create infinite rectangles with the use of lets say a button (not necessarily a button, it can be anything) and then let the user be capable of modyfing them (location/size etc).
Examples would be nice. I just feel there is a better way than declaring a gazillion objects in the code and then displaying them one by one. In C++ i could declare a malloc expandable container that would just hold the values, and then just display things using these values, not sure for java.
Simple code for reference:
public static void main(String[] args){
JFrame frame = new JFrame("A.L.T.E.S");
//Container container = frame.getContentPane();
frame.setSize(1024, 768);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Block object = new Block(10,10,20,20);
frame.add(object);
object.reDraw();
}
public class Block extends JPanel{
int yPos;
int xPos;
int xSize;
int ySize;
public Block(int xPos, int yPos, int xSize, int ySize){
this.xPos = xPos;
this.yPos = yPos;
this.xSize = xSize;
this.ySize = ySize;
}
public void setYPos(int yPos){
this.yPos = yPos;
}
public void setXPos(int xPos){
this.xPos = xPos;
}
public void setXSize(int xSize){
this.xSize = xSize;
}
public void setYSize(int ySize){
this.ySize = ySize;
}
public int getYPos(){
return yPos;
}
public int getXPos(){
return xPos;
}
public int getYSize(){
return ySize;
}
public int getXSize(){
return xSize;
}
public void reDraw(){
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(xPos, yPos, xSize, ySize);
}
}
Nothing in Java is simple.
First, Java already has a Rectangle class that holds the origin and size of a Rectangle. In your code, you're making all the rectangles blue. Suppose you want the user to set the color of a Rectangle. You can define your Block class like this.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
public class Block {
private Color color;
private Rectangle rectangle;
public Block(int x, int y, int width, int height) {
this(new Rectangle(x, y, width, height));
}
public Block(Rectangle rectangle) {
this.rectangle = rectangle;
this.color = Color.BLUE;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public Rectangle getRectangle() {
return rectangle;
}
public void draw(Graphics g) {
g.setColor(getColor());
g.fillRect(rectangle.x, rectangle.y,
rectangle.width, rectangle.height);
}
}
Next, you need a model class to hold all of the Blocks that your user defines.
Something like this BlockList class.
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
public class BlockList {
private List<Block> blockList;
public BlockList() {
this.blockList = new ArrayList<Block>();
}
public void init() {
this.blockList.clear();
}
public void addBlock(Block block) {
this.blockList.add(block);
}
public void draw(Graphics g) {
for (int i = 0; i < blockList.size(); i++) {
blockList.get(i).draw(g);
}
}
}
Now that you have your GUI model defined, you would build your GUI. Your drawing JPanel would call the draw method in your BlockList class.
I strongly suggest that you go through the Oracle tutorial on Swing. Go through the complete tutorial before you attempt to create a Swing GUI.
In java, use a Collection. In this case, use a List. You can create an ArrayList<Block>, then invoke add to add new rectangles. Then, you can iterate through this collection by using iterator, then calling hasNext and next on the iterator to find all the elements. I'm sure this brief hypnosis is going to be confusing, and if so, check out the Java Tutorial on Collections, which explains everything in all the detail you are going to need.

Categories

Resources