paintComponent is not drawing in the entire JPanel - java

I'm trying to make the game snake and have run into an issue. What I have is a class called Segment which is used to create the objects that hold the x- and y-positions and also the direction of the snake. The class extends JPanel and overrides the method paintComponent(). I then add an object of type Segment to a JFrame in a different class. The methods I have for moving/changing directions of the snake (actually just a square at the moment) work perfectly but my problem is this:
When the square gets to about half of the width of the frame or half of the height of the frame it stops being drawn. I have made the background of the JPanel light grey so I know that the square hasn't reached the end of the JPanel when it stops. Below is my simple paintComponent() method and the section in the class that extends JFrame where I add the object.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.LIGHT_GRAY);
g.setColor(Color.black);
g.fillRect(xpos, ypos, width, height);
}
public Snake() {
setLayout(new BorderLayout());
addKeyListener(l);
segment = new Segment(100, 100, Segment.Dir.RIGHT);
segment.setPreferredSize(new Dimension(500,500));
add(segment, BorderLayout.CENTER);
timer.start();
setVisible(true);
pack();
setTitle("Snake");
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
I also know that the objects position doesn't stop being updated so it's just the drawing of the square in the entire panel/frame that's the issue. Appreciate any help!
Here's an MCVE:
import java.awt.*;
import javax.swing.*;
public class Segment extends JPanel {
private int width = 10;
private int height = 10;
private int xpos, ypos;
private Dir dir;
public enum Dir {
LEFT, RIGHT, UP, DOWN;
}
public Segment() {
xpos = 0;
ypos = 0;
dir = Dir.RIGHT;
}
public Segment(int x, int y, Dir d) {
xpos = x;
ypos = y;
dir = d;
}
public Dir getDir() {
return dir;
}
public void setDir(Dir d) {
dir = d;
}
public void setX(int x) {
xpos = x;
repaint();
}
public void setY(int y) {
ypos = y;
repaint();
}
public int getX() {
return xpos;
}
public int getY() {
return ypos;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.LIGHT_GRAY);
g.setColor(Color.black);
g.fillRect(xpos, ypos, width, height);
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Snake extends JFrame implements ActionListener {
Segment segment;
Timer timer = new Timer(50, this);
public Snake() {
setLayout(new BorderLayout());
setSize(500,500);
segment = new Segment(100, 100, Segment.Dir.RIGHT);
segment.setPreferredSize(new Dimension(getWidth(),getHeight()));
add(segment, BorderLayout.CENTER);
timer.start();
setVisible(true);
setTitle("Snake");
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == timer) {
segment.setX((segment.getX() + 4 + getWidth())%getWidth());
}
}
public static void main(String[] arg) {
new Snake();
}
}

Don't override getX() and getY() of the Segment class.
Those are methods of all Swing components. They get the current location of the component within the parent container.
Use different method names to control the location of the painting of your snake. Since your variable names are xPos and yPos maybe use getXPos() and getYPos().
So what happens is that the snake is drawn at xPos/yPos relative to the Segment panel and the Segment panel is also drawn at xPos/yPos relative to its parent container.

Related

Adding shapes to JPanel on a button click

I have a Class Circle with a button and a Class with a jPanel what i want to do is when that button is clicked a circle will be drawn on the panel and each time i click that button and change x and y "some how not implemented here" i got a circle on the JPanel over and over .
How to do that, or is there a way to do what i descriped regardless of my code but i want the class circle to extends Shape.
public class Window{
private JFrame frame;
private JPanel panel = new JPanel();
Circle c = new Circle(frame, panel);
// some other buttons
.
.
// some code to set the panel grid bag constaraints and background then
frame.getContentPane().add(panel, gbc_panel);
}
then the Circle Class
public class Circle extends Shape implements ActionListener{
private JPanel Panel;
private GridBagConstraints gbc_btnCircle;
private JButton btnCircle;
public void setPanel(JPanel panel) {
Panel = panel;
}
public Circle(JFrame frame, JPanel panel){
btnCircle = new JButton("Circle");
// some code to set grid bag constraint then
frame.getContentPane().add(btnCircle, gbc_btnCircle);
setPanel(panel);
btnCircle.addActionListener(this);
}
public void paint(Graphics g) {
super.paintComponents(g);
g.setColor(Color.red);
g.fillOval(100, 100, 100, 100);
Panel.add(this);
}
public void actionPerformed(ActionEvent arg0) {
repaint();
}
}
You kinda have the wrong idea. In your drawing panel, you should have a List<Circle>. And in the paintComponent method of the drawing panel, you should iterate through the list to draw each circle
class Circle {
int x, int y, int width, int height;
public Circle (int x, int y, int width, int height) {
... set em
}
public void draw(Graphics g) {
g.fillOval(x, y, width, height);
}
}
class DrawingPanel extends JPanel {
List<Circle> circles = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Circle circle : circles) {
circle.draw(g);
}
}
// Dont forget to override public Dimension getPreferredSize()
}
To add more Circles to the list, just have a addCircle method in the DrawingPanel class
public void addCircle(Circle circle) {
circles.add(circle);
repaint();
}
As far as the button, you should be creating it in the Window class. In the ActionListener, just create a new Circle and add it the DrawingPanel by calling the addCircle method
An aside, Circle doesn't need the extend Shape. The Shape API already has an Ellipse2D class, which you can create circles from
class DrawingPanel extends JPanel {
List<Ellipse2D> circles = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
for (Ellipse2D circle : circles) {
g2.fill(circle);
}
g2.dispose();
}
// Dont forget to override public Dimension getPreferredSize()
}
See 2D Graphics
UPDATE: full example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CirclesDemo {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new CirclesDemo();
}
});
}
public CirclesDemo() {
JFrame frame = new JFrame();
frame.add(panel);
frame.add(createButton(), BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private final DrawingPanel panel = new DrawingPanel();
private JButton createButton() {
JButton button = new JButton("Add Circle");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
int[] circleValues = generateRandomValues(300, 300, 50, 150);
int x = circleValues[0];
int y = circleValues[1];
int width = circleValues[2];
int height = width;
Circle circle = new Circle(x, y, width, height);
panel.addCircle(circle);
}
});
return button;
}
private int[] generateRandomValues(int maxX, int maxY,
int minSize, int maxSize) {
Random random = new Random();
int[] values = new int[3];
values[0] = random.nextInt(maxX);
values[1] = random.nextInt(maxY);
values[2] = Math.min(random.nextInt(maxSize) + minSize, maxSize);
return values;
}
class Circle {
int x, y, width, height;
public Circle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public void draw(Graphics g) {
g.drawOval(x, y, width, height);
}
}
class DrawingPanel extends JPanel {
List<Circle> circles = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Circle circle : circles) {
circle.draw(g);
}
}
public void addCircle(Circle circle) {
circles.add(circle);
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
}
You are overriding the paint method of Circle. You need to be overriding the paint method of the panel.

