trying to create a rectangle using paint but repaint method's not calling paint method.
even tried replacing paint with paintComponent, but still not working.
So what changes to make to make it work.
is there a problem with calling repaint method in run.
is there a problem with the instance.
trying to create a rectangle using paint but repaint method's not calling paint method.
even tried replacing paint with paintComponent, but still not working.
So what changes to make to make it work.
is there a problem with calling repaint method in run.
is there a problem with the instance.
package src;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
public class main extends JFrame implements Runnable{
private final int Height = 480;
private final int Width = 640;
Thread gameloop;
public static main instance = null;
private main(){
JFrame frame = new JFrame();
frame.setSize(this.Width,this.Height);
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static main getInstance(){
if (instance == null){
instance = new main();}
return instance;
}
private void start(){
gameloop = new Thread(this);
gameloop.start();
}
#Override
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(g2d.getBackground());
g2d.fillRect(0, 0, instance.Width, instance.Height);
g2d.setColor(Color.red);
g2d.fillRect(0, 0, 50, 50);
}
#Override
public void run() {
Thread current = Thread.currentThread();
while (gameloop == current){
try{
Thread.sleep(5);
}
catch (InterruptedException e){
e.printStackTrace();
}
repaint();
}
}
public static void main(String[] args){
main.getInstance();
main.getInstance().start();
}
}
The original problem was that you created a new JFrame in your constructor and then made that visible, instead of using the main instance you just created, so nothing in your main class was actually being displayed in your app, just a blank JFrame that does nothing. Also your run loop made no sense.
However, your code has a lot of other problems, both in logic and style. I'd advise you to just refactor everything. Here's a cleaner version that also solves your problem.
package src;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
public final class Main extends JFrame implements Runnable {
private volatile boolean running;
private Main(int width, int height) {
setSize(width, height);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void start() {
running = true;
new Thread(this).start();
}
private void stop() {
running = false;
}
#Override
public void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(g2d.getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(Color.red);
g2d.fillRect(0, 0, 50, 50);
}
#Override
public void run() {
while (running) {
try {
Thread.sleep(40);
}
catch (InterruptedException e){
e.printStackTrace();
}
repaint();
}
}
public static void main(String[] args) {
new Main(640, 480).start();
}
}
Related
I am using Graphics g to draw an image for my player and a map. Whenever the player moves I want to update the player image to the new location without updating the map image. How can I do this?
Thanks in advance for any replies!
Sorry about my messy code.
Main:
package Main;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Main {
public static JFrame frame;
static int size = 32;
static int width = size*20;
static int height = size*17;
static playerObj p = new playerObj(200,200);
static tileMap grid = new tileMap();
public static void main(String[] args) {
frame = new JFrame("Game");
frame.getContentPane().setPreferredSize(new Dimension(width-9, height-9));
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(new drawGraphics());
frame.setVisible(true);
}
}
drawGraphics:
package Main;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class drawGraphics extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
boolean running = true;
boolean renderMap = true;
playerObj p = Main.p;
int size = Main.size;
static int x = 0;
static int y = 0;
Thread thread = new Thread(this);
public drawGraphics() {
setFocusable(true);
addKeyListener(new controls());
start();
}
public void start() {
thread.start();
}
public void paint(Graphics g) {
Graphics2D d = (Graphics2D) g;
super.paintComponent(g);
if (renderMap) {
map(d);
}
player(g);
repaint();
}
public void player(Graphics g) {
try {
BufferedImage pImg = ImageIO.read(new File("images/player.png"));
g.drawImage(pImg, p.getX(), p.getY(), null);
} catch (IOException e) {
e.printStackTrace();
}
}
public void map(Graphics g) {
System.out.println("2dfsdf");
Graphics2D d = (Graphics2D) g;
for (int i = 0; i < tileMap.map.length; i++) {
for (int j = 0; j < tileMap.map[i].length; j++) {
d.setColor(tileMap.map[i][j].getC());
d.fillRect(tileMap.map[i][j].getX(), tileMap.map[i][j].getY(),
Main.size, Main.size);
if (tileMap.map[i][j].solid()) {
d.setColor(Color.BLACK);
d.drawRect(tileMap.map[i][j].getX(),
tileMap.map[i][j].getY(), Main.size, Main.size);
}
}
}
}
public void move() {
if (controls.up) {
controls.goUp();
y--;
repaint();
}
if (controls.down) {
controls.goDown();
y++;
repaint();
}
if (controls.left) {
controls.goLeft();
x--;
repaint();
}
if (controls.right) {
controls.goRight();
x++;
repaint();
}
if (controls.place) {
repaint();
}
}
public void run() {
while (running == true) {
move();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Don't draw directly in a JFrame but rather in a JPanel that is displayed within the JFrame.
If you're using Swing as your GUI library, then draw the background as a BufferedImage, and draw that first in your paintComponent method. Then draw your image sprite at whatever location needed next:
#Override // this is in a JPanel extended class
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, null);
}
if (spriteImg != null) {
g.drawImage(spriteImg, spriteX, spriteY, null);
}
}
Some issues with your code:
Don't override paint and then call super.paintComponent inside of it.
Instead override paintComponent and call the same super method inside.
Never call repaint() inside of paint or paintComponent. Use a Swing Timer instead.
In your player(...) method, you re-read the image in each time the method is called, something that will slow your painting down to a crawl. Don't do this, but instead read the image in once, and save it to a variable.
I am making a game by java and it refreshes itself 60 times per second. Every time it executes a loop and I use g2d to draw images and strings. Things work fine if I do g2d.setFont(new Font("Arial", Font.PLAIN, 8)); and drawstring and it would be normal, but if I set the font to some "unfamiliar" fonts and do the same thing, the swing would show white screen in the first second of start up then paint everything correctly and it's apparently too slow (2 secs).
I put a jpanel in a jframe and override the paint() method of jpanel to draw everything I need. I've already used SwingUtilities.invokeLater in my code.
import javax.swing.*;
import java.awt.*;
public class Window extends JFrame{
public Window(){
add(new Board());
setSize(800,600);
setVisible(true);
}
public static void main(String[] args){
new Window();
}
private class Board extends JPanel {
Font font = new Font("Bitmap", Font.PLAIN, 64);
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setFont(font);
g2d.drawString("This is slow", 220,200);
Toolkit.getDefaultToolkit().sync();
g2d.dispose();
g.dispose();
}
}
}
This is not in a loop but it's very laggy.
http://fontsov.com/download-fonts/bitmap1159.html
This is the cutie font that slows our application down. "Arial" will load blazingly fast. How can I make this less laggy?
First and foremost, for best help, create and post your minimal code example program for us to review, test, and possibly fix. Without this, it will be hard for us to fully understand your problem.
Consider:
Overriding paintComponent not paint to get the advantage of double buffering.
Avoid using invokeLater unless you're sure that the code is being called off of the Swing event thread and you are making calls that need to be on the event thread.
Put slow running code in a background thread such as that which can be found using a SwingWorker.
Putting your text in a JLabel, not drawn on a component.
Draw all static images to a BufferedImage, and displaying that in paintComponent. Then draw all changing images, such as your moving sprites, directly in the paintComponent method.
Don't forget to call your super.paintCompmonent(g) within your paintComponent(Graphics g) method override.
Edit
A BufferedImage solution could look like,....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
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();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); //do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
paintGame(g2d);
// Toolkit.getDefaultToolkit().sync();
// g2d.dispose();
// g.dispose();
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
mainImage = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = mainImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
}
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
Edit 2
Or with a SwingWorker background thread....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
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();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); // do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
paintGame(g2d);
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
imgWorker.addPropertyChangeListener(new ImgWorkerListener());
imgWorker.execute();
}
private class ImgWorkerListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
try {
mainImage = imgWorker.get();
// repaint() here if you don't have a game loop running
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
SwingWorker<BufferedImage, Void> imgWorker = new SwingWorker<BufferedImage, Void>() {
#Override
protected BufferedImage doInBackground() throws Exception {
BufferedImage img = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
return img;
}
};
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
it's a bit uneconomic to create a new Font each time paint() is called (which happens a lot), you could move that to your constructor.
and the font should be changed to some orthodox fonts (Arial,Calibri etc)
This is the smallest SSCCE,of my project, that I could implement to show you.
Can anyone explain why the square, that I create into Render, is not shown?
I APPRECIATE ANY HELP, IT IS VERY IMPORTANT
this code is compilable,and it runs,but as i said it don't show the square.
Loop Class
public class Foo {
public void update() {
for (int i = 0; i < 20; i++)
System.out.println("foo");
}
}
Render Class
import java.awt.Graphics2D;
public class Render {
private static Render renderManager = new Render();
public void setRenderState(Graphics2D graphic) {
showRender(graphic);
}
private void showRender(Graphics2D graphic) {
graphic.fillRect(4, 3, 40, 40);
}
public static Render getRenderManagerInstance() {
return renderManager;
}
}
Main class
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class Main {
private static final Main mainFrame = new Main();
private final JFrame frame;
private Main() {
frame = new JFrame();
frame.setUndecorated(true);
frame.add(new MyPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static Main getMainFrameInstance() {
return mainFrame;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Main.getMainFrameInstance();
}
});
}
}
MyPanel Class
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class MyPanel extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
// thread and loop
private Thread thread;
private boolean running;
private int FPS = 60;
private long targetTime = 1000 / FPS;
private long start;
private long elapsed;
private long wait;
// image
public BufferedImage image;
// foo
private Foo foo;
private Render render = Render.getRenderManagerInstance();
public MyPanel() {
setPreferredSize(new Dimension(700, 700));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
// prevent to be done all method.
private synchronized void initGraphic() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
foo = new Foo();
running = true;
}
public void run() {
initGraphic();
// loop
while (running) {
start = System.nanoTime();
foo.update();
repaint();
elapsed = System.nanoTime() - start;
wait = (targetTime - elapsed / 1000000) - 8;
if (wait <= 0)
wait = 6;
try {
Thread.sleep(wait);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics = (Graphics2D) image.getGraphics();
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
render.setRenderState((Graphics2D) graphics);
}
Two problems:
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Check the values of WIDTH and HEIGHT at this point. I don't think they are what you expect. Presumably this is getting called before the component is realized.
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics = image.getGraphics();
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
render.setRenderState((Graphics2D) graphics);
}
You are drawing into the image, but you are never drawing the image itself on to the component. Keep a reference to the original component's Graphics object and then, at the end, paint the image with that on to the component.
public void paintComponent(Graphics panelG2d) {
super.paintComponent(panelG2d);
Graphics2D imageG2d = (Graphics2D) image.getGraphics();
imageG2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
imageG2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
render.setRenderState(imageG2d);
panelG2d.drawImage(image, 0, 0, this);
}
You don't add image to the MyPanel. You need to add it. In initGraphic do something like the following:
private synchronized void initGraphic() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
this.add(image); //New.
foo = new Foo();
running = true;
}
so I went on and started creationg game as usual. Except this time I got an error O.o. I was trying to find an answer, but non of the ones I thought maybe here I can get a good Answer! Heres the error:
Description Resource Path Location Type
Cannot make a static reference to the non-static field image Game.java /POGA/src/packagehere line 71 Java Problem
Description Resource Path Location Type
Cannot make a static reference to the non-static method createBufferStrategy(int) from the type Canvas Game.java /POGA/src/packagehere line 66 Java Problem
I get more of these type, but I guess If you show me and viewers of this question how to fix these errors we would be able to fix the rest of the "same" ones...
package packagehere;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
public static boolean running = false;
JFrame frame;
public static String title = "POGA game thingy - 0.1 Aplha";
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
public static final Dimension gameDim = new Dimension(WIDTH, HEIGHT);
synchronized void start() {
Thread thread = new Thread();
thread.start();
running = true;
}
public void run() {
while(running) {
tick();
render();
}
}
synchronized void stop() {
running = false;
System.exit(0);
}
public Game() {
setMaximumSize(gameDim);
setMinimumSize(gameDim);
setPreferredSize(gameDim);
frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
frame.requestFocus();
}
public static void tick() {
}
public static void render() {
BufferStrategy bs = getBufferStrategy();
if(bs == null) {
bs = createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.dispose();
bs.show();
}
}
The problem is at below line
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
Second on what object are you calling getWidth() and getHeight() methods?
I think you want to get the width and height of Canvas.
To solve this issue remove static from render() method.
Where are getBufferStrategy() and createBufferStrategy() declared?
(Answer: In the type Canvas which you are extending)
They are NON-Static methods, you cannot access them from within your render() method, because that method is static.
You can access Static methods from within Static and non-Static methods.
You can access non-static methods from non-static methods only.
I've been trying to fix but it never changes the screen. I'm trying to used the Graphics as seen in the render() method. Tell me if something is wrong inside the render method so I can relax, because I can't seem to find the problem.
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 {
private static final long serialVersionUID = 1L;
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() {
thread = new Thread();
thread.start();
running = true;
}
public synchronized void stop() {
running = false;
try{
thread.join();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public void run() {
while(running) {
tick();
render();
}
}
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 static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Rain");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Let me give you a stack trace of your error.
Your render method is not even being called here.
This is because your run method is not being called at all.
The reason behind all this is that you have not passed correct Runnable object at the time of Thread creation. It creates a Thread with empty run.
In your start method, just replace
thread = new Thread();
with
thread = new Thread(this);
And it should work.
Hope this helps. Enjoy.