public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.fillRect(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_DOWN) {
System.out.println("down");
ball.moveY(5);
}
if(keyCode == KeyEvent.VK_UP) {
System.out.println("up");
ball.moveY(-5);
}
if(keyCode == KeyEvent.VK_LEFT) {
System.out.println("left");
ball.moveX(-5);
}
if(keyCode == KeyEvent.VK_RIGHT) {
System.out.println("right");
ball.moveX(5);
}
System.out.println("X: " +ball.getX() +", Y: " +ball.getY());
repaint();
}
When I press an arrow key and move the ball, why doesn't the repaint() method erase the ball's location from before? It's creating a tail thing.
Thanks
You are forgetting to call the super's paintComponent. i.e.,
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
}
Note
that paintComponent should be protected, not public. Also, don't forget the #Override annotation.
KeyListeners should be avoided for Swing applications. Key Bindings are in general preferred since they are "higher level" concepts.
Because you've broken the paint chain.
One of the jobs that paintComponent does is to clear the Graphics context of what ever was painted to it before.
Make sure you call super.paintComponent first
Generally, the Graphics context is a shared resource, this means that everything that was painted during a paint cycle will share the same Graphics context. It also means that it's possible that the same Graphics context will be used for a single native peer (as is the case for you). You must always make best efforts to clean the context before use (transparency being a special case)
Take a look at Painting in AWT and Swing for more details about how painting is done in Swing
As has already being suggested, it is recommended that you use the Key Bindings API over KeyListener, the most significant reasons is because the key bindings API gives you greater control of the level of focus required before a key event is triggered
You are forget to call super.paintComponent(g). Have a look at PaintComponent
Try to replace
public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.fillRect(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
}
By
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(ball.getX(), ball.getY(), ball.getWidth(), ball.getHeight());
}
Related
I know there's no direct replacement for java.awt.Canvas in swing, and I know I'm supposed to use a JPanel and override paintComponent, for example like so:
public void paintComponent(Graphics g) {
g.setColor(Color.black);
g.drawOval(0, 0, 100, 100);
}
And this would draw a black circle on the JPanel when it is created. The problem I have is that I want a dynamic canvas: I want to be able to draw things in response to user input, and redraw continuously, not just once when the application starts. An example would be having a moving object on a canvas, that would need to be redrawn at a rate of say 60 frames per second. How could I achieve this without using AWT components?
EDIT: what I mean is, in an actual canvas, I'd be able to arbitrarily call, say, drawOval anywhere in my code, and that would draw an oval on the canvas; is this doable with JPanel?
Store the information to be drawn (e.g. a Shape or a group of them) and call repaint() from a Swing Timer. Each time the paintComponent(..) method is called, first call the super(..) method to erase the previous drawings, then iterate the list of shapes, move them if necessary, and draw each one.
Here's one way to do it:
public class Renderer extends JComponent implements ActionListener {
private int x;
public Renderer() {
Timer timer = new Timer(1000/60, this);
timer.start();
x = 0;
}
#Override
public void paintComponent(Graphics g) {
super.paint(g);
// drawing code
g.setColor(Color.black);
g.drawOval(x, 0, 100, 100);
}
private void update() {
this.x++;
}
#Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
}
Now just add this to your component (JPanel or whatever):
comp.add(new Renderer());
I want to understand this code
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class pinpon extends JFrame {
private Image image;
private Graphics graph;
int x , y ;
public class klavye extends KeyAdapter{
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
if (key == e.VK_LEFT)
x=x-5;
if (key == e.VK_RIGHT)
x=x+5;
if (key == e.VK_UP)
y=y-5;
if (key == e.VK_DOWN)
y=y+5;
}
public void keyReleased(KeyEvent e){
}
}
public pinpon(){
addKeyListener(new klavye());
setSize(640, 480);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x=150;
y=150;
}
public void paint(Graphics g){
image = createImage(getWidth(), getHeight());
paintComponent(image.getGraphics());
g.drawImage(image,0,0,this);
}
public void paintComponent(Graphics g){
g.fillOval(x, y, 15, 15);
repaint();
}
public static void main(String[] args) {
new pinpon();
}
}
but in here i thing this code is for double buffering
public void paint(Graphics g){
image = createImage(getWidth(), getHeight());
paintComponent(image.getGraphics());
g.drawImage(image,0,0,this);
}
This code is used for moving ball without any trace of ball. But i did not understand how is it works. Can anybody help me. Or tell me where can i find any explanation. Thanks.
But i did not understand how is it works
Me either and you should not even worry about what it is doing because that code is completely wrong and should NOT be used for several reasons:
you would never invoke paintComponent() directly
you would never invoke repaint() in a painting method. This will cause an infinite loop
custom painting is done by overriding the paintComponent() method only. You don't need to override paint().
Read the section from the Swing tutorial on Custom Painting for explanations and examples of how painting SHOULD be done.
Once you understand the basics of painting properly then you can move on to getting rid of the KeyListener. Instead you should be using Key Bindings. All Swing components use Actions and Key Bindings to handle specific keyboard input from the user. Check out Motion Using the Keyboard for more information and working examples.
I put this code together based on a lot of examples I found around here on stackoverflow. When I run the program the entire screen flickers intensely. I'm sure there is something simple I'm overlooking, but so far have been unable to track down a solution. I've been debugging this for a couple hours mostly with the help of online forum reading, so I figured it was time to ask the audience.
public class Screen extends JComponent {
#Override
public Dimension getPreferredSize(){
Dimension tempDimension = Toolkit.getDefaultToolkit().getScreenSize();
return tempDimension;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)bufferStrategy.getDrawGraphics();
g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); //sprites overlap instead of overwrite
if(game==null){
drawSplash(g2D);
}else{
drawBoard(g2D);
}
g2D.dispose();
bufferStrategy.show();
}
}
If any additional code is required, I can provide it. Thank you for your help, stackoverflow!
To achieve the results you are getting, you either have another class which extends from Canvas or are using the BufferStrategy from the top level container. In either case, both must be visible on the screen.
Basically, they are fighting each other, as they are two different painting algorithms. Swing, which is a passive painting algorithm, paints updates as they are needed and the BufferStrategy, which uses an active algorithm, requiring your to schedule the updates to the buffer as required.
Both use a double buffering algorithm.
So, you should pick one or the other...
public class Screen extends JComponent {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g.create();
g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); //sprites overlap instead of overwrite
if (game == null) {
drawSplash(g2D);
} else {
drawBoard(g2D);
}
g2D.dispose();
}
}
or something like...
public void gameEngine(BufferStrategy strategy) {
// Main loop
while (!done) {
// Prepare for rendering the next frame
// ...
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
// Get a new graphics context every time through the loop
// to make sure the strategy is validated
Graphics2D g2D = (Graphics2D) strategy.getDrawGraphics();
// Render to graphics
g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); //sprites overlap instead of overwrite
if (game == null) {
drawSplash(g2D);
} else {
drawBoard(g2D);
}
// Dispose the graphics
g2D.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
}
Which was pretty much ripped from the JavaDocs for BufferStrategy
BTW, this...
#Override
public Dimension getPreferredSize(){
Dimension tempDimension = Toolkit.getDefaultToolkit().getScreenSize();
return tempDimension;
}
is a really bad design, you are making assumptions about the state of the component which may not meet reality. You should allow the window to decide how large it ultimately wants to be, which can be achieved by using setExtendedState and passing it JFrame.MAXIMIZED_BOTH, which will take into consideration other OS elements, like the task bar or dock
I've a JPanel where I'm drawing with the mouse events and after resizing, or minimizing-restoring it, it doesnt display what has to be drawn, despite a "degub" println shows me the function is being called, but for some reason, it reamains blank
I thought I should have added my drawing function in the paintComponent function but it seems not to be working right, so what I'm doing wrong or where should I place that drawElements() call?
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
drawElements();
}
void drawElements() {
Graphics2D g = (Graphics2D)this.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Element el : elements) {
el.draw(g);
}
}
Pass the graphics object to the drawElements method.
(Right answer provided by #rafalopez79)
I realize that a major component missing from my game is a sense of time, ticks, or FPS. I am planning on implementing this soon, but wanted to get some feedback on how to set up my "bullets" instead. I want the user to press the space bar and have a bullet fired across the screen. Now I have gotten close without a sense of FPS; however, it just draws as one giant line, meaning the bullet "trail" never clears. I am wondering why, when I call repaint, the rectangle can move around the screen via my keyboard, but whenever I have something set automatically to move then it just leaves a "trail", even though I am calling repaint(); in each method.
Also, how could i create my bullet from another class?
public class drawingComponent extends JComponent implements KeyListener {
public Rectangle hello = new Rectangle(300, 100, 50, 50);
Rectangle bullet = new Rectangle(310,75, 10,10);
boolean goingon = false;
public drawingComponent(){
addKeyListener(this);
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setColor(new Color(255,25,0));
g2.setFont(new Font("monospace", Font.BOLD+Font.ITALIC, 30));
g2.drawString("nothing yet",300,320);
g2.fill(hello);
setFocusable(true);
requestFocus();
g2.setColor(new Color(0,25,0));
if (goingon == true){
while (bullet.y < 1000){
bullet.y=bullet.y+10;
g2.fill(bullet);
}
bullet.y=300;
}
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W){
hello.y=hello.y-1;
hello.setLocation(hello.x,hello.y);
repaint();
System.out.println(hello.y);
}
if(e.getKeyCode() == KeyEvent.VK_S){
hello.y=hello.y+1;
hello.setLocation(hello.x,hello.y);
repaint();
}
if(e.getKeyCode() == KeyEvent.VK_A){
hello.x=hello.x-1;
hello.setLocation(hello.x,hello.y);
repaint();
}
if(e.getKeyCode() == KeyEvent.VK_D){
hello.x=hello.x+1;
hello.setLocation(hello.x,hello.y);
repaint();
}
if(e.getKeyCode() == KeyEvent.VK_SPACE){
goingon = true;
repaint();
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_SPACE){
goingon = false;
repaint();
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
Start by repairing the paint chain...
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(new Color(255,25,0));
g2.setFont(new Font("monospace", Font.BOLD+Font.ITALIC, 30));
g2.drawString("nothing yet",300,320);
g2.fill(hello);
Next, stop changing the state of the component from within the paint method...
//setFocusable(true);
//requestFocus();
g2.setColor(new Color(0,25,0));
if (goingon == true){
while (bullet.y < 1000){
bullet.y=bullet.y+10;
g2.fill(bullet);
}
bullet.y=300;
}
Painting should simply paint the current state of the component, it should never attempt to modify the state of the component, doing so could trigger another paint request which will put your code into an infinite loop of painting and consume your CPU cycles.
Swing uses a passive rendering algorithm, this means, painting is carried out only when the repaint manager thinks it needs to be done, meaning that painting can be done at random and mostly without your intervention...
Based on the fact that you are trying to force focus to the component, I assume you are trying to overcome issues related to KeyListener. Instead, you should use the key bindings API. Take a look at How to Use Key Bindings for more details
Take a look at Painting in AWT and Swing and Performing Custom Painting for more details.
Don't forget to call super.paintComponent() in overridden paintComponent() method that clears the previews view.
Read more...