How to double buffer rectangles

It always works with images but rectangles and ovals never buffer right. I have a basic game loop in my gamepanel class that draws the player repeatedly. It doesn't remove the rectangle, just leaves a trace. I want to use a rectangle instead of an image for learning purposes. I tried using repaint in the game loop, but it flickered like crazy and still didn't work. I looked at another tutorial on this in this website but they used opengl witch is foreign to me and I don't want to take the time to figure it out.
JFrame:
import javax.swing.JFrame;
public class Game {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setTitle("OMG I MADE A GAME");
f.setResizable(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new Panel());
f.pack();
f.setVisible(true);
}
}
JPanel Class:
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import javax.swing.JPanel;
import com.game.entity.Player;
public class Panel extends JPanel implements Runnable, KeyListener{
private static final long serialVersionUID = -5122190028751177848L;
// dimensions
public static final int WIDTH = 320;
public static final int HEIGHT = 240;
public static final int SCALE = 2;
// game thread
private Thread thread;
private boolean running;
// image
private BufferedImage image;
private Graphics2D g;
private Player p;
public Panel() {
super();
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setFocusable(true);
requestFocus();
}
// DRAWS PANEL TO FRAME
public void addNotify() {
super.addNotify();
if(thread == null) {
thread = new Thread(this);
addKeyListener(this);
thread.start();
}
}
private void init() {
image = new BufferedImage(
WIDTH, HEIGHT,
BufferedImage.TYPE_INT_RGB );
g = (Graphics2D) image.getGraphics();
p = new Player(100, 100);
running = true;
}
public void run() {
init();
// game loop
while(running) {
update();
draw();
drawToScreen();
System.out.println("ELAPSED :" + System.nanoTime()/ 1000000 + " Seconds");
try {
Thread.sleep(10);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
private void update() {
p.update();
}
private void draw(){
// NAME (remember it loops)
String name = "2014 Jay H.";
g.setFont(new Font("Name", 0, 12));
g.setColor(Color.WHITE);
g.drawString(name, 0, 10);
g.setColor(Color.BLUE);
g.fillRect( 0, 10, 65, 5);
//TITLE looks sexy :D
g.setColor(Color.GREEN);
g.setFont(new Font("Title", 0, WIDTH/ 10));
g.drawString("JAY'S GAME", WIDTH/ 5, 100);
//DRAW PLAYER
p.draw(g);
}
// SCREEN IMAGE (dont have to use. Just use this^)
private void drawToScreen() {
Graphics g2 = getGraphics();
g2.drawImage(image, 0, 0,
WIDTH * SCALE, HEIGHT * SCALE,null);
g2.dispose();
}
public void keyTyped(KeyEvent key) {}
// PUBLIC KEYRELEASES
public void keyPressed(KeyEvent key) {
int KeyCode = key.getKeyCode();
//EXIT SYSTEM
if(KeyCode == KeyEvent.VK_Q) {System.exit(0);
} //UP
if(KeyCode == KeyEvent.VK_W){p.setDY(-2);}
}
// PUBLIC KEYRELEASES
public void keyReleased(KeyEvent key) {
int KeyCode = key.getKeyCode();
//UP
if(KeyCode == KeyEvent.VK_W) {p.setDY(0);}
}
}
Player Class:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import javax.swing.ImageIcon;
//FOR NOW THE PLAYER IS A RECTANGLE
public class Player {
// PLAYER CORDINATES AND VELOCITY
int x,y,dx,dy;
public Player(int x, int y) {
//NEEDED TO USE THE X AND Y
this.x =x;
this.y = y;
}
public void update() {
x += dx;
y += dy;
}
// DRAW TO PANEL CLASS
public void draw(Graphics2D g) {
//BODY
g.setColor(Color.PINK);
g.fillRect(x, y, 20, 20);
//EYES
g.setColor(Color.BLACK);
g.fillRect(x+3, y+2, 5, 10);
g.fillRect(x+ 12, y+2, 5, 10);
//EYERIS
g.setColor(Color.WHITE);
g.fillRect(x+3, y+2, 2, 10);
g.fillRect(x+15, y+2, 2, 10);
//NOSE
g.setColor(Color.MAGENTA);
g.fillRect(x+5, y+13, 10, 5);
//NOSTRILLS
g.setColor(Color.red);
g.fillRect(x+6, y+15, 2, 2);
g.fillRect(x+12, y+15, 2, 2);
}
//GET METHODS FOR CORDINATES AND VELOCITY (Unused for now... i think)
public int getX() {return x;}
public int getY() {return y;}
public int getDX() {return dx;}
public int getDY() {return dy;}
//SET METHODS TO CHANGE
public void setX(int x) {this.x = x;}
public void setY(int y) {this.y = y;}
public void setDX(int dx) {this.dx = dx;}
public void setDY(int dy) {this.dy = dy;}
}
You need to "reset" the background of the buffer before you paint to it.
Remember, painting is accumilitive, that is, what ever you painted previously, will remain. You will need to rebuild each frame from scratch each time you paint to it
Flickering will occur for two reasons...
You are using AWT based components, which aren't double buffered
You are overriding paint of a top level container like JFrame, which isn't double buffered.
You should either use a BufferStrategy or override the paintComponent method of a Swing based component, like JPanel which are double buffered by default

Make a object when pressed follow mouse pointer, java [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I want to make a program that has objects on the screen and then when you press down on them it will follow the mouse pointer until you then release the mouse and then it will no longer follow the mouse.
Here is the code i have to add balls to the screen so if it would be possible to just adapt the code it would be great. It is split into 3 classes
import java.awt.BorderLayout;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class DrawBalls {
JFrame frame = new JFrame();
final DrawPanel drawPanel = new DrawPanel();
JPanel controlPanel = new JPanel();
JButton createBallButton = new JButton("Add ball");
DrawBalls(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
controlPanel.add(createBallButton);
frame.add(drawPanel);
frame.add(controlPanel, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
{
drawPanel.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
for (Ball b : drawPanel.getBalls()) {
if (b.getBounds().contains(me.getPoint())) {
//this has it being the same coordinates as the mouse i don't know
//how to have it run constantly so when i move it, it doesn't work
b.setx(me.getX()-(b.radius/2));
b.sety( me.getY()-(b.radius/2));
drawPanel.repaint();
}
}
}
});
createBallButton.addActionListener(new ActionListener() {
Random rand = new Random();
private int counter = 1;
int noOfClicks = 1;
public void actionPerformed(ActionEvent e) {
if(noOfClicks<=10){
int ballRadius = 10;
int x = rand.nextInt(drawPanel.getWidth());
int y = rand.nextInt(drawPanel.getHeight());
//check that we dont go offscreen by subtarcting its radius unless its x and y are not bigger than radius
if (y > ballRadius) {
y -= ballRadius;
}
if (x > ballRadius) {
x -= ballRadius;
}
drawPanel.addBall(new Ball(x, y, ballRadius, counter));//add ball to panel to be drawn
counter++;//increase the ball number
noOfClicks++;
}
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new DrawBalls();
}
});
}
Ball class
import java.awt.*;
import java.awt.geom.*;
public class Ball {
private Color color;
private int x, y;
private int radius;
private final int number;
Ball(int x, int y, int radius, int counter) {
this.x = x;
this.y = y;
this.radius = radius;
this.number = counter;
this.color = Color.RED;
}
public void draw(Graphics2D g2d) {
Color prevColor = g2d.getColor();
g2d.drawString(number + "", x + radius, y + radius);
g2d.setColor(color);
g2d.fillOval(x, y, radius, radius);
g2d.setColor(prevColor);
}
public Rectangle2D getBounds() {
return new Rectangle2D.Double(x, y, radius, radius);
}
int getNumber() {
return number;
}
}
DrawPanel
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class DrawPanel extends JPanel {
ArrayList<Ball> balls = new ArrayList<Ball>();
public void addBall(Ball b) {
balls.add(b);
repaint();
}
public ArrayList<Ball> getBalls() {
return balls;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (Ball ball : balls) {
ball.draw(g2d);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
One way is to make your Ball class an actual Swing component. Then you can use the ComponentMover class.
Edit:
how do you make a class into a swing component
Basically, you move your draw(...) code into the paintComponent() method of JComponent. Here is a simple example that does all the custom painting for you because the painting is based on a Shape object. You would still need to modify the code to paint the "number".
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class ShapeComponent extends JComponent
{
Shape shape;
public ShapeComponent(Shape shape)
{
this.shape = shape;
setOpaque( false );
}
public Dimension getPreferredSize()
{
Rectangle bounds = shape.getBounds();
return new Dimension(bounds.width, bounds.height);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor( getForeground() );
g2d.fill( shape );
}
#Override
public boolean contains(int x, int y)
{
return shape.contains(x, y);
}
private static void createAndShowUI()
{
ShapeComponent ball = new ShapeComponent( new Ellipse2D.Double(0, 0, 50, 50) );
ball.setForeground(Color.GREEN);
ball.setSize( ball.getPreferredSize() );
ball.setLocation(10, 10);
ShapeComponent square = new ShapeComponent( new Rectangle(30, 30) );
square.setForeground(Color.ORANGE);
square.setSize( square.getPreferredSize() );
square.setLocation(50, 50);
JFrame frame = new JFrame();
frame.setLayout(null);
frame.add(ball);
frame.add(square);
frame.setSize(200, 200);
frame.setVisible(true);
MouseListener ml = new MouseAdapter()
{
public void mouseClicked( MouseEvent e )
{
System.out.println( "clicked " );
}
};
ball.addMouseListener( ml );
square.addMouseListener( ml );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
The main difference between this approach and trashgod's suggestion to use an Icon is that mouse events will only be generated when the mouse in over the ball, not the rectangular corners of the ball since the contains(...) method respects the shape of what you are drawing.

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);
}
}

paintComponent does not work if its called by the recursive function?

I want to see all the Points one after another but I see only able to see 1
point. What shold I change to see all the Points ?
In the System.out you can see 10 times "set" and then 2 times
"paintComponent". what should I change that after each time set is
called it change the "paintComponente" ?
==================================================================================
public class exampe extends JPanel
{
int x;
int y;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fillOval(x-2,y-2,4,4);
System.out.println("paintComponent");
}
public void set(int X, int Y)
{
x = X;
y = Y;
System.out.println("set");
super.repaint();
}
public static void main(String args[])
{
int e=1;
JFrame frame = new JFrame("TEST");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
exampe ex= new exampe();
JScrollPane scroll = new JScrollPane(ex);
frame.getContentPane().add(scroll);
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
for(int i=0; i< 10; ++i)
ex.set(e+i,e+i);
}
}
*SIMPLE EXPLANATION AS TO WHY YOU COULD ONLY SEE THE LAST UPDATE : *
A quote taken from Filthy Rich Clients by Chet Haase and Romain Guy
It is important to note that repaint requests get “coalesced,” or combined.
So, for example, if you request a repaint and there is already one on the
queue that has not yet been serviced, then the second request is ignored
because your request for a repaint will already be fulfilled by the earlier
request. This behavior is particularly helpful in situations where many
repaint requests are being generated, perhaps by very different situations
and components, and Swing should avoid processing redundant requests and
wasting effort.
Try your hands on this, and ask what is not clear to you :
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class PointsExample
{
private CustomPanel contentPane;
private Timer timer;
private int x = 1;
private int y = 1;
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
contentPane.set(x, y);
x++;
y++;
if (x == 450)
timer.stop();
}
};
/*
* This is just JFrame, that we be
* using as the Base for our Application.
* Though here we are calling our
* JPanel (CustomPanel), whose
* paintComponent(...) method, we had
* override.
*/
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Locate Mouse Position");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
contentPane = new CustomPanel();
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(100, timerAction);
timer.start();
}
public static void main(String\u005B\u005D args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new PointsExample().createAndDisplayGUI();
}
});
}
}
class CustomPanel extends JComponent
{
private int x;
private int y;
public void set(int a, int b)
{
x = a;
y = b;
repaint();
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(500, 500));
}
#Override
public void paintComponent(Graphics g)
{
g.clearRect(0, 0, getWidth(), getHeight());
Graphics2D g2 =(Graphics2D) g;
g2.fillOval(x, y, 4, 4);
}
}
Here is the code, that will allow you to have a look at your points while iterating inside a for loop, though this approach is highly discouraged, for many cons associated with it. Though try your hands on this instead of calling repaint() call paintImmediately(int ...) or paintImmediately(Rectangle rect)
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class PointsExample
{
private CustomPanel contentPane;
private Timer timer;
private int x = 1;
private int y = 1;
/*
* This is just JFrame, that we be
* using as the Base for our Application.
* Though here we are calling our
* JPanel (CustomPanel), whose
* paintComponent(...) method, we had
* override.
*/
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Locate Mouse Position");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
contentPane = new CustomPanel();
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
for (int i = 0; i < 500; i++)
{
contentPane.set(x, y);
x++;
y++;
if (x == 450)
break;
}
}
public static void main(String\u005B\u005D args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new PointsExample().createAndDisplayGUI();
}
});
}
}
class CustomPanel extends JComponent
{
private int x;
private int y;
public void set(int a, int b)
{
x = a;
y = b;
paintImmediately(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(500, 500));
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.fillOval(x, y, 4, 4);
}
}
1: first line of paintComponent() should be your super.paintComponent()
2: why are you calling super.repaint(), make it simply repaint()
Your Drow should be like this.
public class drow extends JPanel {
...........
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 =(Graphics2D) g;
}
public void set_list(LinkedList <point> p){
Points =p;
repaint();
}
try with this.
i hope this is simply a structure, your paintComponent() isn't drawing anything.
EDIT
public void set_list(LinkedList <point> p){
Points =p;
System.out.println("set_ist");// 1:First this line will be displayed then..
repaint();//2: Then this is called, which in turn calls your `paintComponent()`
}
Now when your paintComponent() is called it has
system.out.println("paintComponent");
//3: so now this will be displayed.
Where is the problem here?
EDIT- SWING TIMER
Your code was ok, but the function processing is way faster than GUI updation, thats why you were unable to see the changes in front of you. The way you were doing, of calling thread.sleep() between function calls to slow down it's call, was not a good approach. For any timing thing's in swing, use swing timer, i changed your code for swing timer.
Using Swing Timer:
public class exampe extends JPanel implements ActionListener {
int x;
int y;
int temp = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fillOval(x - 2, y - 2, 4, 4);
}
public void set(int X, int Y) {
x = X;
y = Y;
}
public static void main(String args[]) {
JFrame frame = new JFrame("TEST");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
exampe ex = new exampe();
JScrollPane scroll = new JScrollPane(ex);
frame.getContentPane().add(scroll);
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer PointTimer = new Timer(1000, ex);
PointTimer.setInitialDelay(1000);
PointTimer.start();
System.out.println("started");
}
#Override
public void actionPerformed(ActionEvent e) {
// set(rand.nextInt(350), rand.nextInt(350));
set(temp+10,temp+10);
temp=temp+2;
repaint();
}
}

Categories