How to clear components in JPanel? - java

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

Okay, so by calling clear() you set a variable isClear to true. And then in your paintComponent you say:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(isClear)
return;
which means 'if isClear is true, don't paint anything' (which it is, you just set it to true with clear()). So, no wonder.
Anyway, I think in the clear method, you might want to do listShape.clear() instead of setting that boolean.

Related

Why can't I draw my line without the use of an infinitely running while loop

I have to use a permanently running while loop to draw my line, otherwise the line renders for a millisecond and goes away. It may look fine but I may add hundreds upon hundreds of methods that would be running in one loop, that may cause some performance issues.
Debug (The main class)
public class Debug {
public static void main(String[] args) {
boolean running = true;
Window test = new Window(800, 600, 100, 10, true, "This is the title");
Renderer3D renderer = new Renderer3D();
// my permanantly running while loop
while (running) {
renderer.draw();
}
test.addRenderer();
}
}
Window (the class to create the window)
public class Window
static int width;
static int height;
static int x;
static int y;
static boolean v;
static String title;
public Window() {}
public Window(int WIDTH, int HEIGHT, int X, int Y, boolean V, String TITLE) {
// TODO Auto-generated constructor stub
width = WIDTH;
height = HEIGHT;
x = X;
y = Y;
v = V;
title = TITLE;
}
public static JFrame window = new JFrame();
public void setWindowVisible(boolean v) {
window.setVisible(v);
}
public void setWindowSize(int Width, int Height) {
window.setSize(Width, Height);
}
public void setWindowLocation(int X, int Y) {
window.setLocation(X, Y);
}
public void setWindowTitle(String TITLE) {
window.setTitle(TITLE);
}
public static void displayProperties() {
window.setSize(width, height);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(x, y);
window.setTitle(title);
window.setVisible(v);
window.setLocationRelativeTo(null);
}
public void addRenderer() {
window.pack();
displayProperties();
}
public JFrame returnWindow() {
return window;
}
}
Renderer (the class to draw things)
public class Renderer3D extends JFrame {
public boolean executed;
public boolean running = true;
public Thread thread;
public Canvas canvas = new Canvas() {
public void paint(Graphics g) {
}
};
#SuppressWarnings("deprecation")
public Renderer3D() {
canvas.setBackground(Color.black);
Window.window.add(canvas);
Window.displayProperties();
Window.window.show();
}
public void draw() {
if (canvas == null) {
canvas.createBufferStrategy(3);
}
Graphics g = canvas.getGraphics();
g.setColor(Color.BLUE);
g.drawLine(100, 100, 300, 300);
}
}
You need to call your draw() method inside paint() as for Canvas in JAVA, paint() method paints this canvas. No need to call it explicitly in your Debug class.
Completely remove the while loop and what is inside it. In your Renderer3D class, modify the canvas creation part like this:
public Canvas canvas = new Canvas() {
public void paint(Graphics g) {
draw();
}
};

JPanel size is not known on start

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

Draw lines, circles anything (Java)

