Java Graphics2D moving object stopped in the middle - java

I'm having a hard time to figure out why this moving rectangle is stopped right in the middle of the Jpanel. The Timer is not stopped, seems there is a boundary in the middle. Anyone could explain it for me please? and how can I make it move the whole way (800)?
here is my code:
public class TestDemo extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private int x;
private int y;
Timer timer;
TestDemo() {
x = 0;
y = 0;
this.setBackground(Color.BLACK);
timer = new Timer(10, this);
timer.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.scale(1, 1);
g2d.setPaint(Color.RED);
g2d.fill(new Rectangle2D.Double(getX(), getY(), 20, 20));
}
public void actionPerformed(ActionEvent e) {
setX(getX() + 1);
repaint();
}
public static void main(String[] args) {
JFrame frame = new JFrame("Moving star");
JPanel testDemo = new TestDemo();
testDemo.setSize(800, 200);
frame.add(testDemo);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
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;
}
}

The code is overriding methods that already exist and are used for other purposes. That is the main problem.
For custom painting any JComponent, use paintComponent(..) rather than paint(..)
Here is the (working) code with both changes implemented.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class TestDemo extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private int x1;
private int y1;
Timer timer;
TestDemo() {
x1 = 0;
y1 = 0;
this.setBackground(Color.BLACK);
timer = new Timer(10, this);
timer.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.scale(1, 1);
g2d.setPaint(Color.RED);
g2d.fill(new Rectangle2D.Double(getX1(), getY1(), 20, 20));
}
public void actionPerformed(ActionEvent e) {
setX1(getX1() + 1);
repaint();
}
public static void main(String[] args) {
JFrame frame = new JFrame("Moving star");
JPanel testDemo = new TestDemo();
testDemo.setSize(800, 200);
frame.add(testDemo);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public int getX1() {
return x1;
}
public void setX1(int x1) {
this.x1 = x1;
}
public int getY1() {
return y1;
}
public void setY1(int y1) {
this.y1 = y1;
}
}

Related

