Is it possible to re-paint an applet without losing its previous contents? I was just trying to make a program which allows users to draw lines, Rectangle etc. using mouse. I have used the repaint method but it does not keep the previously drawn lines/rectangles etc.
Here is the snippet:
public void mousePressed(MouseEvent e){x1=e.getX();y1=e.getY();}
public void mouseDragged(MouseEvent e)
{
x2=e.getX();
y2=e.getY();
repaint();
showStatus("Start Point: "+x1+", "+y1+" End Point: "+x2+", "+y2);
}
public void paint(Graphics g)
{
//g.drawLine(x1,y1,x2,y2);
g.drawRect(x1, y1, x2-x1, y2-y1);
}
Two possible solutions:
Draw to a BufferedImage using the Graphics object obtained from it via getGraphics(), and then draw the BufferedImage in your JPanel's paintComponent(Graphics g) method. Or
Create an ArrayList<Point> place your mouse points into the List, and then in the JPanel's paintComponent(Graphics g) method, iterate through the List with a for loop, drawing all the points, or sometimes better -- lines that connect the contiguous points.
Other important suggestions:
Be sure that you're using the Swing library (JApplet, JPanel), not AWT (Applet, Panel, Canvas).
You're better off avoiding applets if at all possible.
Don't draw in a paint method but rather a JPanel's paintComponent(Graphics g) method.
Don't forget to call the super's method first thing in your paintComponent(Graphics g) method override.
You need to keep track of everything that has been painted and then repaint everything again.
See Custom Painting Approaches for the two common ways to do this:
Use a ArrayList to keep track of objects painted
Use a BufferedImage
here is an exemple of code you can use :
ArrayList<Point> points = new ArrayList<Point>();
private void draw(Graphics g){
for (Point p: this.points){
g.fillOval(1, 2, 2, 2);
}
}
//after defining this function you add this to your paint function :
draw(g)
g.drawRect(x1, y1, x2-x1, y2-y1);
points.add(new Point(x1, y1, x2-x1, y2-y1))
// PS : point is a class I created to refer to a point, but you can use whatever
Related
I am practicing Java, trying to get back into OOP programming. I decided to recreate snake using a tutorial online. I am using Graphics for my code and i was wondering if the paintComponent() method is called 60 times a second or something similar. My probelm is that i am building some walls, if the snake collides he dies, the walls however i only want them drawn once, but it seems that the walls are drawn over and over again (I tested this using sysout). Some code is provided below:
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
Inside the draw function
//Draw wall
wall1 = new Walls(10, 10, 10, 20, UNIT_SIZE, g);
The Walls constructor
Walls(int startX, int startY, int endX, int endY, int UNIT_SIZE, Graphics g)
{
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
g.setColor(Color.GRAY);
for(int i = startY; i<=endY; i++)
{
for(int j = startX; j<=endX; j++)
{
g.fillRect(UNIT_SIZE*j, UNIT_SIZE*i, UNIT_SIZE, UNIT_SIZE);
}
}
}
The Swing painting system calls paintComponent() whenever there's a need to update something about the appearance of your component. The reason can be that the window was hidden or partially obscured and now becomes visible again, or that the contents of the component changed.
So, whenever Swing calls paintComponent(), it's important to draw everything that falls into the paint-requested part of the component, otherwise you'll get nasty paint artifacts like missing elements or leftovers from previous window states.
From your description, I guess it's mostly your software requesting a repaint of your component, by calling the repaint() method somewhere in your code. My recommendations:
Make sure you supply a rectangle to the repaint() call specifying the region that has changed (the snake head, more or less). Swing only repaints the component parts that are known to need it, by setting a fitted clipping region before calling paintComponent().
Optimize your paintComponent() implementation to check whether the clipping region of the Graphics object intersects with your walls. If not, you can skip painting the walls.
I'm pretty new to Java and the GUI world. Right now I'm trying to create a really basic space shooter. To create it I started creating a JFrame, in which I've later on put a personal extension of a JPanel called GamePanel, on which I'm now trying to display all my components. Until here it's all pretty clear, the problem comes now: I have my GamePanel in which I display my player, and on the KeyEvent of pressing S the player should shoot the Bullets. I've managed the bullets as an Array, called Shooter[], of Bullet Objects, created by myself this way:
public class Bullet implements ActionListener{
Timer Time = new Timer(20, this);
private int BulletY = 430;
public int PlayerX;
public Rectangle Bound = new Rectangle();
public Bullet(int playerx) {
this.PlayerX = playerx;
Time.start();
}
public void draw(Graphics g){
g.setColor(Color.RED);
g.fillRect(PlayerX + 2, BulletY, 3, 10);
g.dispose();
}
#Override
public void actionPerformed(ActionEvent e) {
if (Time.isRunning()) {
BulletY = BulletY - 5;
Bound = new Rectangle (PlayerX + 2, BulletY, 3, 10);
}
}
}
I thought that calling the draw method in the GamePanel's paint() method would have allowed me to display both all the bullets shot and the player. What actually happens is that at the start it seems allright, but when I press S the player disappears and just one bullet is shot. Can you explain me why? This is how my paint() method looks like:
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, 500, 500);
for(int i = 0; i < BulletsCounter; i++) {
Shooter[i].draw(g);
}
g.setColor(Color.RED);
g.fillRect(PlayerX, PlayerY, 20, 20);
//System.out.println("Here I should have painted the player...");
g.dispose();
}
BulletsCounter is a counter I've created to avoid any NullPointerExceptions in painting the whole array, it increases when S is pressed and so another bullet of the array is initialized and shot.
Thank you for your patience, I'm new to the site, so warn me for any mistake.
You've several significant problems, the biggest given first:
You're disposing a Graphics object given to you by the JVM. Never do this as this will break the painting chain. Instead, only dispose of a Graphics object that you yourself have created.
You're drawing within paint which is not good for several reasons, but especially bad for animation since you don't have automatic double buffering of the image
You don't call the super painting method within your override and thus don't allow the JPanel to do house-keeping painting.
Recommendations:
Don't dispose of the Graphics object, not unless you, yourself, create it, for example if you extract one from a BufferedImage.
Override the JPanel's paintComponent method, not its paint method to give you double buffering and smoother animation.
And call super.paintComponent(g) first thing in your override to allow for housekeeping painting
I have the following task for my school in Java:
Create a GUI window with your own graphic. This graphic should be created in a separate JPanel class and drawn using the draw and fill methods of the java.awt.Graphics class (e.g. a house with a garden, a car, ...). The graphic should contain at least 5 different types of graphics (rectangle, oval, ...), at least one polygon (draw or fillPolygon (polygon p) method) and an arc (draw or fillArc method (int x, int y, int width, int height, int startAngle, int arcAngle)). The graphic should also contain at least 10 drawing elements and consist of at least 4 different colors.
But I don´t know how to use the class Graphics, so I don´t know how to create a Grahpics object and edit it. Does anyone know how to solve this? Thank you
You can use graphics with a JPanel;
class exampleclass extends JPanel {
exampleClass() {
...
}
#Override
public void paintComponent(Graphics g) {
...your code here...
}
}
For more information, look at; https://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html
You can call paint method with, repaint();
I'm making a space game that renders objects onto a JPanel.
These objects' render method is called in my Space class.
I have 2 objects, alienShip and myShip with respective classes. Each class has a render method. I can't get both ships to render onto my JPanel simultaneously, it's either one or the other. I only see the object that calls the .render(g2) method first.
SPACE CLASS:
spaceImage=new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
foregroundImage=new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
//create the space Image background and instantiate ships (myShip, alienShip)
//Below render() method is called in my Game class using a standard game loop with
update method and rendor method.
public void render(Graphics2D g) {
Graphics2D g2=(Graphics2D) foregroundImage.getGraphics();
g2.drawImage(spaceImage, 0, 0, null);
myShip.render(g2); <---alienShip does not appear, only myShip.
alienShip.render(g2); <---If I swap these 2 commands, then alienShip appears,
and myShip does not
g.drawImage(foregroundImage, x, x, null);
}
ALIENSHIP AND MYSHIP CLASS:
public void render(Graphics2D g) {
g.drawImage(shipImage, x, y, null);
g.dispose();
}
I've tried to create a Drawable interface, and loop through all drawable objects calling DrawableObject.render(g2), but doesn't fix it. Furthermore, I have bullets that DO rendor simultaneously with myShip.
myShip and alienShip does extend an abstract class called Ship as well. Hope this makes sense.
You're .dispose()ing the graphics object after drawing one item, then trying to draw another item with it.
Currently I have a JPanel with its paintComponent overridden with lots of image processing based on various states. When an event occurs (infrequent) many of the states change and the images that are drawn change. It doesn't seem the best way to keep doing all the processing every time the paintComponent is it possible to do something like when an event occurs draw everything to a Graphics2D instance and then merge this with the paintComponent one? Is this also the best way to do it?
As MadProgrammer suggested, storing rendered output can help you.
When the event that might change the image occurs, you can draw stuff to a BufferedImage like following.
private BufferedImage renderedImage;
public void triggerEvent(int width, int height) {
this.renderedImage = new BufferedImage(width, height, TYPE_INT_ARGB);
Graphics2D g = this.renderedImage.createGraphics();
// Paint things on g.
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(this.renderedImage, 0, 0, this);
}
Hope this helps.