I am trying to use repaint in a timer task, but eclipse is telling me the method is undefined, and I don't know why. I believe I have all the proper imports. Below is just a small segment of my code.
import java.awt.Color;
import java.awt.Graphics;
import java.util.TimerTask;
import java.util.Timer;
import javax.swing.JPanel;
class task extends TimerTask
{
public void run()
{
repaint();
}
}
You're calling a method that has not been declared in the class it is held in, and so Java, not "Eclipse" is complaining, and rightfully so.
If you are trying to redraw a Swing GUI component intermittently using a timer then,
Use a Swing Timer, not a java.util.Timer, since the latter does not handle Swing threading properly.
Call repaint() on a Swing component, not on nothing as you're doing.
Most important, go through the Java and Java Swing tutorials, as it will explain all of this and more.
For example, try running this straight, and then try running it stoned. It's almost psychedelic:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyRepaint extends JPanel {
private static final Color COLOR_1 = Color.RED;
private static final Color COLOR_2 = Color.BLUE;
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int DELAY = 25;
private int x1 = 0;
private int y1 = 0;
private int x2 = 20;
private int y2 = 20;
Paint myPaint = new GradientPaint(x1, y1, COLOR_1, x2, y2, COLOR_2, true);
public MyRepaint() {
new Timer(DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
x1++;
y1++;
x2++;
y2++;
x1 %= PREF_W;
y1 %= PREF_H;
x2 %= PREF_W;
y2 %= PREF_H;
myPaint = new GradientPaint(x1, y1, COLOR_1, x2, y2, COLOR_2, true);
// the repaint method call below works because it is calling it on
// the current object of this class, which extends JPanel
// and thus has a repaint() method.
repaint();
}
}).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(myPaint);
g2.fillRect(0, 0, PREF_W, PREF_H);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
MyRepaint mainPanel = new MyRepaint();
JFrame frame = new JFrame("MyRepaint");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
so i am trying to make a program that will draw a line when you call the static void and it will send the coordinates of the line into an array to draw it in the panel class when i call it once it draws a line but when i call it twice it does not draw the first line only the second.
main class
package main;
import javax.swing.*;
public class VB {
public static int[] POS_x1;
public static int[] POS_y1;
public static int[] POS_x2;
public static int[] POS_y2;
public static int PosCount;
VB(){
}
public static void NewWindow(String Title, String LogoPath, int x, int y, int Width, int Height){
Panel panel = new Panel();
ImageIcon image = new ImageIcon(LogoPath);
JFrame frame = new JFrame();
frame.setIconImage(image.getImage());
frame.setTitle(Title);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(panel);
frame.setBounds(x, y, Width, Height);
frame.setResizable(false);
frame.setVisible(true);
}
public static void DrawLine(int x1, int y1, int x2, int y2) {
POS_x1 = new int[256];
POS_y1 = new int[256];
POS_x2 = new int[256];
POS_y2 = new int[256];
POS_x1[PosCount] = x1;
POS_y1[PosCount] = y1;
POS_x2[PosCount] = x2;
POS_y2[PosCount] = y2;
PosCount++;
System.out.println(PosCount);
}
public static void main(String[] args) {
VB.NewWindow("window", "res/img/saullularphone.PNG", 100, 100, 500, 500);
VB.DrawLine(0, 0, 100, 50);
VB.DrawLine(0, 50, 100, 50);
}
}
Panel class
package main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class Panel extends JPanel {
Panel(){
repaint();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (int pos = 0; pos < VB.PosCount; pos++) {
g2.setColor(Color.black);
g2.drawLine(VB.POS_x1[pos], VB.POS_y1[pos], VB.POS_x2[pos], VB.POS_y2[pos]);
}
}
}
i tried drawing the first line then redrawing then drawing the second line but it didn't work and drew the second line
You should not be using the static keyword anywhere but the static main method.
Here's a GUI that draws two lines. You can add additional lines if you wish.
I created a Swing model using plain Java getter/setter classes.
I created a LineSegment class to hold all the parameters to draw a line. I created a DrawingLinesModel class to hold a List of LineSegment instances. You can use an array, but a List is more flexible.
I created a JFrame and a drawing JPanel.
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the Performing Custom Painting section.
All Swing applications must start with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
Here's the complete runnable code. I made all the additional classes inner classes so I could post the code as one block.
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class DrawingLinesExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new DrawingLinesExample());
}
private final DrawingLinesModel model;
private final DrawingPanel drawingPanel;
public DrawingLinesExample() {
this.model = new DrawingLinesModel();
this.drawingPanel = new DrawingPanel(model);
}
#Override
public void run() {
JFrame frame = new JFrame("Drawing Lines");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private final DrawingLinesModel model;
public DrawingPanel(DrawingLinesModel model) {
this.model = model;
this.setPreferredSize(new Dimension(600, 640));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
for (LineSegment line : model.getLines()) {
g2d.setColor(line.getColor());
g2d.setStroke(new BasicStroke(line.getThickness()));
Point sp = line.getStartPoint();
Point ep = line.getEndPoint();
g2d.drawLine(sp.x, sp.y, ep.x, ep.y);
}
}
}
public class DrawingLinesModel {
private final List<LineSegment> lines;
public DrawingLinesModel() {
this.lines = new ArrayList<>();
this.lines.add(new LineSegment(new Point(10, 10),
new Point(400, 400), Color.BLUE, 9));
this.lines.add(new LineSegment(new Point(10, 400),
new Point(400, 10), Color.MAGENTA, 11));
}
public List<LineSegment> getLines() {
return lines;
}
}
public class LineSegment {
private final int thickness;
private final Color color;
private final Point startPoint, endPoint;
public LineSegment(Point startPoint, Point endPoint, Color color,
int thickness) {
this.startPoint = startPoint;
this.endPoint = endPoint;
this.color = color;
this.thickness = thickness;
}
public Point getStartPoint() {
return startPoint;
}
public Point getEndPoint() {
return endPoint;
}
public Color getColor() {
return color;
}
public int getThickness() {
return thickness;
}
}
}
I'm trying to make two blinking circles that blink at different rates. I'm using ScheduledExecutorService in the Circle class to regulate the blinking, and its duration is set by the ms (milliseconds) variable in each Circle.
When I make one car individually, they blink at the correct rates (I have the black one set to 1000ms, the red set to 10ms). However, when I create them both and add them to my JLayeredPane, they both blink at the shorter period.
I'm not too familiar with the use of ScheduledExecutorService, so if someone could help me out with what's going wrong it'd be greatly appreciated!
import java.awt.Color;
import java.awt.Graphics;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.awt.*;
import javax.swing.*;
public class blinker extends JFrame
{
JLayeredPane lp = new JLayeredPane();
public carlight()
{
lp.setLayout(new BorderLayout());
lp.setPreferredSize(new Dimension(450, 450));
car c1 = new car(new Color(0, 0, 0), "1", 10, 0, 0);
c1.setOpaque(false);
car c2 = new car(new Color(255, 0, 0), "2", 1000, 100, 100);
c2.setOpaque(false);
c1.setBounds(0, 0, 450, 450);
c2.setBounds(0, 0, 450, 450);
lp.add(c2);
lp.add(c1);
add(lp);
setTitle("Carlights");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 500);
setVisible(true);
}
public static void main(String[] args)
{
carlight cl = new carlight();
}
}
class Circle extends JPanel
{
private Color color;
private String name;
private long ms;
private int x, y;
private boolean on = true;
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
#Override
public void paintComponent(Graphics g)
{
super.paintComponents(g);
if(on)
{
g.setColor(color);
int r = 50;
g.fillOval(x, y, r, r);
on = false;
}
else
{
on = true;
}
}
public car(Color c, String s, long l, int x, int y)
{
color = c;
name = s;
ms = l;
this.x = x;
this.y = y;
this.service.scheduleAtFixedRate(new Runnable()
{
public void run()
{
repaint();
}
}, 0, ms, TimeUnit.MILLISECONDS);
}
}
Your problem is that you have program logic in the paintComponent method, where you change the state of the boolean variable. You don't have full control over when or even if this method will be called, and in fact both paintComponents will be called when repaint is called which is why your blinkers aren't working. The solution: get the logic out of the paintComponent method by changing the state of the boolean field, on, elsewhere. Also you'll want to use a Swing Timer for better Swing threading.
You also will want to fix your use of layouts including avoiding use of setBounds. This is especially dangerous and unpredictable in your setup, using it with a BorderLayout. Myself, I'd not make the Circle class extend a JPanel but rather make it a logical class, not a component class, and then I'd have the drawing component, a class that does extend JPanel, hold instances of Circle classes and then draws them in its paintComponent. For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class BlinkerEg extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = PREF_W;
private List<Circle> circles = new ArrayList<>();
public BlinkerEg() {
circles.add(new Circle(Color.red, 1000, 0, 0, 450, this));
circles.add(new Circle(Color.black, 60, 0, 0, 450, this));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Circle circle : circles) {
circle.paint(g2);
}
}
private static void createAndShowGui() {
BlinkerEg mainPanel = new BlinkerEg();
JFrame frame = new JFrame("BlinkerEg");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class Circle {
private Color color;
private int x, y;
private int diam;
private JComponent component;
private boolean on = true;
public Circle(Color color, int ms, int x, int y, int diam, JComponent component) {
this.color = color;
this.x = x;
this.y = y;
this.diam = diam;
this.component = component;
new Timer(ms, new TimerListener()).start();
}
public void paint(Graphics g) {
if (on) {
g.setColor(color);
g.fillOval(x, y, diam, diam);
}
}
public boolean isOn() {
return on;
}
public void setOn(boolean on) {
this.on = on;
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
setOn(!isOn());
component.repaint();
}
}
}
I want my button to change color on the mod == 0 of i % 3. The paintComponent(...) is called when the form is re-sized and index is passed in so I would think that this should change the color of my button ever time I start moving the form around the screen.
I have two components on the screen but both will not show up this might be a factor.
Code:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class testform {
public static void main (String[] p) {
testBall3 j1 = new testBall3();
myButton b1 = new myButton("test");
JPanel testPane = new JPanel();
testPane.setBackground(Color.green);
testPane.setLayout(new BorderLayout());
j1.setPreferredSize(new Dimension(10,10));
//testPane.add(b1);
testPane.add(j1);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(testPane);
frame.pack();
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//j1.setColorBall(Color.BLACK);
//j1.repaint();
}
}
class myButton extends JButton {
private static final long serialVersionUID = 1L;
public myButton(String s) {
super(s);
}
public void setPrefferedSize(Dimension d) {
//this.setBounds(x, y, width, height)
setPreferredSize(d);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
index += i;
System.out.println(i);
if (index % 3 == 0) {
setBackground(Color.RED);
}
else {
setBackground(Color.BLACK);
}
}
}
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
class testBall3 extends JComponent
{
private static final long serialVersionUID = 1L;
private Color colorBall = Color.red;
private int x1, y1;
int index = 0;
public void setColorBall(Color c)
{
this.colorBall = c;
}
public testBall3()
{
super();
System.out.println("MyBall (0)");
}
public testBall3(int x, int y, int diameter)
{
super();
this.setLocation(x, y);
this.setSize(diameter, diameter);
System.out.println("MyBall (1)");
x1 = x;
y1 = y;
}
public void paintBorder(Graphics g)
{
super.paintBorder(g);
g.setColor(Color.YELLOW);
g.fillOval(100, 100, 50, 50);
System.out.println("PaintBorder");
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(colorBall);
g.fillOval(x1, y1, 10, 10);
System.out.println("paintComponent");
}
public void paint(Graphics g)
{
super.paint(g);
paintComponent(g);
paintBorder(g);
paintChildren(g);
System.out.println("Paint");
}
}
But paintComponent doesn't take a second parameter, how are you passing it? I would think that instead of trying to pass i, you would want make i an attribute of class myButton instead and initialize it to 0 upon instantiation. That is, if you want each button to have its own counter. That sounds like the better plan.
You've got a lot of strange stuff going on...
You've got a component where you override all four major painting methods for no good reason.
In this component, your paint method override calls the super method, and calls the other 3 methods, which in essence will make those 3 methods be called twice.
You've got program logic (advancement of i) inside of your myButton's paintComponent method -- something that should never be done. You do not have full control over when or even if this method is called.
You are calling setBackground(...) from within paintComponent, something which shouldn't be done.
Your class names do not begin with an upper case letter, going against coding conventions, and potentially confusing anyone who tries to read your code.
If you want to change the state of a component on resize, use a ComponentListener.
e.g.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class Foo2 extends JPanel {
protected static final Color MAGIC_BACKGROUND = Color.red;
protected static final int MAGIC_NUMBER = 3;
private static final int TIMER_DELAY = 20;
private int index = 0;
private JButton myButton = new JButton("My Button");
protected int DELTA_SIZE = 2;
public Foo2() {
add(myButton);
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
index++;
if (index % MAGIC_NUMBER == 0) {
myButton.setBackground(MAGIC_BACKGROUND);
} else {
myButton.setBackground(null);
}
}
});
new Timer(TIMER_DELAY, new ActionListener() {
private Toolkit toolkit = Toolkit.getDefaultToolkit();
private int screenWidth = toolkit.getScreenSize().width;
private int screenHeight = toolkit.getScreenSize().height;
#Override
public void actionPerformed(ActionEvent e) {
if (getWidth() >= screenWidth || getHeight() >= screenHeight) {
((Timer)e.getSource()).stop();
} else {
int width = getWidth() + DELTA_SIZE;
int height = getHeight() + DELTA_SIZE;
setPreferredSize(new Dimension(width, height));
Window win = SwingUtilities.getWindowAncestor(Foo2.this);
win.pack();
win.setLocationRelativeTo(null);
}
}
}).start();
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Foo2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Foo2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I am trying to relocate a rectangle but for I cannot figure out why it stays in the same location.
It creates a red rectangle but does not change color or move to a new location.
Here is my code:
package grap_prj.dom.shenkar;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class graphic_main extends JPanel{
static Rectangle rec = new Rectangle ();
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
rec.setSize(10, 10);
rec.setLocation(10, 10);
g2d.setColor(Color.RED);
g2d.drawRect((int)rec.getX(),(int)rec.getY(), 10, 10);
g2d.fillRect((int)rec.getX(),(int)rec.getY(), 10, 10);
}
public static void update_ui (Graphics g)
{
System.out.println("in update");
rec.setLocation(50, 50);
Graphics2D g2d = (Graphics2D) g;
g2d.drawRect((int)rec.getX(),(int)rec.getY(), 10, 10);
g2d.fillRect((int)rec.getX(),(int)rec.getY(), 10, 10);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Simple Graphics");
frame.add(new graphic_main());
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
graphic_main.update_ui(frame.getGraphics());
frame.revalidate();
}
}
Update:
I have made a few changes in the code, but still the same situation. I change the location but a new rectangle is added instead of moving the existing one.
You are continuosly setting location at 10,10 so the rectangle will always be drawn at 10,10.
After setting location 50,50 you aren't drawing anything. Next step you will set 10,10 again.
Whenever you override paintComponent(), you need to call super.paintComponent().
You are also calling repaint() from repaint(). You need to decide on some action that will cause it to repaint.
You should never call update() or repaint() inside of a paintComponent(...) method. Ever. This risks recursion or ineffective uncontrolled animation.
Don't change the state of your object inside of a paint or paintComponent method. You don't have full control over when or even if these methods get called.
Don't forget to call the super's method inside your paintComponent override to allow the JPanel to do its housekeeping graphics including erasing old dirty pixels.
Even though you change the Graphics context's Color to blue, it will change right back to red anytime the paintComponent is called. So your color change is futile code. Solution: make the Color a variable that can be set.
If you want to do Swing animation, use a Swing Timer.
For an example of Swing animation, have a look at my example here.
For another example, have a look at this:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class SimpleAnimation extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private static final Color[] COLORS = { Color.red, Color.orange,
Color.yellow, Color.green, Color.blue, Color.magenta };
private static final int RECT_WIDTH = 40;
private static final int TIMER_DELAY = 10;
private int x = 0;
private int y = 0;
private int colorIndex = 0;
private Color color = COLORS[colorIndex];
public SimpleAnimation() {
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.fillRect(x, y, RECT_WIDTH, RECT_WIDTH);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
x++;
y++;
if (x + RECT_WIDTH > getWidth()) {
x = 0;
}
if (y + RECT_WIDTH > getHeight()) {
y = 0;
}
if (x % 40 == 0) {
colorIndex++;
colorIndex %= COLORS.length;
color = COLORS[colorIndex];
}
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SimpleAnimation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SimpleAnimation());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Your changing the location before the frame gets the chance to render it. So its creating it at 10, 10 and then when its rendered changes it to 50 50 then to 10, 10.
I looked and the codes seems fine to me. Got an error but hopefully it's the source code, not something wrong with the cpu I have nor JDK.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.*;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
public static int width = 300;
public static int height = width / 16*9;
public static int scale = 3;
private Thread thread;
private boolean running = false;
private JFrame frame;
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
running = false;
try{
thread.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void run(){
while(running){
tick();
render();
}
}
public void tick() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if(bs==null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
bs.dispose();
bs.show();
}
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Title");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Then I got this error, even when I countlessly modified the source code I had.
Exception in thread "Display" java.lang.NullPointerException
at java.awt.Component$BltBufferStrategy.showSubRegion(Component.java:4307)
at java.awt.Component$BltBufferStrategy.show(Component.java:4255)
at com.thecherno.Rain.Game.render(Game.java:58)
at com.thecherno.Rain.Game.run(Game.java:39)
at java.lang.Thread.run(Thread.java:695)
Im starting to seem if it because of an outdated JDK. Current Version I have is JDK 6.
You state:
What Im trying to do is change color as seen in the render method. The background to be black.
Use Swing components such as a JComponent or JPanel.
Simply call setBackground(Color.BLACK) on the component will do.
You appear to be creating a game loop of some type. Consider using a Swing Timer for this.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Game2 extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = PREF_W / 16 * 9;
private static final int SCALE = 3;
private static final Color BACKGROUND = Color.BLACK;
private static final int TIMER_DELAY = 20;
private Timer swingTimer;
public Game2() {
setBackground(BACKGROUND);
swingTimer = new Timer(TIMER_DELAY, new TimerListener());
swingTimer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// TODO: add any custom painting here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W * SCALE, PREF_H * SCALE);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// TODO add code that gets called in game loop
}
}
private static void createAndShowGui() {
Game2 mainPanel = new Game2();
JFrame frame = new JFrame("Game2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Note that this code is based on your stated requirements and what I'm guessing are other requirements based on your code. If there are further requirements not mentioned, please elaborate them for us.
Try using g.dispose(); followed by bs.show(); and then
g = (Graphics2D)bs.getDrawGraphics();. I know it looks weird, but you are emptying the canvas and then refilling it using your strategy. You may also need to do an initial check for g being null and initialize it before the first display loop.