I am not able to draw after clear my jpanel

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.border.BevelBorder;
public class Cliente extends JPanel {
private JButton adelanteButton;
private JButton undoButton;
private JPanel panel1;
private JPanel panelDibujo;
private Rectangulo rectangulo = new Rectangulo();
Originator originator;
Caretaker caretaker;
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Patron Memento");
Cliente cliente = new Cliente();
frame.setContentPane(cliente.panel1);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Memento m : caretaker.history) {
System.out.println("forcitooooooo");
dibujar(m.getState(), Color.GREEN);
}
}
public Cliente() {
caretaker = new Caretaker();
originator = new Originator();
createUIComponents();
undoButton.addActionListener(e -> {
caretaker.anterior();
panelDibujo.repaint();
});
panelDibujo.setBackground(Color.WHITE);
panelDibujo.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
panelDibujo.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
MousePressedEvent(e);
}
#Override
public void mouseReleased(MouseEvent e) {
MouseReleasedEvent(e);
}
});
}
private void createUIComponents() {
}
private void MousePressedEvent(MouseEvent e){
rectangulo.setX1(e.getX());
rectangulo.setY1(e.getY());
}
private void MouseReleasedEvent(MouseEvent e){
rectangulo.setX2(e.getX());
rectangulo.setY2(e.getY());
originator.setState(rectangulo);
dibujar(rectangulo, Color.orange);
caretaker.addMemento(originator.CreateMemento());
rectangulo = new Rectangulo();
}
public void dibujar(Rectangulo r, Color c) {
Graphics g = panelDibujo.getGraphics();
g.setColor(c);
g.drawRect(r.getX1(), r.getY1(), r.getX2() - r.getX1(), r.getY2() - r.getY1());
g.dispose();
}
}
Hello i am applying the memento pattern by using a jpanel and drawing some rectangles inside, right now my code is working fine about drawing with the mouse events, but the issue is when i try to undo. My logic so far is clear the jpanel and redo all the rectangles minus the last one.
But after clearing my jpanel is not drawing again :( can someone help me to fix it? thank you
Caretaker.java
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Stack;
public class Caretaker {
LinkedList<Memento> history;
int indice;
public Caretaker(){
history = new LinkedList<>();
indice = 0;
}
void addMemento(Memento m){
if (history.size() == indice || history.isEmpty()){
indice++;
history.add(m);
}else {
indice = history.size()-1;
history.subList(indice +1, history.size()).clear();
}
}
Memento anterior(){
if (history.size() > 0){
indice--;
return history.removeLast();
}
JOptionPane.showMessageDialog(null, "No hay mas wey!");
return null;
}
Memento siguiente(){
if (indice < history.size()+1){
indice++;
return history.get(indice+1);
}
JOptionPane.showMessageDialog(null, "No hay mas wey!");
return null;
}
public void redibujar(JPanel f){
Graphics g = f.getGraphics();
for (Memento m: history) {
g.drawRect(m.getState().getX1(), m.getState().getY1(), m.getState().getX2() - m.getState().getX1(), m.getState().getY2() - m.getState().getY1());
g.dispose();
}
}
public void clear(){
history.clear();
indice = 0;
}
}
Memento.java
public class Memento {
Rectangulo state;
/*
Constructor, unica manera de mandar/crear/guardar los datos
*/
public Memento(Rectangulo state) {
this.state = state;
}
public Memento(){
state = new Rectangulo();
}
Rectangulo getState(){
return state;
}
}
Originator.java
public class Originator {
Rectangulo state;
public void setState(Rectangulo rectangulo){
this.state = rectangulo;
}
public Memento CreateMemento(){
return new Memento(state);
}
public void setMemento(Memento m) {
setState(m.getState());
}
}
Rectangulo.java
import java.awt.*;
public class Rectangulo {
private int x1;
private int x2;
private int y1;
private int y2;
Rectangulo(){
}
public Rectangulo(int x1, int x2, int y1, int y2) {
this.x1 = x1;
this.x2 = x2;
this.y1 = y1;
this.y2 = y2;
}
public int getX1() {
return x1;
}
public void setX1(int x1) {
this.x1 = x1;
}
public int getX2() {
return x2;
}
public void setX2(int x2) {
this.x2 = x2;
}
public int getY1() {
return y1;
}
public void setY1(int y1) {
this.y1 = y1;
}
public int getY2() {
return y2;
}
public void setY2(int y2) {
this.y2 = y2;
}
public void draw(Graphics g){
g.setColor(Color.orange);
g.drawRect(this.getX1(), this.getY1(), this.getX2() - this.getX1(), this.getY2() - this.getY1());
}
}
Again, you're not drawing correctly. You are trying to render using a JPanel, cliente, that is never added to the GUI, and you're trying to use a Graphics object that is extracted from this unrendered component, making the Graphics object thus obtained short-lived and unstable.
Instead, do all drawing in the paintComponent method. You can use a BufferedImage and draw that in paintComponent if desired, especially if you want images with objects that show different colors, or you can use your List (here a LinkedList, but ArrayList will work) and draw in paintComponent. For instance, something simple like:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class Cliente2 extends JPanel {
private static final int BI_WIDTH = 800;
private static final int BI_HEIGHT = 650;
private Rectangle drawingRect = null;
// private java.util.List<Rectangulo> rectangulos = new ArrayList<>();
List<Rectangulo2> rectangulos = new ArrayList<>();
private JButton clearBtn = new JButton("Clear");
public Cliente2() {
setBackground(Color.WHITE);
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
clearBtn.addActionListener(e -> clear());
add(clearBtn);
}
private void clear() {
rectangulos.clear();
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(BI_WIDTH, BI_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (drawingRect != null) {
g2.setColor(Color.LIGHT_GRAY);
g2.draw(drawingRect);
}
for (Rectangulo2 rectangulo : rectangulos) {
rectangulo.draw(g2);
}
}
private class MyMouse extends MouseAdapter {
private Point p0;
#Override
public void mousePressed(MouseEvent e) {
p0 = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e) {
drawingRect = createDrawingRect(e);
repaint();
}
private Rectangle createDrawingRect(MouseEvent e) {
Point p1 = e.getPoint();
int x = Math.min(p0.x, p1.x);
int y = Math.min(p0.y, p1.y);
int width = Math.abs(p0.x - p1.x);
int height = Math.abs(p0.y - p1.y);
return new Rectangle(x, y, width, height);
}
#Override
public void mouseReleased(MouseEvent e) {
// lets create some random colors:
float hue = (float) Math.random();
float brightness = (float) Math.random();
Color color = Color.getHSBColor(hue, 1f, brightness);
Rectangulo2 rectangulo = new Rectangulo2(color, p0, e.getPoint());
rectangulos.add(rectangulo);
drawingRect = null;
repaint();
}
}
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Patron Memento");
// Cliente cliente = new Cliente();
// frame.setContentPane(cliente.panel1);
frame.add(new Cliente2());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
class Rectangulo2 {
private static final Stroke STROKE = new BasicStroke(3f);
private Color color;
private Point p0, p1;
public Rectangulo2() {
}
public Rectangulo2(Color color, Point p0, Point p1) {
super();
this.color = color;
this.p0 = p0;
this.p1 = p1;
}
public Color getColor() {
return color;
}
public Point getP0() {
return p0;
}
public Point getP1() {
return p1;
}
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(color);
int x = Math.min(p0.x, p1.x);
int y = Math.min(p0.y, p1.y);
int width = Math.abs(p0.x - p1.x);
int height = Math.abs(p0.y - p1.y);
g2.fillRect(x, y, width, height);
g2.setStroke(STROKE);
g2.setColor(Color.BLACK);
g2.drawRect(x, y, width, height);
g2.dispose();
}
}

Swing draws only after resizing

Program should draw the line twice longer after clicking the button, but it only does that after clicking AND THEN resizing the window. I don't know what is happening, i thought this is gonna be easy.
Could you tell me how can I fix it?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.Random;
import java.util.Stack;
class MyButtonPanel extends JPanel {
public static final int HEIGHT = 800;
public static final int WIDTH = 800;
private JButton greenButton;
private JPanel buttonPanel;
Stack<Point> points;
int X = 25;
int Y = 25;
public MyButtonPanel() {
greenButton = new GreenButton();
points = new Stack<Point>();
buttonPanel = this;
setLayout(new FlowLayout());
setPreferredSize(new Dimension(WIDTH, HEIGHT));
add(greenButton);
}
class GreenButton extends JButton implements ActionListener
{
GreenButton() {
super("LongerLine");
addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
//points.push(new Point(0,0));
X = 2 * X;
Y = 2 * Y;
validate();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//g2d.setColor(Color.WHITE);
//g2d.fillRect(0, 0, WIDTH, HEIGHT);
g2d.setColor(Color.BLACK);
//drawLines(g2d);
Line2D lin = new Line2D.Double(0,0, X, Y);
g2d.draw(lin);
}
private void drawLines(Graphics2D g2d) {
//Line2D lin = new Line2D.Float(100, 100, 250, 260);
//g2d.draw(lin);
double x1, y1, x2, y2;
/*
for(Point point: points) {
x1 = (double) point.getX();
y1 = (double) point.getY();
Line2D line = new Line2D.Double(x1,y1,200,200);
g2d.draw(line);
}
*/
}
}
public class MyActionFrame extends JFrame {
public MyActionFrame() {
super("Test akcji");
JPanel buttonPanel = new MyButtonPanel();
add(buttonPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
//setResizable(false);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new MyActionFrame();
}
});
}
}
This validate();, or better revalidate(); is called when a container's layout needs to be re-done, often when components are added or removed, and is not what you're doing or desiring. Instead you want to call repaint() which suggests that the component be painted.

java gui paintComponent refresh

I am learning java gui interface and wrote a program that has a button. Each time the button is clicked, a random sized rectangle will be added to the screen. But instead of adding it to the screen, the program keeps erasing the old one, which I want to keep on the screen. Here is my code. I tried to do paint() and it did not work. Thanks in advance.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class SimpleGui implements ActionListener {
JFrame frame = new JFrame();
public static void main(String[] args){
SimpleGui gui = new SimpleGui();
gui.go();
}
public void go(){
JButton button = new JButton("Add a rectangle");
MyDrawPanel panel = new MyDrawPanel();
button.addActionListener(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.getContentPane().add(BorderLayout.CENTER, panel);
frame.setSize(300, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event){
frame.repaint();
}
class MyDrawPanel extends JPanel{
public void paintComponent(Graphics g){
g.setColor(Color.blue);
int height = (int) (Math.random()*120 + 10);
int width = (int) (Math.random()*120 + 10);
int x = (int) (Math.random()*40 + 10);
int y = (int) (Math.random()*40 + 10);
g.fillRect(x, y, height, width);
}
}
}
Your paintComponent method is written to draw only one rectangle, so its behavior should come as no shock to you. If you want it to draw multiple, you have one of two options:
Create an ArrayList<Rectangle>, and in the actionPerformed method, add a new random Rectangle to this List and then call repaint(). In the paintComponent method, iterate through this List with a for-loop, painting each Rectangle.
Or you could draw the new random rectangle onto a BufferedImage that is displayed by the paintComponent method.
The first method is the easier of the two, the 2nd is better if you're worried about program responsiveness, say in an animation program.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class TwoDrawRectMethods extends JPanel {
// Array to hold our two drawing JPanels
private AddRandomRect[] addRandomRects = {
new DrawList("Using List"),
new DrawBufferedImage("Using BufferedImage")};
// constructor
public TwoDrawRectMethods() {
// add drawing rectangles onto GUI
for (AddRandomRect addRandomRect : addRandomRects) {
add(addRandomRect);
}
// button to tell rectangles to add a new Rectangle
add(new JButton(new DrawAction("Add New Rectangle")));
}
// The button's Action -- an ActionListener on "steroids"
private class DrawAction extends AbstractAction {
public DrawAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
// tell both drawing JPanels to add a new rectangle
for (AddRandomRect addRandomRect : addRandomRects) {
addRandomRect.addRectangle();
}
}
}
private static void createAndShowGui() {
TwoDrawRectMethods mainPanel = new TwoDrawRectMethods();
JFrame frame = new JFrame("TwoDrawRectMethods");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class DrawList extends AddRandomRect {
private static final Color RECT_COLOR = Color.RED;
private List<Rectangle> rectList = new ArrayList<>();
public DrawList(String title) {
super(title);
}
#Override
public void addRectangle() {
rectList.add(createRandomRect());
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(RECT_COLOR);
for (Rectangle rectangle : rectList) {
g2.draw(rectangle);
}
}
}
#SuppressWarnings("serial")
class DrawBufferedImage extends AddRandomRect {
private static final Color RECT_COLOR = Color.BLUE;
private BufferedImage img = null;
public DrawBufferedImage(String title) {
super(title);
}
#Override
public void addRectangle() {
if (img == null) {
img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Rectangle rect = createRandomRect();
Graphics2D g2 = img.createGraphics();
g2.setColor(RECT_COLOR);
g2.draw(rect);
g2.dispose();
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, null);
}
}
}
#SuppressWarnings("serial")
abstract class AddRandomRect extends JPanel {
private static final int PREF_W = 500;
private static final int PREF_H = PREF_W;
private Random random = new Random();
public AddRandomRect(String title) {
setBorder(BorderFactory.createTitledBorder(title));
}
abstract void addRectangle();
protected Rectangle createRandomRect() {
int x1 = random.nextInt(PREF_W);
int x2 = random.nextInt(PREF_W);
int y1 = random.nextInt(PREF_H);
int y2 = random.nextInt(PREF_H);
int x = Math.min(x1, x2);
int y = Math.min(y1, y2);
int width = Math.abs(x1 - x2);
int height = Math.abs(y1 - y2);
return new Rectangle(x, y, width, height);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
}

Java - MouseListener Action Event in paintComponent

Here i have a code which draws a rectangle on the mouseClicked position using the paintComponent.I can get the output message but anything related to graphics and .draw() wont work.
Code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public final class testclass extends JFrame {
static JPanel p;
Timer t;
int x = 1;
int y = 1;
int xspeed = 1;
int yspeed = 1;
public testclass() {
initComponents();
this.setBounds(100, 300, 500, 500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.start();
this.add(p);
}
public void initComponents() {
final ActionListener action = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println("Hello!");
p.repaint();
}
};
t = new Timer(50, action);
p = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
final Graphics2D gD = (Graphics2D) g;
moveBALL();
gD.drawOval(x, y, 25, 25);
p.addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("a");
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("b");
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println("c");
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("d");
}
#Override
public void mouseClicked(MouseEvent e) {
gD.drawRect(e.getX(), e.getY(), 10, 60);
gD.setColor(Color.green);
System.out.println("clicked");
}
});
}
void moveBALL() {
x = x + xspeed;
y = y + yspeed;
if (x < 0) {
x = 0;
xspeed = -xspeed;
} else if (x > p.getWidth() - 20) {
x = p.getWidth() - 20;
xspeed = -xspeed;
}
if (y < 0) {
y = 0;
yspeed = -yspeed;
} else if (y > p.getHeight() - 20) {
y = p.getHeight() - 20;
yspeed = -yspeed;
}
}
};
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new testclass().setVisible(true);
p.setBackground(Color.WHITE);
}
});
}
}
What is the proper way to implement a mouseListener() in this program?
Thanks.
Some suggestions on current code:
Watch class naming scheme i.e testclass should be TestClass or even better Test (but thats nit picking). All class names begin with capital letter and each new word thereafter is capitalized.
Dont extend JFrame unnecessarily.
Dont call setBounds on JFrame rather use appropriate LayoutManager and/or override getPreferredSize() of JPanel and return dimensions which fits its content.
Always call pack() on JFrame before setting it visible (taking above into consideration).
Use MouseAdapter vs MouseListener
Dont call moveBall() in paintComponent rather call it in your Timer which repaints the screen, not only slightly better design but we also should not do possibly long running tasks in paint methods.
As for your problem I think your logic is a bit skewed.
One approach would see the Rectangle (or Rectangle2D) get replaced by its own custom class (which will allow us to store attributes like color etc). Your ball would also have its own class which has the method moveBall() and its attributes like x and y position etc. On every repaint() your JPanel would call the method to move the ball, the JPanel itself could wrap the moveBall() in its own public method which we could than call from the timer which repaints the screen.
Here is an example of your code with above fixes implemented (please analyze it and if you have any questions let me know):
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.*;
public class Test {
private MyPanel p;
private Timer t;
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents();
frame.add(p);
frame.pack();
frame.setVisible(true);
t.start();
}
private void initComponents() {
final ActionListener action = new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
p.moveEntities();//moves ball etc
p.repaint();
}
};
t = new Timer(50, action);
p = new MyPanel();
p.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
p.addEntity(e.getX(), e.getY(), 10, 50, Color.GREEN);
System.out.println("clicked");
}
});
p.setBackground(Color.WHITE);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class MyPanel extends JPanel {
int width = 300, height = 300;
ArrayList<MyRectangle> entities = new ArrayList<>();
MyBall ball = new MyBall(10, 10, 25, 25, Color.RED, width, height);
void addEntity(int x, int y, int w, int h, Color c) {
entities.add(new MyRectangle(x, y, w, h, c));
}
void moveEntities() {
ball.moveBALL();
}
#Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(ball.getColor());
g2d.fillOval((int) ball.x, (int) ball.y, (int) ball.width, (int) ball.height);
for (MyRectangle entity : entities) {
g2d.setColor(entity.getColor());
g2d.fillRect((int) entity.x, (int) entity.y, (int) entity.width, (int) entity.height);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
}
class MyRectangle extends Rectangle2D.Double {
Color color;
public MyRectangle(double x, double y, double w, double h, Color c) {
super(x, y, w, h);
color = c;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
class MyBall extends Ellipse2D.Double {
int xspeed = 1;
int yspeed = 1;
Color color;
private final int maxWidth;
private final int maxHeight;
public MyBall(double x, double y, double w, double h, Color c, int maxWidth, int maxHeight) {
super(x, y, w, h);
color = c;
this.width = w;//set width and height of Rectangle2D
this.height = h;
//set max width and height ball can move
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
void moveBALL() {
x = x + xspeed;
y = y + yspeed;
if (x < 0) {
x = 0;
xspeed = -xspeed;
} else if (x > maxWidth - ((int) getWidth() / 2)) {// i dont like hard coding values its not good oractice and resuaibilty is diminshed
x = maxWidth - ((int) getWidth() / 2);
xspeed = -xspeed;
}
if (y < 0) {
y = 0;
yspeed = -yspeed;
} else if (y > maxHeight - ((int) getHeight() / 2)) {
y = maxHeight - ((int) getHeight() / 2);
yspeed = -yspeed;
}
}
}
First of all the paint component is called every time swing needs to redraw the component.
And you are adding a new instance of mouse listener to the panel every time the paint is called.
Just move the line
p.addMouseListener(new MouseListener() {...}
out of the paint component, preferably after the initialization of the panel.
default template is
JPanel p = new JPanel(){
#Override
public void paintComponent(Graphics g) {
}
};
p.addMouseListener(new MouseListener() or new MouseAdapter()
//Your overridden methods
});
Hope this helps.

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