Image not rendering (JAVA) - java

So, today I decided to try to make my own game without using a tutorial, and if I have a problem, try to figure it out on my own. However, this problem is something that I don't understand.
Here is my code:
Game class (where the image is supposed to be rendered):
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
private int width = 350;
private int height = 200;
private int scale = 3;
private Dimension size = new Dimension(width * scale, height * scale);
private Thread thread;
private boolean running = false;
private BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
private Loader loader;
public Game() {
JFrame frame = new JFrame("Game");
frame.setPreferredSize(size);
frame.setMaximumSize(size);
frame.setMinimumSize(size);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(this);
frame.setVisible(true);
loader = new Loader();
}
public static void main(String[] args) {
Game game = new Game();
game.start();
new Images();
}
public void render() {
BufferStrategy bs = super.getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.drawImage(Images.TEST, 10, 10, null);
g.dispose();
bs.show();
}
public synchronized void start() {
if (running)
return;
else
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
if (!running)
return;
else
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void run() {
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getScale() {
return scale;
}
}
Loader class (where I load the image):
public class Loader {
public BufferedImage loadImage(String fileName) {
try {
System.out.println("Trying to load: " + fileName + " ... succeded!");
return ImageIO.read(new File(fileName));
} catch(Exception e) {
e.printStackTrace();
}
System.out.println("Trying to load: " + fileName + " ... failed!");
return null;
}
}
And my images class, where all of the images get set to a file:
public class Images {
public static Loader loader;
public static final BufferedImage TEST;
static {
Loader loader = new Loader();
TEST = loader.loadImage("res/test.png");
}
}
All I want to do, is simple display an image to the screen, yet this method does not seem to work. I do not know what I am doing wrong.
And, no I haven't put in the wrong directory of the image.
Thanks in advance!

Since run is empty, nothing is performing an update/paint cycle. Start by updating the run method to perform call render...
#Override
public void run() {
while (running) {
render();
}
}
The point of BufferStrategy is to take control of the painting process, so you now become responsible for performing it
Next, get rid of getWidth and getHeight, this is going to cause no end of issues and I wasted time trying to figure out why it wasn't displaying my full image.
The following...
frame.setPreferredSize(size);
frame.setMaximumSize(size);
frame.setMinimumSize(size);
is a bad idea, as the frame includes the window decorations, so your available content size will be reduced by the size of the windows decorations, which you are probably no expecting.
Instead, replace it with...
#Override
public Dimension getPreferredSize() {
return size;
}
and the call pack on the window to pack the window decorations around your desired content size.
Don't get me started on frame.setResizable(false);
TEST = loader.loadImage("res/test.png"); worries me. If res/test.png is embedded within your application Jar then the loading process will fail. If it's externalised to the disk, then you are going to have issues with loading the images if the working directory is not the same as the installation directory - just be warned

Related

Major confusion about Graphics in Java

I'm new to Java and OOP programming in general so if you guys could give me dumbed down explanation I would appreciate it. I don't really understand how the Graphics object and paintComponent work in general.
The basic idea of the Simulation class is that it will do the following.
1) Create a JFrame for my animation to take place in.
2) Create a Panel (I tried using a Canvas but people told me not to do that) which fits inside my JFrame, the animation will we painted to this panel.
3) Depending on the value of 'type' (and maybe some other conditions which I have not yet coded) it will set up and paint (to the Panel) the background picture (the graphics) for the corresponding Animation.
4) After painting the background image I wan't to be able to return it to Simulation class and modify it (the background Image) in a Loop with my Simulation running on a thread (therefore creating an animation).
5) After the animation is finished I want the Simulation JFrame to close (I'm not even close to getting to this part though).
Everything I see on here just tells me to create the class InitSimGraphics and have paintComponent method within it. I want to be able to paint my lines/rectangles ect.. onto the Panel and then go on to use it again where I can modify parts of it (aka make a particle move through the screen).
What I am doing right now is clearly not working and I am really really new to this so please try to go easy on me. A different approach is probably best I think since this isn't working.
Thanks!
package comp4Pack;
import javax.swing.*;
import java.awt.*;
public class Simulation implements Runnable {
private final int pwidth = 768, pheight = 432;
private int type;
private JFrame frame;
private JPanel panel;
private boolean running = false;
private Thread thread;
/* Type means the following
*
* 0 - Kinematics
* 1 - Dynamics (Momentum)
* 2 - Vectors
* 3 - ...
*
*/
public Simulation(int type){
this.type = type;
initSimulation();
InitSimGraphics i = new InitSimGraphics();
panel.add(i);
}
private void initSimulation(){
if(type == 0){
frame = new JFrame("Kinematics Simulation");
} else if(type == 1){
frame = new JFrame("Dynamics Simulation");
} else {
frame = new JFrame("Vectors Simulation");
}
frame.setSize(pwidth, pheight);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
panel = new JPanel(new BorderLayout());
panel.setPreferredSize(new Dimension(pwidth, pheight));
panel.setMaximumSize(new Dimension(pwidth, pheight));
panel.setMinimumSize(new Dimension(pwidth, pheight));
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
private void initGraphics(){
}
public void run() {
while(running){
tick();
render();
}
stop();
}
private void tick(){
}
private void render(){
}
public synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop(){
if(!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
..
package comp4Pack;
import javax.swing.*;
import java.awt.*;
public class InitSimGraphics extends JPanel {
Graphics g;
private final int pwidth = 768, pheight = 432;
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawLine(0, 0, pwidth, pheight);
this.g = g;
}
public Graphics getGraphics(){
return g;
}
}

How do I correctly set up canvas capable on running a simulation

I'm brand new to Java and have only recently learnt about object oriented programming. I'm trying to create a program which can run a simulation, the general idea is that I want a part of the screen dedicated to buttons/sliders and another part to be dedicated the the Canvas running the simulation. For now I'm not worried about the simulation itself, I'm just trying to get some graphics on the canvas (which is smaller than the JFrame).
Here is my code (I'll try to leave some explanation below it)
public class Launcher {
public static void main(String[] args){
Display display = new Display();
}
}
.
import java.awt.*;
import javax.swing.*;
public class Display {
public final int width = 1280, height = 720;
public final int cwidth = 894, cheight = 504;
public final String title = "Mechancis Simulator";
private JFrame frame;
//private JPanel panel;
private Canvas canvas;
private Simulation simulation;
public Display(){
initDisplay();
simulation = new Simulation();
}
private void initDisplay(){
frame = new JFrame(title);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
/*panel = new JPanel();
panel.setSize(width, height);
panel.setLocation(0,0); */
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(cwidth, cheight));
canvas.setMaximumSize(new Dimension(cwidth, cheight));
canvas.setMinimumSize(new Dimension(cwidth, cheight));
canvas.setLocation(width - (cwidth +15), 15);
//panel.add(canvas);
frame.add(canvas);
/* Add code for buttons/sliders/boxes here */
/* Add these to panel */
}
public JFrame getFrame(){
return frame;
}
public Canvas getCanvas(){
return canvas;
}
}
.
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.*;
import javax.swing.*;
public class Simulation extends Display implements Runnable {
private boolean running = false;
private Thread thread;
private BufferStrategy bs;
private Graphics g;
public Simulation(){
}
private void init(){
}
private void tick(){
}
private void render(){
bs = getCanvas().getBufferStrategy();
if(bs == null){
getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Draw Here!
//End Drawing!
bs.show();
g.dispose();
}
public void run(){
init();
while(running){
tick();
render();
}
stop();
}
public synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop(){
if(!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
When I run the program the window starts going crazy. I'm quite new to classes and threading so maybe that is the problem. I just want to be able to run the simulation after setting up Frame and Canvas in the Display object.
Thanks.
What you're doing basically is this:
class Display {
private final Simulation sim;
public Display() { sim = new Simulation(); }
}
class Simulation extends Display {
public Simulation() { }
}
when you create a new Display the constructor creates a new Simulation which is a Display which creates a new Simulation which is a Display which creates a new Simulation which is a Display which creates a new Simulation...*
So don't. There's no reason for your Simulation to be a display and to own another Simulation. If you want all the control in Display define a constructor that takes as an argument the Simulation it's displaying and give it a simulation when you create it:
class Display {
private final Simulation sim;
public Display(Simulation sim) { this.sim = sim; }
}
class Simulation {
}
...
Display display = new Display(new Simulation());
*I suggest you google for a tutorial on inheritance, if you wish to know more. Here's the tutorial from oracle to get you started: "You can write a subclass constructor that invokes the constructor of the superclass, either implicitly or by using the keyword super." In your code example the constructor super() is invoked implicitly.

Java Lang nullpointer exception in animation example?

import java.awt.*;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class Images extends JFrame {
public static void main(String[] args) {
DisplayMode dm = new DisplayMode(800,600,32, DisplayMode.REFRESH_RATE_UNKNOWN);
Images I = new Images();
I.run(dm);
}
private Screen s;
private Image bg;
private Image pic;
private boolean nLoaded;
Animation a;
public void run(DisplayMode dm)
{
nLoaded = false;
s = new Screen();
try{
s.Setfullscreen(dm, this);
LoadPics();
MovieLoop();
try{
Thread.sleep(50000);
}catch(Exception ex){}
}finally{
s.restoreScreen();
}
}
public void MovieLoop(){
long startingtime = System.currentTimeMillis();
long cumTime = startingtime;
while(cumTime-startingtime < 5000)
{
long timepassed = System.currentTimeMillis() - cumTime;
cumTime += timepassed;
a.update(timepassed);
Graphics g = s.getFullScreenWindow().getGraphics();
draw(g);
g.dispose();
try{
Thread.sleep(20);
}catch(Exception ex){}
}
}
public void draw(Graphics g)
{
g.drawImage(bg, 0,0, null);
g.drawImage(a.getImage(),0,0,null); }
//Create Load Pictures
public void LoadPics()
{
bg = new ImageIcon("C:\\Gamepics\\BackgroundImage.jpg").getImage();
pic = new ImageIcon("C:\\Gamepics\\SmileyIcon3.png").getImage();
nLoaded = true;
repaint();
}
public void paint(Graphics g){
if(g instanceof Graphics2D){
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
if(nLoaded)
{
g.drawImage(bg, 0, 0, null);
g.drawImage(pic, 300,300, null);
}
}
}
Im not understanding what I did wrong ive overlooked everything the best I can. Im just practicing a simple animation and I keep getting 3 null pointer exceptions.
Ive researched the best I can and apparently NullPointerExceptions in java have to do with trying to get the size of null arrays? The compiler hasn't marked any of my lists as problems so im a little confused. Any help would be greatly appreciated. All of the errors are commented out. There are three of them and they are in the Images class
Errors:
Exception in thread "main" java.lang.NullPointerException
at Images.MovieLoop(Images.java:45)
at Images.run(Images.java:26)
at Images.main(Images.java:8)
Animation Class
import java.awt.Image;
import java.util.*;
public class Animation {
private ArrayList scenes;
private int sceneindex;
private long movietime;
private long totaltime;
//CONSTRUCTOR
public Animation(){
scenes = new ArrayList();
totaltime =0;
start();
}
//Add scene to array list and sets time for each scene
//For example. If you have 3 scenes you would add t to total time three times. So if you had
//3 Scenes, one for 1s, one for 2s, one for 3s. Total time would be 6s. and you would call addscene 3 times
public synchronized void addScene(Image i, long t)
{
totaltime+=t;
scenes.add(new OneScene(i, totaltime));
}
//start animation from beggininign inignngingingnig
public synchronized void start(){
movietime = 0;
sceneindex = 0;
}
//change scenes
//movie time is the sum of all the time passed from last update
//If you have more than one scene. timepassed gets added to movietime.
//if movietime is greater than or equal to total time(ie. animation is complete) restart the animation
public synchronized void update(long timepassed)
{
if(scenes.size() > 1){
movietime += timepassed;
if(movietime >= totaltime)
{
movietime = 0;
sceneindex = 0;
}
while(movietime > getScene(sceneindex).endTime)
{
sceneindex++;
}
}
}
public synchronized Image getImage(){
if(scenes.size() == 0){
return null;}
else{
return getScene(sceneindex).pic;
}
}
//Getscene
private OneScene getScene(int x){
return (OneScene)scenes.get(x);
}
//Scenes are gonna be
private class OneScene{
Image pic;
long endTime;
public OneScene(Image pic, long endTime)
{
this.pic = pic;
this.endTime = endTime;
}
}
}
I included the animation class because the compiler is highlighting these three method calls as the source of the problem
a.update(timepassed);
MovieLoop();
I.run(dm);
Please Note: This is a really long comment
Let's start with Graphics g = s.getFullScreenWindow().getGraphics(); - getGraphics is NEVER a good idea, this can return null.
You should NEVER try and update any UI component from any thread other the EDT and you should NEVER draw directly to it in this manner, instead, you should be using paintComponent.
You should NEVER dispose of any Graphics context that you did not create yourself, this will prevent other components from been painted.
You should avoid overriding paint, especially of a top level container, if for no other reason, it's not double buffered (the top level container), and you will also be painting over any other child components.
Check out Performing Custom Painting for more details.
You should try using ImageIO instead of ImageIcon. ImageIO will throw exceptions if it can't read the file, where as ImageIcon simply fails silently, no very helpful.

AnimatedGIFField from blackberry knowledge base, don't know how to manipulate the gif

I am using this code, if anybody is familiar with it, its from the blackberry knowledge base. Anyway, I was wondering how to manipulate GIF's using this class. I can get the gif on the screen, but it keeps repeating and will not disappear. Any help is greatly appreciated!
public class AnimatedGIFField extends BitmapField
{
private GIFEncodedImage _image; //The image to draw.
private int _currentFrame; //The current frame in
the animation sequence.
private int _width; //The width of the image
(background frame).
private int _height; //The height of the image
(background frame).
private AnimatorThread _animatorThread;
public AnimatedGIFField(GIFEncodedImage image)
{
this(image, 0);
}
public AnimatedGIFField(GIFEncodedImage image, long style)
{
//Call super to setup the field with the specified style.
//The image is passed in as well for the field to
//configure its required size.
super(image.getBitmap(), style);
//Store the image and it's dimensions.
_image = image;
_width = image.getWidth();
_height = image.getHeight();
//Start the animation thread.
_animatorThread = new AnimatorThread(this);
_animatorThread.start();
}
protected void paint(Graphics graphics)
{
//Call super.paint. This will draw the first background
//frame and handle any required focus drawing.
super.paint(graphics);
//Don't redraw the background if this is the first frame.
if (_currentFrame != 0)
{
//Draw the animation frame.
graphics.drawImage(_image.getFrameLeft(_currentFrame), _image.getFrameTop(_currentFrame),
_image.getFrameWidth(_currentFrame), _image.getFrameHeight(_currentFrame), _image, _currentFrame, 0, 0);
}
}
//Stop the animation thread when the screen the field is on is
//popped off of the display stack.
protected void onUndisplay()
{
_animatorThread.stop();
super.onUndisplay();
}
//A thread to handle the animation.
private class AnimatorThread extends Thread
{
private AnimatedGIFField _theField;
private boolean _keepGoing = true;
private int _totalFrames; //The total number of
frames in the image.
private int _loopCount; //The number of times the
animation has looped (completed).
private int _totalLoops; //The number of times the animation should loop (set in the image).
public AnimatorThread(AnimatedGIFField theField)
{
_theField = theField;
_totalFrames = _image.getFrameCount();
_totalLoops = _image.getIterations();
}
public synchronized void stop()
{
_keepGoing = false;
}
public void run()
{
while(_keepGoing)
{
//Invalidate the field so that it is redrawn.
UiApplication.getUiApplication().invokeAndWait(new Runnable()
{
public void run()
{
_theField.invalidate();
}
});
try
{
//Sleep for the current frame delay before
//the next frame is drawn.
sleep(_image.getFrameDelay(_currentFrame) * 10);
}
catch (InterruptedException iex)
{} //Couldn't sleep.
//Increment the frame.
++_currentFrame;
if (_currentFrame == _totalFrames)
{
//Reset back to frame 0 if we have reached the end.
_currentFrame = 0;
++_loopCount;
//Check if the animation should continue.
if (_loopCount == _totalLoops)
{
_keepGoing = false;
}
}
}
}
}
}
Don't call super.paint(graphics), rather draw everything you need to draw by yourself. re-write your paint(Graphics graphics) method like below:
private boolean isPaint = true;
protected void paint(Graphics graphics) {
if(!isPaint) return;
// super.paint(graphics);
if (_currentFrame == _image.getFrameCount()-1) {
graphics.setGlobalAlpha(0);
isPaint = false;
}
graphics.drawImage(
_image.getFrameLeft(_currentFrame),
_image.getFrameTop(_currentFrame),
_image.getFrameWidth(_currentFrame),
_image.getFrameHeight(_currentFrame), _image,
_currentFrame, 0, 0
);
}

Why is the paint() method not executing update() or paint() methods?

I'm having this problem where the paint() or update() methods in a class isn't getting called when I execute repaint(). Here's the code:
public class BufferedDisplay extends Canvas implements Runnable {
// Contains all the images in order, ordered from background to foreground
private ArrayList<ImageStruct> images;
// Tracks the last insert ID of the last image for a particular layer
private TreeMap<Integer, Integer> insertIDs;
// Image that holds the buffered Image
private Image offscreen;
public BufferedDisplay() {
images = new ArrayList<ImageStruct>();
insertIDs = new TreeMap<Integer, Integer>();
}
public void addImageStruct(ImageStruct is) {
int layer = is.getLayer();
// Index to insert the image at
int index = -1;
if(insertIDs.containsKey(layer)) {
index = insertIDs.get(layer)+1;
insertIDs.put(layer, index);
}
else {
index = images.size();
insertIDs.put(layer, index);
}
if(index>-1) {
images.add(index, is);
}
}
public void run() {
try
{
while(true)
{
System.out.print("\nSleeping... ");
System.out.print("ArraySize:"+images.size()+" ");
Thread.sleep(1000);
System.out.print("Slept. ");
repaint();
}
}
catch(Exception e)
{
System.out.println("Display Error: ");
e.printStackTrace();
System.exit(-1);
}
}
// Overrides method so the background isn't automatically cleared
public void update( Graphics g )
{
System.out.print("Updating... ");
paint(g);
}
public void paint( Graphics g )
{
System.out.print("Painting... ");
if(offscreen == null)
offscreen = createImage(getSize().width, getSize().height);
Graphics buffer = offscreen.getGraphics();
buffer.setClip(0,0,getSize().width, getSize().height);
g.setColor(Color.white);
paintImages(buffer);
g.drawImage(offscreen, 0, 0, null);
buffer.dispose();
}
public void paintImages( Graphics window )
{
for(ImageStruct i : images) {
i.draw(window);
}
}
}
This class is implemented in this:
public class Game extends JPanel{
// A reference to the C4Game class
private C4Game game;
// A reference to the BufferedDisplay class
private BufferedDisplay display;
// The Image used to initialize the game board
private Image tile;
private int tileSize = 75;
private int tileLayer = 5;
// Thread that controls animation for the BufferedDisplay
Thread animation;
public Game(C4Game game) {
this.game = game;
display = new BufferedDisplay();
try {
tile = ImageIO.read(new File("img\\tile.png"));
} catch (IOException e) {
System.out.println("ERROR: ");
e.printStackTrace();
}
((Component)display).setFocusable(true);
add(display);
animation = new Thread(display);
animation.start();
initBoard();
}
public void initBoard() {
for(int x = 0; x<game.numRows()*tileSize; x+=tileSize) {
for(int y = 0; y<game.numCols()*tileSize; y+=tileSize) {
System.out.println("Placing " +x +" " +y +"...");
display.addImageStruct(new ImageStruct(tile, tileLayer, x, y, tileSize, tileSize));
}
}
}
}
...Which is then implemented in a JFrame.
public class TetraConnect extends JFrame{
public TetraConnect() {
super("TetraConnect", 800, 600);
try {
setIconImage(Toolkit.getDefaultToolkit().createImage("img/icon.png"));
ms = new MainScreen(this);
add(ms);
ms.updateUI();
C4Game c4g = new C4Game(5,6);
Game g = new Game(c4g);
add(g);
g.updateUI();
}
catch(Exception e) {
System.out.println("Init. Error: ");
e.printStackTrace();
System.exit(-1);
}
}
The output when I run it, is:
Slept.
Sleeping... Slept.
Sleeping... Slept.
Sleeping... Slept.
And so forth. I'm also not able to see any images on the Canvas (I'm assuming they are never drawn in the first place). It seems to completely skip the repaint method; the debug statements "Updating... " and "Repainting... " never show up. However, repaint also seems to be executing; the loop repeats without problems. Why isn't the repaint method calling the paint() or update() methods?
As #camickr noted in the comments, you are using the heavyweight AWT canvas. You should really be using lightweight Swing components. Instead of:
public class BufferedDisplay extends Canvas implements Runnable {
I recommend:
public class BufferedDisplay extends JPanel implements Runnable {
Given that small change, I would then do the following:
When overriding the default paining of a component you should override the paintComponent() method.
So, instead of:
public void paint( Graphics g )
{
It should be:
protected void paintComponent( Graphics g )
{
That may fix your problem.
Also, you shouldn't have to override the update() method. Instead, just leave out a call to super.paintCompenent(g) in the paint component method. This should cause the background to be left alone by default.
Make sure that the BufferedDisplay object has been added to a container (e.g. a Frame), and that the container itself is visible. If the component is not showing, then calls to repaint() will not result in update() being called.
This is just generic advice. If you post a self-contained example that can be compiled and run it will probably be easier to find out what is wrong.

Categories