Related
I am having issues with the below program I have been working on. The program is supposed to take the users' input via a GUI and then use those to create and draw an object. After some testing I know that the object (either oval or rectangular) is being created. The issue I am running into is that the object is not being drawn within the panel. What am I doing wrong here and how can I get the draw method to be called. I am very new to the graphics methods and maybe making a simple mistake.
import java.awt.*;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
*
* Purpose: This GUI will take a users input to print a shape
*/
public class Test {
//Shape class that extends the base rectangle class
public abstract static class Shape extends Rectangle {
private static final long serialVersionUID = 1L;
// instance variables for shape class
private String color;
private Boolean solid;
private int count;
// Constructor for shape class
public Shape(Rectangle rectangle, String color, Boolean solid)
{
super(rectangle);
this.color = color;
this.solid = solid;
count++;
}
// Method that will give the number of shapes printed
public int getNoOfShapes() {
return count;
}
// method that will take the users color select and set the color
public void setColor(Graphics g) {
if(color.equalsIgnoreCase("black"))
g.setColor(Color.BLACK);
else if(color.equalsIgnoreCase("red"))
g.setColor(Color.RED);
else if(color.equalsIgnoreCase("orange"))
g.setColor(Color.ORANGE);
else if(color.equalsIgnoreCase("yellow"))
g.setColor(Color.YELLOW);
else if(color.equalsIgnoreCase("green"))
g.setColor(Color.GREEN);
else if(color.equalsIgnoreCase("blue"))
g.setColor(Color.BLUE);
else if(color.equalsIgnoreCase("magenta"))
g.setColor(Color.MAGENTA);
}
// return shape type is solid or hollow
public Boolean getSolid() {
return solid;
}
// draw method
public abstract void draw(Graphics g);
}
//Oval subclass
public static class Oval extends Shape {
private static final long serialVersionUID = 1L;
// Constructor for the oval class
public Oval(Rectangle rectangle, String color, Boolean solid) {
super(rectangle, color, solid);
}
//Draw method for the oval
#Override
public void draw(Graphics g) {
// Draw a hollow oval shape
if(super.getSolid() == false)
g.drawOval((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight());
//Draw a solid oaval shape
else if(super.getSolid() == true)
g.fillOval((int)getX(),(int) getY(), (int)getWidth(), (int)getHeight());
}
}
//Rectangular subclass
public static class Rectangular extends Shape {
private static final long serialVersionUID = 1L;
// Constructor for Rectangular class
public Rectangular(Rectangle rectangle, String color, Boolean solid) {
super(rectangle, color, solid);
}
//Method to draw a rectangle
#Override
public void draw(Graphics g) {
// Will draw a hollow rectangle
if(super.getSolid() == false)
g.drawRect((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight());
//Will draw a solid rectangle
else if(super.getSolid() == true)
g.fillRect((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight());
}
}
//Drawing class with GUI inside
public static class Drawing extends JPanel {
private static final long serialVersionUID = 1L;
// create Shape
private Shape shape1=null;
public void drawShape(Shape shape) throws OutsideBounds{
try {
if(shape.intersects(270,20,200,200))
throw new OutsideBounds("This shape will not fit into the drawing box");
}catch(OutsideBounds o) {
JOptionPane.showMessageDialog(null, o.getMessage());
}catch(Exception e) {
JOptionPane.showMessageDialog(null, "Please only enter integers ");
}
}
// Method to paint shape
#Override
public void paintComponent(Graphics g) {
try {
// print count of shapes
super.paintComponents(g);
shape1.setColor(g);
shape1.draw(g);
repaint();
}catch(Exception e) {}
}
}
public static class GUI{
// Instance variables for the GUI
// private JFrame window;
private JLabel shape;
private JLabel fillType;
private JLabel color;
private JLabel width;
private JLabel height;
private JLabel xCoordinate;
private JLabel yCoordinate;
private JLabel printCount;
private JComboBox<String> cshape;
private JComboBox<String> cfillType;
private JComboBox<String> ccolor;
private JTextField widthField;
private JTextField heightField;
private JTextField xField;
private JTextField yField;
private JButton draw;
private JButton clear;
private JButton exit;
private JPanel panel;
// Constructor that will initiate GUI variables
public GUI() {
JFrame window = new JFrame();
window.setSize(500,350); // set size fo frame
window.setDefaultCloseOperation(EXIT_ON_CLOSE);
window.setLayout(null); // set no layout
window.setLocationRelativeTo(null); // centered frame
window.setTitle("Geometric Drawing"); // title
shape=new JLabel("Shape Type");
fillType=new JLabel("Fill Type");
color=new JLabel("Color");
width=new JLabel("Width");
height=new JLabel("Height");
xCoordinate=new JLabel("x coordinate");
yCoordinate=new JLabel("y coordinate");
printCount=new JLabel("1");
cshape=new JComboBox<>(new String[] {"Oval","Rectangle"});
cfillType=new JComboBox<>(new String[] {"Solid","Hollow"});
ccolor=new JComboBox<>(new String[] {"Black","Red","Orange","Yellow","Green","Blue","Magenta"});
widthField=new JTextField();
heightField=new JTextField();
xField=new JTextField();
yField=new JTextField();
draw=new JButton("Draw");
clear = new JButton("clear");
exit = new JButton("exit");
panel=new JPanel();
// set border with title to panel
panel.setBorder(BorderFactory.createTitledBorder("Shape Drawing"));
// adding all parts to the window
window.add(shape);
window.add(fillType);
window.add(color);
window.add(width);
window.add(height);
window.add(xCoordinate);
window.add(yCoordinate);
window.add(printCount);
window.add(cshape);
window.add(cfillType);
window.add(ccolor);
window.add(widthField);
window.add(heightField);
window.add( xField);
window.add(yField);
window.add(draw);
window.add(clear);
window.add(exit);
window.add(panel);
// set positions within the window
shape.setBounds(20, 20, 100, 30);
fillType.setBounds(20, 55, 100, 30);
color.setBounds(20, 90, 100, 30);
width.setBounds(20, 125, 100, 30);
height.setBounds(20, 160, 100, 30);
xCoordinate.setBounds(20, 195, 100, 30);
yCoordinate.setBounds(20, 230, 100, 30);
printCount.setBounds(285, 40, 20, 30);
cshape.setBounds(140, 20, 100, 30);
cfillType.setBounds(140, 55, 100, 30);
ccolor.setBounds(140, 90, 100, 30);
widthField.setBounds(140, 125, 100, 30);
heightField.setBounds(140, 160, 100, 30);
xField.setBounds(140, 195, 100, 30);
yField.setBounds(140, 230, 100, 30);
draw.setBounds(230, 280, 80, 30);
clear.setBounds(120, 280,80,30);
exit.setBounds(330, 280,80,30);
panel.setBounds(270, 20, 200, 200);
// adding action listener to draw button
// draw.addActionListener((ActionListener) this);
window.setVisible(true); // make frame visible
draw.addActionListener(
new java.awt.event.ActionListener(){
public void actionPerformed(java.awt.event.ActionEvent evt){
try {
Drawing d1 = new Drawing();
Shape shape;
String color;
int xCoord = 0, yCoord = 0, width = 0, height = 0;
//Point accounting for the needed shift
xCoord = Integer.parseInt(xField.getText() + 270);
yCoord = Integer.parseInt(yField.getText() + 50);
width = Integer.parseInt(widthField.getText());
height = Integer.parseInt(heightField.getText());
Rectangle r1 = new Rectangle (xCoord, yCoord, width, height);
// Point p = new Point(shapeX+270, shapeY+50);
//setting dimensions based off user input
//Dimension d = new Dimension(shapeWidth, shapeHeight);
if(((String) cshape.getSelectedItem()).equalsIgnoreCase("oval")){
shape = new Oval(r1, (String)ccolor.getSelectedItem(), true);
System.out.print("creating oval");
}
else{
shape = new Rectangular(r1,(String)ccolor.getSelectedItem(), true);}
d1.drawShape(shape);
window.repaint(); // call paint() method
}catch(NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Please only enter integers ");
} catch (OutsideBounds ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
//Action Listener for clear button
clear.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//Clearing all text fields
widthField.setText("");
heightField.setText("");
xField.setText("");
yField.setText("");
}
});
//Action Liistener for exit button
exit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//message to the user
JOptionPane.showMessageDialog(null,"Program is ending");
window.dispose();}
});
}
}
// Out of bounds class
public static class OutsideBounds extends Exception {
private static final long serialVersionUID = 1L;
// parameterized constructor
public OutsideBounds(String errorMessage) {
// call super class parameterized constructor
super(errorMessage);
}
}
public static void main(String[] args) {
GUI G1 = new GUI(); // Creating GUI
}
}```
There are a number small problems, which are combining to produce a larger problem.
null layouts are just a bad idea. Take the time to learn how to use and mix appropriate layouts
Don't use String as a carrier of information if you can avoid it. It's too easy to screw up. In you case, learn how to make use of a ListCellRenderer to customise the JComoboBox so it can carry Color as it's base value
There should be a single instance of Drawing which should render ALL the shapes. You then add each new shape to it. Instead of trying to create new instances for each individual shape.
In order for something to be painted, it must be added to something which can be painted. This means that the Drawing panel needs to be added to your frame at some point (or a contained which is directly or indirectly contained within your frame).
This is a very basic re-work of your code. It will generate a oval or rectangle at a random location with a random color. I'll leave you to fill in the rest of your requirements around it
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import static javax.swing.WindowConstants.EXIT_ON_CLOSE;
public class Test {
//Shape class that extends the base rectangle class
public abstract static class Shape extends Rectangle {
private static final long serialVersionUID = 1L;
// instance variables for shape class
private String color;
private Boolean solid;
private int count;
// Constructor for shape class
public Shape(Rectangle rectangle, String color, Boolean solid) {
super(rectangle);
this.color = color;
this.solid = solid;
count++;
}
// Method that will give the number of shapes printed
public int getNoOfShapes() {
return count;
}
// method that will take the users color select and set the color
public void setColor(Graphics g) {
if (color.equalsIgnoreCase("black")) {
g.setColor(Color.BLACK);
} else if (color.equalsIgnoreCase("red")) {
g.setColor(Color.RED);
} else if (color.equalsIgnoreCase("orange")) {
g.setColor(Color.ORANGE);
} else if (color.equalsIgnoreCase("yellow")) {
g.setColor(Color.YELLOW);
} else if (color.equalsIgnoreCase("green")) {
g.setColor(Color.GREEN);
} else if (color.equalsIgnoreCase("blue")) {
g.setColor(Color.BLUE);
} else if (color.equalsIgnoreCase("magenta")) {
g.setColor(Color.MAGENTA);
}
}
// return shape type is solid or hollow
public Boolean getSolid() {
return solid;
}
// draw method
public abstract void draw(Graphics g);
}
//Oval subclass
public static class Oval extends Shape {
private static final long serialVersionUID = 1L;
// Constructor for the oval class
public Oval(Rectangle rectangle, String color, Boolean solid) {
super(rectangle, color, solid);
}
//Draw method for the oval
#Override
public void draw(Graphics g) {
// Draw a hollow oval shape
if (super.getSolid() == false) {
g.drawOval((int) getX(), (int) getY(), (int) getWidth(), (int) getHeight());
} //Draw a solid oaval shape
else if (super.getSolid() == true) {
g.fillOval((int) getX(), (int) getY(), (int) getWidth(), (int) getHeight());
}
}
}
//Rectangular subclass
public static class Rectangular extends Shape {
private static final long serialVersionUID = 1L;
// Constructor for Rectangular class
public Rectangular(Rectangle rectangle, String color, Boolean solid) {
super(rectangle, color, solid);
}
//Method to draw a rectangle
#Override
public void draw(Graphics g) {
// Will draw a hollow rectangle
if (super.getSolid() == false) {
g.drawRect((int) getX(), (int) getY(), (int) getWidth(), (int) getHeight());
} //Will draw a solid rectangle
else if (super.getSolid() == true) {
g.fillRect((int) getX(), (int) getY(), (int) getWidth(), (int) getHeight());
}
}
}
//Drawing class with GUI inside
public static class Drawing extends JPanel {
private List<Shape> shapes;
private List<String> colors;
private final Random rnd = new Random();
public Drawing() {
shapes = new ArrayList<>(25);
colors = new ArrayList<>();
colors.add("black");
colors.add("red");
colors.add("orange");
colors.add("yellow");
colors.add("green");
colors.add("blue");
colors.add("magenta");
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected Rectangle randomBounds() {
int minSize = 10;
int avaliableWidth = getWidth() - minSize;
int avaliableHeight = getHeight() - minSize;
int width = Math.max(minSize, rnd.nextInt(avaliableWidth / 4));
int height = Math.max(minSize, rnd.nextInt(avaliableHeight / 4));
int x = rnd.nextInt(avaliableWidth - width);
int y = rnd.nextInt(avaliableHeight - height);
Rectangle bounds = new Rectangle(x, y, width, height);
return bounds;
}
protected String randomColor() {
Collections.shuffle(colors);
String color = colors.get(0);
return color;
}
public void addCircle() {
shapes.add(new Oval(randomBounds(), randomColor(), rnd.nextBoolean()));
repaint();
}
public void addRectangle() {
shapes.add(new Rectangular(randomBounds(), randomColor(), rnd.nextBoolean()));
repaint();
}
// Method to paint shape
#Override
public void paintComponent(Graphics g) {
// print count of shapes
super.paintComponents(g);
for (Shape shape : shapes) {
Graphics2D g2d = (Graphics2D) g.create();
shape.setColor(g2d);
shape.draw(g2d);
g2d.dispose();
}
}
}
public static class GUI {
private Drawing drawing;
// Constructor that will initiate GUI variables
public GUI() {
JFrame window = new JFrame();
window.setDefaultCloseOperation(EXIT_ON_CLOSE);
window.setTitle("Geometric Drawing"); // title
JPanel controls = new JPanel(new GridLayout(0, 1));
controls.add(makeButton("Circle"));
controls.add(makeButton("Rectangle"));
drawing = new Drawing();
window.add(controls, BorderLayout.WEST);
window.add(drawing);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true); // make frame visible
}
protected JButton makeButton(String name) {
JButton btn = new JButton(name);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ("Circle".equals(e.getActionCommand())) {
drawing.addCircle();
} else if ("Rectangle".equals(e.getActionCommand())) {
drawing.addRectangle();
}
}
});
return btn;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
GUI G1 = new GUI(); // Creating GUI
}
});
}
}
}
Take a look at:
Laying Out Components Within a Container
How to Use Combo Boxes
for more details
I need to draw a ring, with given thickness, that looks something like this:
The center must be transparent, so that it doesn't cover previously drawn shapes. (or other rings) I've tried something like this:
//g is a Graphics2D object
g.setColor(Color.RED);
g.drawOval(x,y,width,height);
g.setColor(Color.WHITE);
g.drawOval(x+thickness,y+thickness,width-2*thickness,height-2*thickness);
which draws a satisfactory ring, but it covers other shapes; the interior is white, not transparent. How can I modify/rewrite my code so that it doesn't do that?
You can create an Area from an Ellipse2D that describes the outer circle, and subtract the ellipse that describes the inner circle. This way, you will obtain an actual Shape that can either be drawn or filled (and this will only refer to the area that is actually covered by the ring!).
The advantage is that you really have the geometry of the ring available. This allows you, for example, to check whether the ring shape contains a certain point, or to fill it with a Paint that is more than a single color:
Here is an example, the relevant part is the createRingShape method:
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RingPaintTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
RingPaintTestPanel p = new RingPaintTestPanel();
f.getContentPane().add(p);
f.setSize(800,800);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class RingPaintTestPanel extends JPanel
{
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.RED);
g.drawString("Text", 100, 100);
g.drawString("Text", 300, 100);
Shape ring = createRingShape(100, 100, 80, 20);
g.setColor(Color.CYAN);
g.fill(ring);
g.setColor(Color.BLACK);
g.draw(ring);
Shape otherRing = createRingShape(300, 100, 80, 20);
g.setPaint(new GradientPaint(
new Point(250, 40), Color.RED,
new Point(350, 200), Color.GREEN));
g.fill(otherRing);
g.setColor(Color.BLACK);
g.draw(otherRing);
}
private static Shape createRingShape(
double centerX, double centerY, double outerRadius, double thickness)
{
Ellipse2D outer = new Ellipse2D.Double(
centerX - outerRadius,
centerY - outerRadius,
outerRadius + outerRadius,
outerRadius + outerRadius);
Ellipse2D inner = new Ellipse2D.Double(
centerX - outerRadius + thickness,
centerY - outerRadius + thickness,
outerRadius + outerRadius - thickness - thickness,
outerRadius + outerRadius - thickness - thickness);
Area area = new Area(outer);
area.subtract(new Area(inner));
return area;
}
}
You can use the Shape and Area classes to create interesting effects:
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;
import java.net.*;
public class Subtract extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int size = 100;
int thickness = 10;
int innerSize = size - (2 * thickness);
Shape outer = new Ellipse2D.Double(0, 0, size, size);
Shape inner = new Ellipse2D.Double(thickness, thickness, innerSize, innerSize);
Area circle = new Area( outer );
circle.subtract( new Area(inner) );
int x = (getSize().width - size) / 2;
int y = (getSize().height - size) / 2;
g2d.translate(x, y);
g2d.setColor(Color.CYAN);
g2d.fill(circle);
g2d.setColor(Color.BLACK);
g2d.draw(circle);
g2d.dispose();
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Subtract");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Subtract());
frame.setLocationByPlatform( true );
frame.setSize(200, 200);
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
Using an Area you can also add multiple Shapes together or get the intersection of multiple Shapes.
You could use graphics.setStroke(...) for this. This way the center will be fully transparent and therefore won't cover previously drawn shapes. In my example I had to do some additional calculations because of this method though, to make sure the displayed x and y coordinates are actually the same as the ones of the Ring instance:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example {
public Example() {
ArrayList<Ring> rings = new ArrayList<Ring>();
rings.add(new Ring(10, 10, 100, 20, Color.CYAN));
JPanel panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D gg = (Graphics2D) g.create();
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Ring ring : rings) {
// Previously drawn
gg.setColor(Color.BLACK);
String str = "Hello!";
gg.drawString(str, ring.getX() + (ring.getWidth() - gg.getFontMetrics().stringWidth(str)) / 2,
ring.getY() + ring.getHeight() / 2 + gg.getFontMetrics().getAscent());
// The actual ring
ring.draw(gg);
}
gg.dispose();
}
};
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
}
class Ring {
private int x, y, width, height, thickness;
private Color color;
public Ring(int x, int y, int width, int height, int thickness, Color color) {
setX(x);
setY(y);
setWidth(width);
setHeight(height);
setThickness(thickness);
setColor(color);
}
public Ring(int x, int y, int radius, int thickness, Color color) {
this(x, y, radius * 2, radius * 2, thickness, color);
}
public void draw(Graphics2D gg) {
Stroke oldStroke = gg.getStroke();
Color oldColor = gg.getColor();
gg.setColor(Color.BLACK);
gg.setStroke(new BasicStroke(getThickness()));
gg.drawOval(getX() + getThickness() / 2, getY() + getThickness() / 2, getWidth() - getThickness(),
getHeight() - getThickness());
gg.setColor(getColor());
gg.setStroke(new BasicStroke(getThickness() - 2));
gg.drawOval(getX() + getThickness() / 2, getY() + getThickness() / 2, getWidth() - getThickness(),
getHeight() - getThickness());
gg.setStroke(oldStroke);
gg.setColor(oldColor);
}
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 getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getThickness() {
return thickness;
}
public void setThickness(int thickness) {
this.thickness = thickness;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
}
I am making a flappy bird like plane game, and in one class I have the background that moves, and then I add it to the jPanel in the main which is in its own class, in another class I have the player and I add that to the main Jpanel. But whichever class I add first dissapears when I add the second class to the JPanel. Here is my background class:
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class map1 extends JPanel implements ActionListener{
Timer t = new Timer(5, this);
int rect1x = 1000, rect1y = 0;
int rect2x = 1250, rect2y = 0;
int rect3x = 1500, rect3y = 0;
int rect4x = 1750, rect4y = 0;
int rect5x = 2000, rect5y = 0;
int rect1dx = 1000, rect1dy = 300;
int rect2dx = 1250, rect2dy = 350;
int rect3dx = 1500, rect3dy = 400;
int rect4dx = 1750, rect4dy = 350;
int rect5dx = 2000, rect5dy = 300;
public map1(){t.start();}
public void rectset1(Graphics g){
g.drawRect(rect1x, rect1y, 50, 100);
g.drawRect(rect1dx, rect1dy, 50, 300);
}
public void rect2(Graphics g){
g.drawRect(rect2x, rect2y, 50, 150);
g.drawRect(rect2dx, rect2dy, 50, 300);
}
public void rect3(Graphics g){
g.drawRect(rect3x, rect3y, 50, 200);
g.drawRect(rect3dx, rect3dy, 50, 300);
}
public void rect4(Graphics g){
g.drawRect(rect4x, rect4y, 50, 150);
g.drawRect(rect4dx, rect4dy, 50, 300);
}
public void rect5(Graphics g){
g.drawRect(rect5x, rect5y, 50, 100);
g.drawRect(rect5dx, rect5dy, 50, 300);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
rectset1(g);
rect2(g);
rect3(g);
rect4(g);
rect5(g);
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
rect1x--;
rect2x --;
rect3x --;
rect4x --;
rect5x --;
rect1dx --;
rect2dx --;
rect3dx --;
rect4dx --;
rect5dx --;
}
}
And here is my plane class:
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class player extends JPanel implements ActionListener, KeyListener {
int x = 200, y = 300;
Timer t = new Timer(5, this);
public void space(){
y+=20;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawOval(x, y, 50, 50);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if(code == KeyEvent.VK_SPACE){space();}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
y--;
}
}
And lastly my main:
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class testMain extends JFrame{
public testMain(){}
public static void main(String args[]){
map1 m = new map1();
player q = new player();
JFrame j = new JFrame();
j.setSize(800,600);
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.add(m);
j.add(q);
j.setVisible(true);
}
}
You should have a single JPanel that paints itself by overriding paintComponent(). That JPanel class should have a reference to anything that needs to be drawn. From the paintComponent() method, you just iterate over each game object that needs to be drawn and draw it. Better yet, each game object should have a drawMe(Graphics g) method that draws itself, and your paintComponent() method can just pass its Graphics instance into each of those methods.
public class GamePanel extends JPanel{
//example GameObjects, these could be in a list
GameObject bird = new Bird();
GameObject cloud = new Cloud();
public void paintComponent(Graphics g){
bird.drawMe(g);
cloud.drawMe(g);
}
}
First off in your main class you are extending JFrame but then instantiating it as well which is redundant. You should do either of the two, not both!
Ex:
public class main extends JFrame{
public main(){
setSize(800,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(m);
add(q);
setVisible(true);
}
}
Secondly answering your question, you should always have a single class that does all the drawing for your game. Lets call this the Board class. You could have other classes that have functions to draw, but these functions should be called in your Board class within the paintComponent() function.
Note: Also make sure to do this -
void paintComponent(Graphics g){
super.paintComponent(g);
......
g.dispose();
}
I have a 3x3 check board-like image rendered on a JPanel which is added onto a JFrame. Then I have 9 more JPanels (1 on top of each square) and on click something needs to be drawn on the corresponding square. My problem is that it only works for the top-left square. The rest of the drawings seem to be drawn below the checkboard image. So if I comment out the part that loads the checkboard image,and click as if they were there then the drawings appear correctly. I get the same result with a layered pane. Absolute positioning is used and the coordinates seem to be correct since if I remove the checkboard image then the drawings appear where they should and the drawings do not occupy more than a square.
My code is structured as follows:
'main' class creates the frame and adds an instance of another class which extends JPanel and which also draws the checkboard image using paintComponent(Graphics g).
'main' class has also 9 instances added of a class that extends JPanel and draws something on a mouse click using paintComponent(Graphics g). Each instance is placed on top of a square
Please note that because I was going to do it with just Rectangles I named the second class Rectangles but it is rectangualar JPanels not java Rectangle instances
Code:
public class Main3
{
private JFrame frame=new JFrame("");
private Rectangles rect00=new Rectangles(0,0,129,129);
private Rectangles rect01=new Rectangles(136,0,129,129);
private Rectangles rect02=new Rectangles(268,0,129,129);
private Rectangles rect10=new Rectangles(0,136,129,129);
private Rectangles rect11=new Rectangles(134,136,129,129);
private Rectangles rect12=new Rectangles(269,137,129,129);
private Rectangles rect20=new Rectangles(0,270,129,129);
private Rectangles rect21=new Rectangles(136,269,129,129);
private Rectangles rect22=new Rectangles(269,270,129,129);
public void Display()
{
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(null);
frame.setSize(600,400);
sub inter=new sub();
inter.setLayout(null);
inter.setBounds(0,0,600,400);
inter.setSize(600,400);
rect00.setBounds(rect00.getX(),rect00.getY(),rect00.getWidth(),rect00.getHeight());
rect01.setBounds(rect01.getX(),rect01.getY(),rect01.getWidth(),rect01.getHeight());
rect02.setBounds(rect02.getX(),rect02.getY(),rect02.getWidth(),rect02.getHeight());
rect10.setBounds(rect10.getX(),rect10.getY(),rect10.getWidth(),rect10.getHeight());
rect11.setBounds(rect11.getX(),rect11.getY(),rect11.getWidth(),rect11.getHeight());
rect12.setBounds(rect12.getX(),rect12.getY(),rect12.getWidth(),rect12.getHeight());
rect20.setBounds(rect20.getX(),rect20.getY(),rect20.getWidth(),rect20.getHeight());
rect21.setBounds(rect21.getX(),rect21.getY(),rect21.getWidth(),rect21.getHeight());
rect22.setBounds(rect22.getX(),rect22.getY(),rect22.getWidth(),rect22.getHeight());
rect00.setOpaque(false);
rect01.setOpaque(false);
rect02.setOpaque(false);
rect10.setOpaque(false);
rect11.setOpaque(false);
rect12.setOpaque(false);
rect20.setOpaque(false);
rect21.setOpaque(false);
rect22.setOpaque(false);
inter.add(rect00);
inter.add(rect01);
inter.add(rect02);
inter.add(rect10);
inter.add(rect11);
inter.add(rect12);
inter.add(rect20);
inter.add(rect21);
inter.add(rect22);
frame.add(inter);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String args[])
{
new main().Display();
}
private class sub extends JPanel
{
private BufferedImage image;
public sub ()
{
try
{
image=ImageIO.read(new File("image.jpg"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(600,400));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
}
}
This is the other class
public class Rectangles extends JPanel implements MouseListener
{
private int Posx;
private int Posy;
private int width;
private int height;
private boolean selected=false;
public Rectangles(int Posx,int Posy,int width,int height)
{
this.Posx=Posx;
this.Posy=Posy;
this.width=width;
this.height=height;
this.addMouseListener(this);
}
#Override
protected void paintComponent(Graphics g)
{
if(selected==true)
{
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g2);
g2.setColor(new Color(250, 235, 215));
g2.drawRect(Posx,Posy,width,height);
Graphics2D g3=(Graphics2D)g;
g2.setColor(new Color(0,0,0));
g3.setStroke(new BasicStroke(20));
g3.drawLine(Posx,Posy,Posx+width,Posy+height);
g3.drawLine(Posx+width,Posy,Posx,Posy+height);
}
}
public int getX()
{
return Posx;
}
public int getY()
{
return Posy;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public void setSelected()
{
selected=true;
}
#Override
public void mouseClicked(MouseEvent arg0)
{
}
#Override
public void mouseEntered(MouseEvent arg0)
{
}
public void mouseExited(MouseEvent arg0)
{
}
#Override
public void mousePressed(MouseEvent arg0)
{
}
#Override
public void mouseReleased(MouseEvent arg0)
{
selected=true;
repaint();
}
}
1) You dont honor the components paint chain.
As per java docs for paintComponent(Graphics g):
Further, if you do not invoker super's implementation you must honour
the opaque property, that is if this component is opaque, you must
completely fill in the background in a non-opaque color. If you do not
honor the opaque property you will likely see visual artifacts.
2) super.paintComponent would in most cases be the first call in the method.
3) But there is more, your cast to Graphics2D twice, that should not be done:
Graphics2D g2 = (Graphics2D) g;
...
Graphics2D g3=(Graphics2D)g;
omit the g3 its not needed you already have casted to a Graphics2D object
4) Another problem lies here in sub class. You do this in your main code:
inter.add(rect00);
inter.add(rect01);
...
but in inter which is your variable name for the instance of sub class you only have:
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
Thus it will only draw a single image no matter how many rectangles you add!
Also dont do
g2.drawLine(Posx, Posy, Posx + width, Posy + height); rather
g2.drawLine(0, 0, Posx + width, Posy + height); as the JPanel has been added at co-ordinates x and y on its container, when you draw on the JPanel we want to start at the top left i.e 0,0, changing the value would move the image further down on its conatiner
See fixed code here:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
private JFrame frame = new JFrame("");
private Rectangles rect00 = new Rectangles(0, 0, 129, 129);
private Rectangles rect01 = new Rectangles(136, 0, 129, 129);
private Rectangles rect02 = new Rectangles(268, 0, 129, 129);
private Rectangles rect10 = new Rectangles(0, 136, 129, 129);
private Rectangles rect11 = new Rectangles(134, 136, 129, 129);
private Rectangles rect12 = new Rectangles(269, 137, 129, 129);
private Rectangles rect20 = new Rectangles(0, 270, 129, 129);
private Rectangles rect21 = new Rectangles(136, 269, 129, 129);
private Rectangles rect22 = new Rectangles(269, 270, 129, 129);
public void Display() {
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(null);
frame.setSize(600, 400);
sub inter = new sub();
inter.setLayout(null);
inter.setBounds(0, 0, 600, 400);
inter.setSize(600, 400);
rect00.setBounds(rect00.getX(), rect00.getY(), rect00.getWidth(), rect00.getHeight());
rect01.setBounds(rect01.getX(), rect01.getY(), rect01.getWidth(), rect01.getHeight());
rect02.setBounds(rect02.getX(), rect02.getY(), rect02.getWidth(), rect02.getHeight());
rect10.setBounds(rect10.getX(), rect10.getY(), rect10.getWidth(), rect10.getHeight());
rect11.setBounds(rect11.getX(), rect11.getY(), rect11.getWidth(), rect11.getHeight());
rect12.setBounds(rect12.getX(), rect12.getY(), rect12.getWidth(), rect12.getHeight());
rect20.setBounds(rect20.getX(), rect20.getY(), rect20.getWidth(), rect20.getHeight());
rect21.setBounds(rect21.getX(), rect21.getY(), rect21.getWidth(), rect21.getHeight());
rect22.setBounds(rect22.getX(), rect22.getY(), rect22.getWidth(), rect22.getHeight());
rect00.setOpaque(false);
rect01.setOpaque(false);
rect02.setOpaque(false);
rect10.setOpaque(false);
rect11.setOpaque(false);
rect12.setOpaque(false);
rect20.setOpaque(false);
rect21.setOpaque(false);
rect22.setOpaque(false);
inter.addPanel(rect00);
inter.addPanel(rect01);
inter.addPanel(rect02);
inter.addPanel(rect10);
inter.addPanel(rect11);
inter.addPanel(rect12);
inter.addPanel(rect20);
inter.addPanel(rect21);
inter.addPanel(rect22);
frame.add(inter);
frame.setResizable(false);
frame.setVisible(true);
}
public static void main(String args[]) {
new Test().Display();
}
private class sub extends JPanel {
private BufferedImage image;
private ArrayList<Rectangles> rects = new ArrayList<>();
public sub() {
try {
image = ImageIO.read(new File("c:/image.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return (new Dimension(600, 400));
}
void addPanel(Rectangles r) {
rects.add(r);
add(r);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Rectangles r : rects) {
g.drawImage(image, r.getX(), r.getY(), null);
}
}
}
}
class Rectangles extends JPanel implements MouseListener {
private int Posx;
private int Posy;
private int width;
private int height;
private boolean selected = false;
public Rectangles(int Posx, int Posy, int width, int height) {
this.Posx = Posx;
this.Posy = Posy;
this.width = width;
this.height = height;
this.addMouseListener(this);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (selected == true) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(new Color(250, 235, 215));
g2.drawRect(0,0, width, height);
g2.setColor(new Color(0, 0, 0));
g2.setStroke(new BasicStroke(20));
g2.drawLine(0,0, width,height);
g2.drawLine(getWidth(),0, 0, height);
}
}
public int getX() {
return Posx;
}
public int getY() {
return Posy;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void setSelected() {
selected = true;
}
#Override
public void mouseClicked(MouseEvent arg0) {
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
selected = true;
repaint();
}
}
A few other pointers:
Dont use Absolute/Null layout. A GridLayout or GridBagLayout would suit your needs fine. (see here for more.)
Dont do JFrame#setSize(...); rather use Correct LayoutManager and call pack() on JFrame before setting it visible.
Dont call setSize on your Rectangles instances, simply override getPreferredSize like you did with sub panel??
No need for implementing MouseListener, just use MouseAdapter thus giving you the freedom to choose which methods to override and not just override all.
Have a read on Concurrency in Swing especailly Event-Dispatch-Thread
I've been trying to do this assignment and for it to work I need the event mousePressed to work but for some reason it's not responding to the mouse. Its purpose is to paint another yellow circle when the mouse is pressed.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class CatchMonster extends JPanel
{
private int height = 300;
private int width = 600;
private final int delay = 4001;
private ImageIcon image;
private Timer timer;
private int x, y, moveX, moveY, xPoint, yPoint;
public CatchMonster() {
DotListener dot = new DotListener();
addMouseListener(dot);
timer = new Timer(delay, new timerListener());
x = 40;
y = 40;
moveX = moveY = 3;
setPreferredSize(new Dimension(width, height));
setBackground(Color.black);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
g.setColor(Color.yellow);
g.fillOval(x, y, 60, 60);
}
private class timerListener implements ActionListener
{
public void actionPerformed(ActionEvent e) {
Random gn = new Random();
x = gn.nextInt(width);
y = gn.nextInt(height);
repaint();
}
}
private class DotListener implements MouseListener
{
public void mousePressed(MouseEvent event)
{
repaint();
}
#Override
public void mouseClicked(MouseEvent event) {
}
#Override
public void mouseEntered(MouseEvent event) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent event) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent event) {
// TODO Auto-generated method stub
}
}
}
I need the event mousePressed to work but for some reason it's not responding to the mouse. Its purpose is to paint another yellow circle when the mouse is pressed.
But it won't paint another circle as all it does is call repaint(), and how is that going to paint anything new? If you want it to create another circle, you'll have to give it logic to do so. For instance, if you want to paint more than one yellow oval, you'll want to create an ArrayList of Point objects and add a Point into that array list in the mousePressed method. Then in the paintComponent method, you can iterate through the array list, painting ovals for each Point it contains.
In addition, you want to change this:
public void paintComponent(Graphics g) {
super.paintComponents(g); // this is not the "super" method of paintComponent
g.setColor(Color.yellow);
g.fillOval(x, y, 60, 60);
}
to this:
public void paintComponent(Graphics g) {
super.paintComponent(g); // See the difference?
g.setColor(Color.yellow);
g.fillOval(x, y, 60, 60);
}
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class CatchMonster extends JPanel {
private int height = 300;
private int width = 600;
private final int delay = 4001;
private ImageIcon image;
private Timer timer;
private int x, y, moveX, moveY, xPoint, yPoint;
private List<Point> points = new ArrayList<Point>();
public CatchMonster() {
DotListener dot = new DotListener();
addMouseListener(dot);
timer = new Timer(delay, new timerListener());
x = 40;
y = 40;
moveX = moveY = 3;
setPreferredSize(new Dimension(width, height));
setBackground(Color.black);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.yellow);
g.fillOval(x, y, 60, 60);
int radius = 30;
g.setColor(Color.green);
for (Point p : points) {
int x = p.x - radius;
int y = p.y - radius;
g.fillOval(x, y, 2 * radius, 2 * radius);
}
}
private class timerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
Random gn = new Random();
x = gn.nextInt(width);
y = gn.nextInt(height);
repaint();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new CatchMonster());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private class DotListener extends MouseAdapter {
public void mousePressed(MouseEvent event) {
points.add(event.getPoint());
repaint();
}
}
}