When running my program, sometimes the the triangles are drawn, sometimes they aren't, and sometimes only the last one appears. Originally I put the code in a for loop, but it didn't work, so I tried to go backwards and write it all out instead to see if it works, but to no avail. The correct behavior should be, displaying five triangles, equally spaced on the screen (Directly below the top rectangle). I tried printing out the array, but the number of times the println() method was called was sort of random, instead of constant. I heard that the paintComponent() method can be called at any time by the Swing Framework, but I'm not sure. Essentially I'm asking, why the triangles (the cyan ones) aren't being drawn correctly, and how do I fix it?
#SuppressWarnings("serial")
public class GraphicsClass extends JPanel {
private int[] xCoordinates = {20, 40, 30};
private int[] yCoordinates = {40, 40, 60};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, 450, 40);
g.fillRect(0, 260, 450, 40);
g.setColor(Color.CYAN);
g.fillPolygon(xCoordinates, yCoordinates, 3);
xCoordinates[0] += 95;
xCoordinates[1] += 95;
xCoordinates[2] += 95;
g.fillPolygon(xCoordinates, yCoordinates, 3);
xCoordinates[0] += 95;
xCoordinates[1] += 95;
xCoordinates[2] += 95;
g.fillPolygon(xCoordinates, yCoordinates, 3);
xCoordinates[0] += 95;
xCoordinates[1] += 95;
xCoordinates[2] += 95;
g.fillPolygon(xCoordinates, yCoordinates, 3);
xCoordinates[0] += 95;
xCoordinates[1] += 95;
xCoordinates[2] += 95;
g.fillPolygon(xCoordinates, yCoordinates, 3);
}
}
Think about it this way. paintComponent may be called any time (upwards of four times when the component is first painted on the screen in some cases). So each time it is called, you're adding 95 to each of the xCoordinates, this would make xCoordinates[0] equal to 400 after paintComponent is called the first time, 800 after the second time, so on and so fourth...
Instead, you need to make a copy of the xCoordinates and modify it instead, for example...
public class TestPane extends JPanel {
private int[] xCoordinates = {20, 40, 30};
private int[] yCoordinates = {40, 40, 60};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, 450, 40);
g.fillRect(0, 260, 450, 40);
int[] xPosy = Arrays.copyOf(xCoordinates, xCoordinates.length);
g.setColor(Color.CYAN);
for (int index = 0; index < 4; index++) {
g.fillPolygon(xPosy, yCoordinates, 3);
xPosy[0] += 95;
xPosy[1] += 95;
xPosy[2] += 95;
}
}
}
Of course, you could forgo some of the oddities and just make use of the 2D Graphics Shape API
public class TestPane extends JPanel {
private Polygon triangle;
public TestPane() {
triangle = new Polygon(new int[]{20, 40, 30}, new int[]{40, 40, 60}, 3);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.DARK_GRAY);
g2d.fillRect(0, 0, 450, 40);
g2d.fillRect(0, 260, 450, 40);
g2d.setColor(Color.CYAN);
AffineTransform at = AffineTransform.getTranslateInstance(0, 0);
for (int index = 0; index < 4; index++) {
Shape shape = at.createTransformedShape(triangle);
g2d.fill(shape);
at.translate(95, 0);
}
}
}
Related
I am trying to repaint a string used to keep score in a small java game I'm making but I am not sure how to have the string change on the screen. As you can see it is initially drawn, and I am trying to update it inside of the ingame if statement.
public void paint(Graphics g)
{
super.paint(g);
g.setColor(Color.white);
g.fillRect(0, 0, d.width, d.height);
//g.fillOval(x,y,r,r);
//Draw Player
g.setColor(Color.red);
g.fillRect(p.x, p.y, 20, 20);
if(p.moveUp == true) {
p.y -= p.speed;
}
moveObstacles();
for (int i = 0; i < o.length; i++ ) {
g.fillRect(o[i].x, o[i].y, 10, 5);
}
Font small = new Font("Helvetica", Font.BOLD, 14);
FontMetrics metr = this.getFontMetrics(small);
g.setColor(Color.black);
g.setFont(small);
g.drawString(message, 10, d.height-60);
g.drawString(message2, 10, d.height-80);
if (ingame) {
for (int i = 0; i < o.length; i++ ) {
if ((o[i].x < p.x + 20 && o[i].x > p.x) && (o[i].y < p.y + 20 && o[i].y > p.y)) {
p.x = BOARD_WIDTH/2;
p.y = BOARD_HEIGHT - 60;
lives = lives - 1;
g.drawString(message, 10, d.height-60);
}
}
// g.drawImage(img,0,0,200,200 ,null);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
You create a method like setMessage(…). This method with then save the "message" as a property in your class.
The method will then invoke repaint(), which will cause the component to repaint itself.
This is how all Swing components work. Think about a JLabel and the setText(…) method.
Also:
Custom painting is done by overriding the paintComponent() method, not the paint() method.
There is no need for the Toolkit sync() method.
You should NOT dispose of the Graphics object.
Completing a graphics program in Java, I'm trying to animate rain falling using a timer. Right now I am testing my code with a big blue rectangle so I can see where it's going but the animation isn't working for me. I'm very new to Java graphics so I could be making mistakes that just aren't clear to me.
When I try to repaint the square to move, and the paint function is called the whole screen blinks, this may be because I was using recursive functions to draw fractal trees, but I'm not sure. Is there a way to keep everything I have drawn from being repainted and just call repaint on the rain? Any guidance or tips would be appreciated.
import java.awt.*;
import javax.swing.*;
import java.lang.Math;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class FractalTree extends JFrame {
private int frameWidth = 1440;
private int frameHeight = 850;
private int rainX = 0;
private int rainY = 0;
public FractalTree()
{
setBounds(1000, 1000, frameWidth, frameHeight ); //graphics window size
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ActionListener listener = new TimerListener();
final int DELAY = 1500;
Timer t = new Timer(DELAY, listener);
t.start();
setResizable(false);
}
public void setRain(int newRainX, int newRainY)
{
rainX = newRainX;
rainY = newRainY;
}
public void setSkyGround(Graphics g)
{
Color sky = new Color(180, 225, 255);
g.setColor(sky);
g.fillRect(0, 0, frameWidth, 550);
Color sun = new Color(225, 225, 150);
g.setColor(sun);
g.fillOval(1380, -40, 100, 100);
g.drawLine(frameWidth, 0, 1350, 550);
g.drawLine(frameWidth, 0, 1450, 550);
g.drawLine(1350, 550, 1450, 550);
int xpoints[] = {frameWidth, 1450, 1350};
int ypoints[] = {0, 550, 550};
int npoints = 3;
g.fillPolygon(xpoints, ypoints, npoints);
g.drawLine(frameWidth, 0, 1080, 550);
g.drawLine(frameWidth, 0, 880, 550);
g.drawLine(880, 550, 1080, 550);
int xpoints2[] = {frameWidth, 1080, 880};
int ypoints2[] = {0, 550, 550};
int npoints2 = 3;
g.fillPolygon(xpoints2, ypoints2, npoints2);
g.drawLine(frameWidth, 0, 480, 550);
g.drawLine(frameWidth, 0, 280, 550);
g.drawLine(480, 550, 280, 550);
int xpoints3[] = {frameWidth, 480, 280};
int ypoints3[] = {0, 550, 550};
int npoints3 = 3;
g.fillPolygon(xpoints3, ypoints3, npoints3);
g.drawLine(frameWidth, 0, 0, 430);
g.drawLine(frameWidth, 0, 0, 300);
g.drawLine(0, 430, 0, 300);
int xpoints4[] = {frameWidth, 0, 0};
int ypoints4[] = {0, 430, 300};
int npoints4 = 3;
g.fillPolygon(xpoints4, ypoints4, npoints4);
g.drawLine(frameWidth, 0, 0, 100);
g.drawLine(frameWidth, 0, 0, 0);
g.drawLine(0, 100, 0, 0);
int xpoints5[] = {frameWidth, 0, 0};
int ypoints5[] = {0, 0, 100};
int npoints5 = 3;
g.fillPolygon(xpoints5, ypoints5, npoints5);
Color grassBackground = new Color(150, 255, 170);
g.setColor(grassBackground);
g.fillRect(0, 550, frameWidth, frameHeight);
}
public void drawTree(Graphics g, int x1, int y1, double angle, int depth, int red, int green, int blue)
{
if (depth == 0)
{
Color doodle = new Color(red, green, blue);
g.setColor(doodle);
g.fillOval(x1, y1, 10, 10);
}
else
{
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(depth));
Color brown = new Color(100, 25, 0);
g.setColor(brown);
int x2 = x1 + (int) (Math.cos(Math.toRadians(angle)) * depth * 10);
int y2 = y1 + (int) (Math.sin(Math.toRadians(angle)) * depth * 10);
g.drawLine(x1, y1, x2, y2);
drawTree(g, x2, y2, angle - 40, depth - 1, red, green, blue);
drawTree(g, x2, y2, angle + 20, depth - 1, red, green, blue);
}
}
public void realFlowers(Graphics g, int x, int y, int lenWid, int petals)
{
//calculates the increment
double inc = (2*Math.PI/petals);
g.setColor(Color.YELLOW);
//draws petals
for(int i = 0; i < petals; i++){
//keeps spacing consistent depandng on number of petals
double value = i * inc;
//draws petals with calculated spacing relative to number of petals
g.fillOval((int)((lenWid)*Math.cos(value)+x-lenWid/4),(int)((lenWid)*Math.sin(value)+y-lenWid/4), lenWid + lenWid/2, lenWid + lenWid/2);
}
//draws middle flower bud;
g.setColor(Color.ORANGE);
g.fillOval(x - lenWid/4, y - lenWid/4, lenWid + lenWid/2 , lenWid + lenWid/2);
}
public void drawGrass(Graphics g, int width, int height, int interval, int red, int green, int blue)
{
height = frameHeight - height;
Color grass = new Color(red, green, blue);
for(int i = 0; i < width; i= i + interval)
{
for(int j = frameHeight; j > height; j = j - interval)
{
g.setColor(grass);
g.fillRect(i, j, 3, 5);
}
}
}
public void rainDrops(Graphics g, int x, int y, int w, int h)
{
setRain(x, y);
Color rain = new Color(0, 76, 153);
g.setColor(rain);
g.fillRect(x, y, w, h);
}
public void moveRainBy(int dx, int dy)
{
rainX = rainX + dx;
rainY = rainY + dy;
repaint();
}
class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
moveRainBy(1, 1);
}
}
public void paint(Graphics g) {
setSkyGround(g);
drawGrass(g, 1440, 315, 5, 0, 255, 0);
drawGrass(g, 1430, 310, 10, 0, 204, 0);
drawTree(g, 1085, 730, -90, 10, 255, 102, 102);
drawTree(g, 250, 600, -90, 8, 255, 255, 255);
drawTree(g, 1110, 740, -90, 4, 255, 102, 102);
drawTree(g, 1060, 745, -90, 2, 255, 102, 102);
realFlowers(g, 700,700, 8, 8);
rainDrops(g, 200, 200, 30, 30);
}
public static void main(String[] args) {
new FractalTree().setVisible(true);
}
}
When I try to repaint the square to move, and the paint function is called the whole screen blinks
This is because you've override paint of the a top level container (JFrame) which is not double buffered.
As a general recommendation, you should be basing your core functionality around a JPanel and override it's paintComponent method. Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
You might like to also have a look at How to get the EXACT middle of a screen, even when re-sized and How can I set in the midst? for more details why it's not recommended to extend directly from JFrame and try to paint to it.
Is there a way to keep everything I have drawn from being repainted and just call repaint on the rain?
Painting is destructive, that is, each time paint/paintComponent is called, you are expected to repaint the entire state of the component from scratch.
You could use a buffering technique, using something like BufferedImage to paint your state to and simply have the paint methods draw the image, but that would depend on how complex a solution you want. If you were to use buffering technique, I would consider which elements are "static" and which elements are "dynamic". Painting those static elements to the buffer and then, when paint is called, painting the dynamic elements over the top the buffer
Please help me how to make this eye move or to make it blink using repaint, thread and implements runnable. I don't know where to place the right codes to make it work. Please help me guys! Thank you!
Here is the code:
import java.awt.*;
import java.applet.*;
public class Pucca extends Applet {
public Pucca(){
setSize(700, 700); }
//paint method
public void paint(Graphics g){
Color white = new Color(255,255,255);
g.setColor(white);
g.fillOval(600, 100, 125, 125); //left white fill eye
g.setColor(Color.BLACK);
g.drawOval(600, 100, 125, 125); // left big black line eye
g.setColor(white);
g.fillOval(700, 100, 125, 125); //right white fill eye
g.setColor(Color.BLACK);
g.drawOval(700, 100, 125, 125); //right big black line eye
Color blue = new Color(0, 160, 198);
g.setColor(blue);
g.fillOval(635, 130, 51, 51); // left blue fill eye
g.setColor(Color.BLACK);
g.drawOval(635, 130, 50, 50); // left black small line eye
g.setColor(blue);
g.fillOval(735, 130, 51, 51); // right blue fill eye
g.setColor(Color.BLACK);
g.drawOval(735, 130, 50, 50); // right black small line eye
g.setColor(Color.BLACK);
g.fillOval(650, 145, 20, 20); // left black iris
g.setColor(Color.BLACK);
g.fillOval(750, 145, 20, 20); // right black iris
}
}
When it comes to animation, everything becomes variable. You also have a lot of repeated code (seriously, if you can paint one eye, you can paint lots).
The first thing you need to is make all the values of the eye as variable as possible.
The follow makes the eye size and position variable and the iris and pupil a scaled value of the eye size, which makes the whole process simpler to animate.
Next, you need an updated loop, which can update the state of the values you want to change. To keep it simple, I've set it up so that the pupil has a variable offset, which is changed over time.
import java.applet.Applet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
public class Pucca extends Applet {
public Pucca() {
setSize(700, 700);
Thread t = new Thread(new Runnable() {
private int xDelta = -1;
private int yDelta = 0;
private int blinkCount = 0;
#Override
public void run() {
while (true) {
try {
Thread.sleep(40);
} catch (InterruptedException ex) {
}
xOffset += xDelta;
double irisSize = eyeSize.width * irisScale;
double range = ((eyeSize.width - irisSize) / 2);
if (xOffset <= -range) {
xOffset = -(int) range;
xDelta *= -1;
} else if (xOffset >= range) {
xOffset = (int) range;
xDelta *= -1;
}
blinkCount++;
if (blink && blinkCount > 10) {
blink = false;
blinkCount = 0;
} else if (blinkCount > 25) {
blink = true;
blinkCount = 0;
}
repaint();
}
}
});
t.setDaemon(true);
t.start();
}
private boolean blink = false;
private int xOffset, yOffset = 0;
private Dimension eyeSize = new Dimension(125, 125);
private Point left = new Point(20, 20);
private Point right = new Point(left.x + 100, left.y);
private double irisScale = 0.4;
private double pupilScale = 0.16;
//paint method
#Override
public void paint(Graphics g) {
super.paint(g);
paintEye(g, new Rectangle(left, eyeSize));
paintEye(g, new Rectangle(right, eyeSize));
}
protected void paintEye(Graphics g, Rectangle bounds) {
Color white = new Color(255, 255, 255);
if (blink) {
g.setColor(Color.YELLOW);
} else {
g.setColor(white);
}
g.fillOval(bounds.x, bounds.y, bounds.width, bounds.height); //left white fill eye
g.setColor(Color.BLACK);
g.drawOval(bounds.x, bounds.y, bounds.width, bounds.height); // left big black line eye
if (!blink) {
Color blue = new Color(0, 160, 198);
paintEyePartAt(g, bounds, irisScale, blue);
paintEyePartAt(g, bounds, pupilScale, Color.BLACK);
}
}
private void paintEyePartAt(Graphics g, Rectangle bounds, double delta, Color color) {
int width = (int) (bounds.width * delta);
int height = (int) (bounds.height * delta);
g.setColor(color);
g.fillOval(
xOffset + bounds.x + ((bounds.width - width) / 2),
yOffset + bounds.y + ((bounds.height - height) / 2),
width, height); // left blue fill eye
g.setColor(Color.BLACK);
g.drawOval(
xOffset + bounds.x + ((bounds.width - width) / 2),
yOffset + bounds.y + ((bounds.height - height) / 2),
width,
height); // left blue fill eye
}
}
This complicates things, as painting can occur for any number of reasons, many of which you don't have control over or will be notified about, so you should be very careful about where and when you change values.
You should also have a look at Java Plugin support deprecated and Moving to a Plugin-Free Web and Why CS teachers should stop teaching Java applets.
Applets are simply a dead technology and given the inherent complexities involved in using them, you should instead focus you should probably attention towards window based programs.
Personally, I'd start with having a look at Painting in AWT and Swing and Performing Custom Painting
I am working on Air Hockey Game for my midterm project.
I have problem with handling two graphics, in this case two handles each of them consists of 3 circles.
I can move only one handle because of keyPressed method.
Another problem is that I can't limit the moving domain, for example when you pressed → the red handle can go beyond the frame width.
I know first problem is related to thread, but I've studied this subject from last week.
My problems are in this class:
public class StartGamePanel extends JPanel implements KeyListener, ActionListener {
double xCircle1 = 200;
double yCircle1 = 100;
double xCircle2 = 200;
double yCircle2 = 700;
double velX = 0, velY = 0;
public StartGamePanel() {
Timer t = new Timer(5, this);
t.start();
addKeyListener(this);
setFocusable(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setColor(new Color(51, 153, 255));
g.fillRoundRect(5, 5, 485, 790, 10, 10);
addKeyListener(this);
Graphics2D southArc = (Graphics2D) g;
southArc.setColor(Color.WHITE);
southArc.setStroke(new BasicStroke(3));
southArc.drawArc(98, 640, 300, 300, 0, 180);
//
Graphics2D northArc = (Graphics2D) g;
northArc.setColor(Color.WHITE);
northArc.setStroke(new BasicStroke(3));
northArc.drawArc(98, -143, 300, 300, 180, 180);
Graphics2D line = (Graphics2D) g;
line.setStroke(new BasicStroke(3));
line.setColor(Color.white);
line.drawLine(6, 395, 488, 395);
Graphics2D dot = (Graphics2D) g;
dot.setColor(Color.black);
for (int j = 10; j < 800; j += 20) {
for (int i = 6; i < 502; i += 20) {
dot.drawLine(i, j, i, j);
}
}
Graphics2D circle1 = (Graphics2D) g;
circle1.setColor(new Color(255, 51, 51));
Shape theCircle = new Ellipse2D.Double(xCircle1 - 40, yCircle1 - 40, 2.0 * 40, 2.0 * 40);
circle1.fill(theCircle);
Graphics2D circle2 = (Graphics2D) g;
circle2.setColor(new Color(255, 102, 102));
Shape theCircle2 = new Ellipse2D.Double(xCircle1 - 35, yCircle1 - 35, 2.0 * 35, 2.0 * 35);
circle2.fill(theCircle2);
Graphics2D circle3 = (Graphics2D) g;
circle3.setColor(new Color(255, 51, 51));
Shape theCircle3 = new Ellipse2D.Double(xCircle1 - 20, yCircle1 - 20, 2.0 * 20, 2.0 * 20);
circle3.fill(theCircle3);
Graphics2D circleprim = (Graphics2D) g;
circleprim.setColor(new Color(0, 51, 102));
Shape theCircleprim = new Ellipse2D.Double(xCircle2 - 40, yCircle2 - 40, 2.0 * 40, 2.0 * 40);
circleprim.fill(theCircleprim);
Graphics2D circle2prim = (Graphics2D) g;
circle2prim.setColor(new Color(0, 102, 204));
Shape theCircle2prim = new Ellipse2D.Double(xCircle2 - 35, yCircle2 - 35, 2.0 * 35, 2.0 * 35);
circle2prim.fill(theCircle2prim);
Graphics2D circle3prim = (Graphics2D) g;
circle3prim.setColor(new Color(0, 51, 102));
Shape theCircle3prim = new Ellipse2D.Double(xCircle2 - 20, yCircle2 - 20, 2.0 * 20, 2.0 * 20);
circle3prim.fill(theCircle3prim);
Graphics2D ball = (Graphics2D) g;
ball.setColor(new Color(224, 224, 224));
Shape theball = new Ellipse2D.Double(200 - 20, 400 - 20, 2.0 * 20, 2.0 * 20);
ball.fill(theball);
Graphics2D ball2 = (Graphics2D) g;
ball2.setColor(new Color(160, 160, 160));
Shape theball2 = new Ellipse2D.Double(200 - 15, 400 - 15, 2.0 * 15, 2.0 * 15);
ball2.fill(theball2);
Graphics2D goal = (Graphics2D) g;
goal.setColor(Color.BLACK);
goal.fill3DRect(100, 0, 300, 10, true);
Graphics2D goal2 = (Graphics2D) g;
goal2.setColor(Color.BLACK);
goal2.fill3DRect(100, 790, 300, 10, true);
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
xCircle1 += velX;
yCircle1 += velY;
}
#Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
velY = -2;
velX = 0;
}
if (code == KeyEvent.VK_DOWN) {
velY = 2;
velX = 0;
}
if (code == KeyEvent.VK_LEFT) {
if (xCircle1 < 0) {
velY = 0;
velX = 0;
} else {
velY = 0;
velX = -2;
}
}
if (code == KeyEvent.VK_RIGHT) {
if (xCircle1 > 200) {
velY = 0;
velX = 0;
}
velY = 0;
velX = 2;
}
}
#Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
velY = 0;
velX = 0;
}
if (code == KeyEvent.VK_DOWN) {
velY = 0;
velX = 0;
}
if (code == KeyEvent.VK_LEFT) {
velY = 0;
velX = 0;
}
if (code == KeyEvent.VK_RIGHT) {
velY = 0;
velX = 0;
}
}
#Override
public void keyTyped(KeyEvent e) { }
}
Thanks!
Your key listener should be as quick as possible so it does not block following key events. Since several people press keys almost at the same time, this situation is common in games.
So the advice would be to use separate thread to listen for key presses which will quickly add events to a queue. This queue then will be processed on EDT(Swing main thread) and paint the results.
You can check out the KeyboardAnimation.java example found in Motion Using The Keyboard. It attempts to explain why Key Bindings are preferred over using a KeyListener.
The example code will animate two images. The left image controlled by W, A, S, D and the right image by Up, Down, Left and Right arrow keys. It also keeps the images within the window bounds. The code is not an actual game, it was just designed to show one way to use configurable Key Bindings.
You might want to also want to change the way the keypress's are handled. At the moment (I think) your only detecting one key down at a time.
You probably need to have an array for "heldkeys" and every time a key is down, add to that array. When a key is released, subtract that key from it.
Then, at a interval, check what keys are in the "heldkeys" array and act on them all.
At least, you will probably need something like this if you plan to have two players. (who both should be able to press keys at the same time).
I don't know Swing well enough to give you exact code, but it will be something like;
//an array of numbers to hold the key-codes of the keys currently held down
HashSet<Integer> HeldKeys = new HashSet<Integer>();
#Override
public void keyDown(KeyEvent e) {
// add key to keys currently held down
HeldKeys.add(e.getKeyCode());
}
#Override
public void keyUp(KeyEvent e) {
//remove key from list of things currently held
HeldKeys.remove(e.getKeyCode());
}
#Override
public void keyPress(KeyEvent e) {
Iterator<Integer> kit = HeldKeys.iterator();
//we loop over every key currently held down, running actions for them if
//there is any assigned.
//For example, one button might move a sprite on the left down
//Another might move a sprite on the right. One, the other, or both should be
//able to all move without waiting for the other.
while (kit.hasNext()) {
int keycode = kit.next();
if (keycode==48){
//do stuff if key with code 48 is held
//(move one of the circles, etc)
}
if (keycode==46){
//do stuff if key with code 46 is held
}
//...etc, for any number of keys you want to do different things for.
}
}
Note; With this method you are not detecting a keypress as one thing, but rather detecting both the key being held down, and then the key being released as separate events.
As people wont hit the keys at the exact same time, this lets you detect lots of keys at once.
This code is off the top of my head, Java, but I have a gwt background, so the names for "keydown" and "keyup" etc might be different.
The "keypress" event in gwt will repeat automatically, if that's not the case in Swing you might need to use a Timer instead, running at an interval. (you might prefer this anyway as its a bit more controllable).
I am using a paintComponent Class in a project of mine, and I am currently wondering how I can decrease the size of the rectangle from the top making it's way downwards.
This is the part of the code:
public Battery(){
super();
firstTime = true;
f = new Font("Helvetica", Font.BOLD, 14);
m = Toolkit.getDefaultToolkit().getFontMetrics(f);
}
public void paintComponent(Graphics g){
if(firstTime){
firstTime = false;
batteryLevel = 1 + this.getHeight();
decr = batteryLevel / 20;
}else{
g.setColor(Color.RED);
g.fillRect(1, 0, this.getWidth(), this.getHeight());
g.setColor(Color.GREEN);
g.fillRect(1, 0, this.getWidth(), batteryLevel);
g.setColor(Color.BLACK);
g.setFont(f);
g.drawString("TEST", (getWidth() - m.stringWidth("TEST")) / 2 , this.getHeight() / 2);
}
}
public void decreaseBatteryLevel(){
batteryLevel -= decr;
this.repaint();
}
PS. Sorry if I did something wrong, I'm new to this forum.
As you want the visible battery level to descend you will want to increase your Y co-ordinate in relation to the value of batteryLevel. You could use:
g.fillRect(1, getHeight() - batteryLevel, getWidth(), batteryLevel);
Instead
g.fillRect(1, 0, this.getWidth(), batteryLevel);
Do
g.fillRect(1, batteryLevel, this.getWidth(), getHeight() - batteryLevel);
Also maybe repaint(50L) instead of repaint().
If your question meant: how to animate a change in the battery level.
Use a javax.swing.Timer:
int toPaintBatteryLevel = batteryLevel;
// In the paintComponent paint upto toPaintBatteryLevel.
Timer timer = new Timer(100, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (toPaintBatteryLevl == batteryLevel) {
return;
}
if (toPaintBatteryLevl > batteryLevel) {
--toPaintBatteryLevel; // Animate slowly
} else {
toPaintBatteryLevel = batteryLevel; // Change immediately
}
repaint(50L);
};
});
timer.start();
For ease of coding, there is a permanent timer. And externally one changes the batteryLevel,
and the time determines the toPaintBatteryLevel, which paintComponent uses to paint.