I am trying to use Java2D to do some simple graphics programming. I've started easy, just trying to display a couple of circles in a JFrame. I was successful displaying a single circle, but when adding a second circle, only the last circle added to the JFrame is displayed. I use class Circle to define my circle and to override the paintComponent method used to display it. Any suggestions on what I might be doing wrong would be greatly appreciated. Code for my classes Circle and DancingCircles is provided below for reference.
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
/**
*
* #author Paul
*/
public class Circle extends JPanel {
// Data members for Circle center and radius
private double centerX, centerY;
private double radius;
// No-argument constructor
Circle() {
centerX = 200;
centerY = 200;
radius = 10;
}
// Full-argument constructor
Circle( double x, double y, double r) {
centerX = x;
centerY = y;
radius = r;
}
// Draw a Circle
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//Convert to Java2D Object
Graphics2D g2 = (Graphics2D) g;
// Create the circle
Ellipse2D circle = new Ellipse2D.Double();
circle.setFrameFromCenter(centerX, centerY, centerX + radius, centerY + radius);
// Draw it
g2.draw(circle);
}// end paintComponent
// Get/set data members
public void setCenterX(double x){this.centerX = x;}
public void setCenterY(double y){this.centerY = y;}
public void setRadius(double r){radius = r;}
public double getCenterX(){return centerX;}
public double getCenterY(){return centerY;}
public double getRadius(){return radius;}
}// end class Circle
import java.awt.*;
import javax.swing.*;
/**
*
* #author Paul
*/
public class DancingCircles extends JFrame{
// Display Dimensions
public static final int DEFAULT_WIDTH = 400;
public static final int DEFAULT_HEIGHT = 400;
// Default constructor
private DancingCircles() {
setTitle("Dancing Circles");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
// Add Circles to JFrame
Circle myCircle = new Circle(200.0, 200.0, 20.0);
add(myCircle); // Add circle to frame
Circle myCircle2 = new Circle(100.0, 100.0, 30.0);
add(myCircle2); // Add circle to frame
}// end DancingCircles
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable()
{
public void run()
{
DancingCircles dc = new DancingCircles();
dc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
dc.setVisible(true);
}
});
}// end main
}
Thanks!
Paul
The way to do this is to remove the drawing methods from the circle class and create a single panel with multiple circles on it instead:
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
import java.util.*;
public class Circles extends JPanel
{
ArrayList<Circle> circles = new ArrayList<Circle>();
public void add(Circle circle) {
circles.add(circle);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Circle circle: circles) {
Ellipse2D circle2D = new Ellipse2D.Double();
circle2D.setFrameFromCenter(
circle.getCenterX(),
circle.getCenterY(),
circle.getCenterX() + circle.getRadius(),
circle.getCenterY() + circle.getRadius());
g2.draw(circle2D);
}
}
}
You are implementing each Circle as a JPanel. With the default LayoutManager of BorderLayout, the JFrame can only hold a single Component at a time when called with add(circle). When you add the second Circle, the first is removed.
To solve this, you can implement a MultiCircle class that draws multiple circles, and only add that to the JFrame once.
I'm not sure you really want your Circles to be JPanels. They really ought to look more like
class Circle {
double x,y,radius;
void draw(Graphics g) {
g.fillOval(...//etc/.
}
}
Then have a JComponent that has a bunch of Circles, and put that in your JFrame.
Having said that, if you must do it the way you've got it, then you should set the JFrame contentPane's layout to null, and make sure your Circles are not opaque. You'll also have to manually resize each Circle to fit its container.
Related
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);
}
}
}
The code is meant to draw a rectangle, which moves in a circle around the center of the canvas one time. The code I currently have is
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.Timer;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class Q3_Circular extends JComponent {
protected int degree = 0;
protected double xStart;
protected double yStart;
protected Timer timer;
public Q3_Circular() {
timer = new Timer(1000, new TimerCallback()); //creates new times that refreshes every 100 ms, and called the TimerCallback class
timer.start();
}
protected class TimerCallback implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (degree < (2 * Math.PI)){
xStart = getWidth()/2 * Math.cos(degree+1);
yStart = getHeight()/2 * Math.sin(degree+1);
degree+= 1;
repaint();
}
else {
degree += 0;
repaint();
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("AnimatedSquare");
Q3_Circular canvas = new Q3_Circular();
frame.add(canvas);
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void paintComponent(Graphics g){
xStart = (double)(getWidth())/2.0 * Math.cos(degree);
yStart = (double)(getHeight())/2.0 * Math.sin(degree);
Graphics2D g2 = (Graphics2D) g;
g2.draw(new Rectangle2D.Double(xStart,yStart, 25,25));
repaint();
}
}
This code appears to draw the rectangle very quickly around the point (0,0). I'm not sure where the code is wrong.
Your code was confusing. Here's the GUI I created.
When creating a Swing GUI, use the model / view / controller pattern. Create a GUI model, and GUI view, and one or more controllers to modify the model and repaint the view.
Here are the changes I made to your code.
I created a DrawingRectangle class to hold the information about the drawing rectangle. This class is a plain old Java object with getters and setters. This class is the GUI model.
I moved everything out of the main method except for the call to the SwingUtilities invokeLater method. The invokeLater method puts the creation and use of the Swing components on the Event Dispatch thread. Oracle and I insist that all Swing applications start on the Event Dispatch thread.
I create the drawing rectangle in the constructor of the Q3_Circular class. Generally, you create the GUI model, then the GUI view.
I rearranged the JFrame code in the run method to be in the proper order. I removed the setSize method and replaced it with the pack method. We don't care how big the JFrame is. We care how big the drawing panel is.
I created a drawing panel from a JPanel. Here, we set the preferred size of the drawing panel. We extend a JPanel so we can override the paintComponent method.
The paintComponent method does nothing but paint the drawing rectangle. No calculations or anything but painting is done in the paintComponent method. I added a call to the super paintComponent method to maintain the Swing paint chain and clear the drawing panel before I paint the drawing rectangle. I draw the rectangle using the x and y coordinates as the center of the rectangle, rather than the upper left corner. This is the one transformation I do in the drawing code.
I created a drawing animation from a Runnable. You can use a Swing Timer if you want. I find it easier to create my own animation code. This is the GUI controller. Here is where we do the calculations, update the model, and repaint the drawing panel. In the repaint method, I use the SwingUtilities invokeLater method to do the painting on the Event Dispatch thread. I do this because the animation thread is a separate thread.
Here's the code. I put all the classes together so I could paste the code easier. You should separate the classes into different files.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Q3_Circular implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Q3_Circular());
}
private static final int DRAWING_WIDTH = 300;
private static final int DRAWING_HEIGHT = DRAWING_WIDTH;
private DrawingRectangle drawingRectangle;
public Q3_Circular() {
int center = DRAWING_WIDTH / 2;
Rectangle2D rectangle = new Rectangle2D.Double(center, center, 32D, 32D);
drawingRectangle = new DrawingRectangle(Color.RED, rectangle);
}
#Override
public void run() {
JFrame frame = new JFrame("Animated Square");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawingPanel drawingPanel = new DrawingPanel(DRAWING_WIDTH,
DRAWING_HEIGHT, drawingRectangle);
frame.add(drawingPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
new Thread(new DrawingAnimation(drawingPanel, drawingRectangle))
.start();
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 8226587438110549806L;
private DrawingRectangle drawingRectangle;
public DrawingPanel(int width, int height,
DrawingRectangle drawingRectangle) {
this.setPreferredSize(new Dimension(width, height));
this.drawingRectangle = drawingRectangle;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(drawingRectangle.getColor());
Rectangle2D rectangle = drawingRectangle.getRectangle();
int x = (int) Math.round(rectangle.getX());
int y = (int) Math.round(rectangle.getY());
int width = (int) Math.round(rectangle.getWidth());
int height = (int) Math.round(rectangle.getHeight());
g.fillRect(x - width / 2, y - height / 2, width, height);
}
}
public class DrawingAnimation implements Runnable {
private DrawingPanel drawingPanel;
private DrawingRectangle drawingRectangle;
public DrawingAnimation(DrawingPanel drawingPanel,
DrawingRectangle drawingRectangle) {
this.drawingPanel = drawingPanel;
this.drawingRectangle = drawingRectangle;
}
#Override
public void run() {
int xCenter = drawingPanel.getWidth() / 2;
int yCenter = drawingPanel.getHeight() / 2;
double radius = drawingPanel.getWidth() / 3;
for (int degree = 0; degree < 360; degree++) {
double radians = Math.toRadians((double) degree);
double x = radius * Math.cos(radians) + xCenter;
double y = radius * Math.sin(radians) + yCenter;
drawingRectangle.setRectangleOrigin(x, y);
repaint();
sleep(100L);
}
}
private void sleep(long interval) {
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
}
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
drawingPanel.repaint();
}
});
}
}
public class DrawingRectangle {
private final Color color;
private Rectangle2D rectangle;
public DrawingRectangle(Color color, Rectangle2D rectangle) {
this.color = color;
this.rectangle = rectangle;
}
public void setRectangleOrigin(double x, double y) {
rectangle
.setRect(x, y, rectangle.getWidth(), rectangle.getHeight());
}
public Color getColor() {
return color;
}
public Rectangle2D getRectangle() {
return rectangle;
}
}
}
I'm new to Java and I want to try some graphic things with it. I want to generate two circles with two different colors and different positions. My code:
Paint Class:
package de.test.pkg;
import javax.swing.*;
public class paint {
public static void main(String[] args) throws Exception{
JFrame frame = new JFrame("Titel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Circle d = new Circle();
Circle r = new CircleRed();
frame.add(d);
frame.add(r);
frame.setSize(600,200);
frame.setVisible(true);
}
}
Circle class
package de.test.pkg;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Circle extends JPanel {
private double iconRadius = 100;
private Color defaultColor = new Color(89,104,99);
private int positionX = 0;
private int positionY = 0;
private Ellipse2D iconBody = new Ellipse2D.Double(getPositionX(),getPositionY(),iconRadius,iconRadius);
public Icon(){
}
public Color getDefaultColor() {
return defaultColor;
}
public void setDefaultColor(Color defaultColor) {
this.defaultColor = defaultColor;
}
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d);
this.setBackground(new Color(255,255,255));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(getDefaultColor());
g2d.draw(iconBody);
g2d.fill(iconBody);
}
}
CircleRed class
package de.design.pkg;
import java.awt.Color;
public class CircleRed extends Circle {
private Color defaultColor = Color.RED;
private int positionX = 120;
private int positionY = 0;
public CircleRed() {
}
public Color getDefaultColor() {
return defaultColor;
}
public void setDefaultColor(Color defaultColor) {
this.defaultColor = defaultColor;
}
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
}
The Result is that the Circles have the same positions.
My questions are:
Why do they have the same positions?
Is this a good way to do that or are there better solutions? I want to use a class so please don't gave me answers with do all that paint thing in the Main.
Is there a better way to hold the position. Maybe in an array? But how should the setter and getter look like if I want to return array[position]?
If I want to set the Position from the Main function. How can I do this?
The Result is that the Circles have the same positions.
(1) Why do they have the same positions?
Not really. The result is that only CircleRed is displayed. Your problem here is not with painting, it's with adding components to a container with a suitable layout manager. The lines
Circle d = new Circle();
Circle r = new CircleRed();
frame.add(d);
frame.add(r);
add r instead of d. This is because JFrame uses BorderLayout by default and you are replacing the center component d with r the line after. Just to show the point, add the line
frame.setLayout(new GridLayout(1, 2));
(2) Is this a good way to do that or are there better solutions? I want to use a class so please don't gave me answers with do all that paint thing in the Main.
It depends on what you are aiming to do. I would venture a guess that if you want to practice inheritance, it would be better for you to create an abstract class for a general circle with shared code and then subclass it with concrete implementation and specific code for the various types. Otherwise, you can just create a single customizable circle class and instantiate that one with different parameters.
It's not a good practical approach in any case because the placement of the circles (which are JPanels) will be determined by the layout manager. The painting only determines the location of the painted shape in the panel. It would be better to just paint the shapes on a single big panel and not with using multiple panels.
There are a few very good answers on the site about moving components around.
(3) Is there a better way to hold the position. Maybe in an array? But how should the setter and getter look like if i want to return array[position]?
There are effectively 2 positions in your design. One is for the panels in the frame, the other is for the shapes in the panels.
For the latter, I would use a Point or just an int x, y fields in the class itself. Getters and setters are the standard ones, the setters will control the position (you will need to call repaint() though).
For the first, it is determined by the layout manager and you don't (shouldn't) control it in a pixel-prefect way. You just instruct the layout manager with "guidelines" and it does the calculations for you.
(4) If I want to set the Position from the Main function. How can i do this?
Again, depends on which position you are talking about. See above.
What your doing is very overkill for just creating two colored circles. You can just use the paint method in java.awt
public void paint(Graphics g){
g.setColor(Color.YELLOW);
g.fillOval(20,20,160,160);
g.setColor(Color.RED);
g.fillOval(60,60,80,80);
}
fillOval takes the following parameters (int x, int y, int width, int height)
You can use g.setColor(Color.NAME) to change the color of your circle. Just call this method before your draw calls.
They're in the same position because the paintComponent() method in Circle is being used for both - and it's using the position variables defined in Circle. When you have CircleRed extend Circle, you don't need to define the position variables again - you inherit them from Circle. Instead, call the setPosition() methods on CircleRed. (You don't need to define these either, they're also inherited.)
There are a variety better solutions, I think the biggest improvement would be to improve your use of inheritance.
That's a fine way to hold the position. If anything else, you could also use a Point object. (Already in Java)
To set the position from the main function, you just call for example
Circle c = new Circle();
c.setPositionX(120);
c.setPositionY(40);
You are going wrong way. You can simply draw two circles by overriding paint method of JFrame class.
Here is a sample demo program.
import java.awt.*;
/**
*
* #author Pankaj
*/
public class TestFrame extends javax.swing.JFrame {
/**
* Creates new form NewJFrame
*/
public TestFrame() {
initComponents();
setTitle("Graphics Demo");
setSize(200,200);
}
/**
* You need to override this method.
*/
#Override
public void paint(Graphics g) {
int X1 = 10; //X coordinate of first circle
int X2 = 60; //X coordinate of second circle
int Y1 = 100; //Y coordinate of first circle
int Y2 = 100; //Y coordinate of second circle
int width = 50; //Width of the circle
int height = 50; //Height of the circle
Color color1 = Color.RED; //Color of first circle
Color color2 = Color.BLUE; //Color of second circle
g.setColor(color1);
g.fillOval(X1, Y1, width, height);
g.setColor(color2);
g.fillOval(X2, Y2, width, height);
}
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setResizable(false);
pack();
}
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}
}
And here's the output
I was reading Core Java and encountered this code snippet:
package draw;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class DrawTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new DrawFrame();
frame.setTitle("DrawTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class DrawFrame extends JFrame
{
public DrawFrame()
{
add(new DrawComponent());
pack();
}
}
class DrawComponent extends JComponent
{
private static final int DEFAULT_WIDTH = 400;
private static final int DEFAULT_HEIGHT = 400;
public void paintCompent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
// draw a rectangle
double leftX = 100;
double topY = 100;
double width = 200;
double height = 150;
Rectangle2D rect = new Rectangle2D.Double(leftX, topY, width, height);
g2.draw(rect);
// draw the enclosed ellipse
Ellipse2D ellipse = new Ellipse2D.Double();
ellipse.setFrame(rect);
g2.draw(ellipse);
// draw a diagonal line
g2.draw(new Line2D.Double(leftX, topY, leftX + width, topY + height));
// draw a circle with the same center
double centerX = rect.getCenterX();
double centerY = rect.getCenterY();
double radius = 150;
Ellipse2D circle = new Ellipse2D.Double();
circle.setFrameFromCenter(centerX, centerY, centerX + radius, centerY + radius);
g2.draw(circle);
}
public Dimension getPreferredSize()
{
return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
}
}
I tried this code on Eclipse, it did run but, instead of rectangles, ellipse, diagonal lines and circle, there appeared nothing in the frame. I double-checked the code against the book, there was no typo. What is wrong?
There's a spelling mistake...
public void paintCompent(Graphics g) {
should be
public void paintComponent(Graphics g) {
This is why you should use the #Override annotation, as it will give you a compile time error when you try to override a method that doesn't exist within the parent hierarcy.
You should also be calling super.paintComponent(g); before performing any custom painting
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));
}
}