so i'm new in stackoverflow.
I am about to create a line, a triangle anything, but i'm just focusing on the line and in a good Object orient Programming.
So i create the class Point2D:
package draw;
/**
*
* #author Pedro
*/
public class Point2D {
private int x,y;
// Construtores
public Point2D(){
this(0,0);
}
public Point2D(int x, int y){
this.x=x;
this.y=y;
}
// Set's e Get's
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
Later i create the class line using the class point2D to get the starting point and final point
package draw;
/**
*
* #author Pedro
*/
public class Linha extends Figura{
private Point2D pinicial;
private Point2D pfinal;
//construtores
public Linha(int xinicial, int yinicial, int xfinal, int yfinal){
pinicial=new Point2D(xinicial, yinicial);
pfinal=new Point2D(xfinal, yfinal);
}
public Linha(Point2D pinicial, Point2D pfinal){
this.pinicial=pinicial;
this.pfinal=pfinal;
}
//Get's e Set's
public Point2D getPinicial() {
return pinicial;
}
public void setPinicial(Point2D pinicial) {
this.pinicial = pinicial;
}
public Point2D getPfinal() {
return pfinal;
}
public void setPfinal(Point2D pfinal) {
this.pfinal = pfinal;
}
}
And then i created a Jframe with a button called "line" and put it a panel inside the jFrame that is the place where its going to get the line draw.
The problems is ... I dont know how to draw the line or how should i cal it.
Can you help me?
simply, in your JPanel class ovverride paintComponent() method:
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g)
g.drawLine(x1, y1, x2, y2);
}
}
Where x1, y1, x2, and y2, are the cords of your line.
If you ONLY want it to draw line AFTER the button is pressed, create a global boolean variable, in your main class, and when the button is pressed, set it to true, then when you create your JPanel do:
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
if (myBoolean) {
super.paintComponent(g)
g.drawLine(x1, y1, x2, y2);
}
}
}
Though the advice given in the other answer is too good, but just couldn't stop myself, from adding a word or two to the same, like, in order for the painting to take place, you need to call repaint(), from inside the actionPerformed attached to JButton.
As already stated by #camickr, the use of getPreferredSize() inside the extended class for Drawing, that will provide a valid staging area, where the drawing needs to be done. This example might can help too in this direction.
Moreover, in case you wanted to keep all the lines which have been drawn on the Board so far intact, then you can simply store them in a List and iterate on this List to draw them all again, whenever a new line is to be drawn.
A simple example is as follows:
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
public class LineExample {
private DrawingBoard board;
private JButton drawLineButton;
private Random random;
private ActionListener buttonAction = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
int width = board.getWidth();
int height = board.getHeight();
Line line = new Line(random.nextInt(width),
random.nextInt(height),
random.nextInt(width),
random.nextInt(height));
board.setValues(line);
}
};
public LineExample() {
random = new Random();
}
private void displayGUI() {
JFrame frame = new JFrame("Drawing Lines Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel(new BorderLayout(5, 5));
board = new DrawingBoard(400, 400);
contentPane.add(board, BorderLayout.CENTER);
drawLineButton = new JButton("LINE");
drawLineButton.addActionListener(buttonAction);
contentPane.add(drawLineButton, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new LineExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
class DrawingBoard extends JPanel {
private int width;
private int height;
private List<Line> lines;
public DrawingBoard(int w, int h) {
width = w;
height = h;
lines = new ArrayList<Line>();
}
public void setValues(Line line) {
lines.add(line);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Line line : lines) {
int xs = line.getXStart();
int ys = line.getYStart();
int xe = line.getXEnd();
int ye = line.getYEnd();
g.drawLine(xs, ys, xe, ye);
}
}
}
class Line {
private Point startPoint;
private Point endPoint;
public Line(int xs, int ys, int xe, int ye) {
startPoint = new Point(xs, ys);
endPoint = new Point(xe, ye);
}
public int getXStart() {
return startPoint.getX();
}
public int getYStart() {
return startPoint.getY();
}
public int getXEnd() {
return endPoint.getX();
}
public int getYEnd() {
return endPoint.getY();
}
}
class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}

Clicking on a JPanel to draw shapes

I have a JFrame containing 3 JPanels; Options, menu, canvas. In options there are a number of JButtons representing shapes. The aim is to click on the JButton of a shape e.g. rectangle, then click anywhere on the canvas and the shape will be drawn there.
For some reason, the shape does not always get drawn, it is only drawn when I click somewhere in the top left area of the canvas. Also the shape seems to randomly change size depending on where I click.
Here are some of my code snippets, it's probably a small error but I just can't seem to find it.
Shape:
public class Shape extends JPanel {
protected int xLocation;
protected int yLocation;
protected int numberOfSides;
protected String areaInfo;
protected String perimeterInfo;
public int getXLocation() {
return xLocation;
}
public void setXLocation(int xLocation) {
this.xLocation = xLocation;
}
public int getYLocation() {
return yLocation;
}
public void setYLocation(int yLocation) {
this.yLocation = yLocation;
}
public int getNumberOfSides() {
return numberOfSides;
}
public Shape(int xLocation, int yLocation, int numberOfSides) {
this.xLocation = xLocation;
this.yLocation = yLocation;
this.numberOfSides = numberOfSides;
}
}
Rectangle:
import java.awt.Color;
import java.awt.Graphics;
public class Rectangle extends Shape {
private int width;
private int height;
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 Rectangle(int xLocation, int yLocation, int width, int height ) {
super(xLocation, yLocation, 4);
this.width = width;
this.height = height;
this.areaInfo = "Multiply width * height";
this.perimeterInfo = "Add the lengths of each side";
}
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(xLocation, yLocation, width, height);
}
}
Canvas:
public class DrawingCanvas extends JPanel implements Serializable{
private ArrayList<Shape> shapeList;
OptionsPanel options;
public void addShape(Shape shape){
shapeList.add(shape);
this.add(shape);
this.repaint();
}
public DrawingCanvas(){
shapeList = new ArrayList<Shape>();
}
}
Frame:
public class DrawingFrame extends JFrame implements MouseListener, MouseMotionListener {
private OptionsPanel options;
private DrawingCanvas canvas;
private MenuBar menu;
Shape s; //shape to be manipulated
public DrawingFrame(){
options = new OptionsPanel();
canvas = new DrawingCanvas();
menu = new MenuBar();
//options.setBounds(0, 0, 100, 500);
options.setBackground(Color.GREEN);
canvas.setBackground(Color.yellow);
menu.setSize(1000,200);
menu.setBackground(Color.magenta);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(1000,500);
this.setTitle("Drawing Application");
this.setLayout(new BorderLayout());
this.getContentPane().add(options, BorderLayout.WEST);
this.getContentPane().add(canvas, BorderLayout.CENTER);
this.getContentPane().add(menu, BorderLayout.PAGE_START);
this.setVisible(true);
options.createRectangleButton.addMouseListener(this);
options.createSquareButton.addMouseListener(this);
options.createCircleButton.addMouseListener(this);
options.createTriangleButton.addMouseListener(this);
options.clearButton.addMouseListener(this);
canvas.addMouseListener(this);
canvas.addMouseMotionListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
boolean createShape = true;
if(e.getSource().equals(options.createRectangleButton)){
createShape = true;
s = new Rectangle(50,50,400,200);
s.addMouseListener(this);
s.addMouseMotionListener(this);
}
if (e.getSource().equals(canvas) && createShape == true){
s.setXLocation(e.getX());
s.setYLocation(e.getY());
createShape = false;
canvas.addShape(s);
}
Absent a complete example, it's hard to say. I'd expect your DrawingCanvas to override paintComponent() in order to render the accumulated Shape instances in shapeList. You might compare your approach to that shown in GaphPanel, cited here.
The code you provided is not complete, but anyway the problem is in your mouseClicked method, if you change your second if to something like the following for example:
if (e.getSource().equals(canvas) && createShape == true){
int x = e.getX();
int y = e.getY();
s = new Rectangle(x,y,x+50,y+50);
canvas.addShape(s);
}
then a rectangle of width & height 50 will be painted whenever you click on the canvas, depending on your x, y location (you could change the fixed width/height by using a variable based on user input). Also, I'm not sure what you're trying to do in your first if section where you're adding a MouseListener to a newly created shape that is not added to the canvas, I guess there's something else you want to do...
I had to overwrite the canvas class' paint method; call super.paint in the canvas class and repaint each shape individually
public void paint(Graphics g){
super.paint(g);
for(int i=0;i<shapeList.size();i++){
((Shape)shapeList.get(i)).paint(g);
}
}

Java - draw graphics using a method and a constructor

I am working on a java 2d game library. I want a method named paintImage() to do graphics.drawImage() every time paintImage() is called.
public void paintImage(image1, x, y){
//i want it to run graphics.drawImage every time it is called.
}
public void anotherMethod(){
paintImage(...);
paintImage(...);
//paint as many times as i want.
}
public void paintComponent(Graphics graphics){
graphics.drawImage();
super.paintComponents();
}
Thanks for your time and please leave a suggestion, sorry but its kind of hard to explain this.
For Single Image Display
public class DrawingDemo {
private JPanel panel;
private MyImage imageData;
public DrawingDemo() {
...
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (imageData != null) {
g.drawImage(imageData.getImage(), imageData.getX(), imageData.getY(), this);
}
}
};
...
}
public void paintImage(Image image1, int x, int y) {
imageData = new MyImage(image1, x, y);
panel.repaint();
}
public void anotherMethod() {
paintImage(...);
paintImage(...);
}
}
public class MyImage { // bean class for storing image information
private Image image;
private int x;
private int y;
public MyImage(Image image, int x, int y) {
this.image = image;
this.x = x;
this.y = y;
}
public Image getImage(){
return image;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
... you can add setter methods
}
UPDATE : For multiple image display
private JPanel panel;
private ArrayList<MyImage> imageData; // or any other data structure you like
public DrawingDemo() {
imageData = new ArrayList<>();
JFrame frame = new JFrame();
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (MyImage myImage : imageData) {
g.drawImage(myImage.getImage(), myImage.getX(), myImage.getY(), this);
}
}
};
frame.add(panel);
frame.setVisible(true);
}
public void paintImage(Image image1, int x, int y) {
imageData.add(new MyImage(image1, x, y));
panel.repaint();
}
public void anotherMethod() {
paintImage(new ImageIcon("/home/blackadmin/Desktop/image.jpg").getImage(), 0, 0);
paintImage(new ImageIcon("/home/blackadmin/Desktop/image2.jpg").getImage(), 50, 50);
paintImage(new ImageIcon("/home/blackadmin/Desktop/image3.jpg").getImage(), 100, 100);
}
OUTPUT :
Have a look at this answer
Comment if you don't understand anything, hope this will help
What I think you're looking to do is to make changes to some states in your class and then redrawing your images with changes based on those state changes -- in other words perhaps you're looking to do animation. If so, then your image drawing should all be done either within the paintComponent method using its Graphics object, or in another method called by paintComponent one that uses the Graphics object passed into paintCocalzmponent. This can be done by passing a Graphics parameter into the other method. Your anotherMethod would then request that the JVM repaint the GUI by calling repaint(). For example:
public void anotherMethod() {
x++;
y++;
repaint(); // this will stimulate JVM to call paint/paintComponent
}
private void paintImage(Graphics g, BufferedImage img, int x, int y2) {
g.drawImage(img, x, y2, this);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintImage(g, image1, x, y);
}
A complete example of this is as follows:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.Transient;
import javax.swing.*;
public class PaintEg extends JPanel {
private static final int IMG_W = 30;
private static final int IMG_H = IMG_W;
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 20;
private BufferedImage image1;
private int x;
private int y;
public PaintEg() {
image1 = createImg();
new Timer(TIMER_DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
anotherMethod();
}
}).start();
}
private BufferedImage createImg() {
BufferedImage img = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setBackground(Color.red);
g2.clearRect(0, 0, IMG_W, IMG_H);
g2.setColor(Color.blue);
g2.fillRect(IMG_W / 4, IMG_H / 4, IMG_W / 2, IMG_H / 2);
g2.dispose();
return img;
}
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void anotherMethod() {
x++;
y++;
repaint(); // this will stimulate JVM to call paint/paintComponent
}
private void paintImage(Graphics g, BufferedImage img, int x, int y2) {
g.drawImage(img, x, y2, this);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintImage(g, image1, x, y);
}
private static void createAndShowGUI() {
PaintEg paintEg = new PaintEg();
JFrame frame = new JFrame("PaintEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(paintEg);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Categories