'New Java awt project just shows grey screen?

So I started making a little Java awt application. I've done this a few times before because it's easy but for some reason nothing is rendering on this one. Below is a little demo project (literally 2 files) which should draw a turquoise square and it literally just doesn't, nothing, no errors, just grey screen. Was wondering if anyone had any ideas what could be going wrong here:

package application;


import java.awt.*;
import java.awt.image.BufferStrategy;
import java.util.Random;

public class Application extends Canvas implements Runnable{
    public static final boolean CHECK_ERRORS = true;

    
    //--------------------running stuff---------------------------------
    private Thread thread;
    private boolean running = false;

    public static final int WIDTH=1100, HEIGHT=700, SCALE = 1;

    //--------------------------init------------------------------------
    public Application(){
        new Window(this);
    }

    //-----------------------start and stop-----------------------------
    public synchronized void start(){
        running= true;
        thread = new Thread(this);
        thread.start();
    }
    public synchronized void stop(){
        try{
            thread.join();
            running=false;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //---------------------------run------------------------------------
    public void run(){
        long timer = System.currentTimeMillis();
        int frames = 0;

        while(running){
            BufferStrategy bs = this.getBufferStrategy();
            if (bs==null){
                this.createBufferStrategy(3);
                return;
            }
            Graphics g = bs.getDrawGraphics();
            g.setColor(new Color(59,230,153));
            g.fillRect(100, 100, SCALE,SCALE);

            g.dispose();
            bs.show();
            frames++;

            if (System.currentTimeMillis()-timer>1000){
                timer+=1000;
                System.out.println("FPS: "+frames);
                frames=0;
            }
        }
    }

    public static void main(String[] args){
        new Application();
    }
}

and the other file in the base package:

package application;

import java.awt.Canvas;
import java.awt.Dimension;
import javax.swing.JFrame;

public class Window extends Canvas{
    private static final long serialVersionUID=240840600533728354L;
    public static final Dimension DIMENSION = new Dimension(Application.WIDTH,Application.HEIGHT);
    public static final String TITLE = "world gen!";

    public Window ( Application game){
        //frame and resizability
        JFrame frame = new JFrame(TITLE);
        frame.setPreferredSize(DIMENSION);
        frame.setMaximumSize(DIMENSION);
        frame.setMinimumSize(DIMENSION);

        //frame and resizability
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.add(game);
        frame.setVisible(true);

        game.start();
    }
}


Solution 1:[1]

There are two immediate issues which stand out...

One...

BufferStrategy bs = this.getBufferStrategy();
if (bs==null){
    this.createBufferStrategy(3);
    return;
}

First, you should call createBufferStrategy before calling getBufferStrategy and second, the return statement will exit the current method.

Two

g.fillRect(100, 100, SCALE,SCALE);

is drawing a rectangle of 1 pixel in size, good luck finding that.

In addition

public synchronized void stop(){
    try{
        thread.join();
        running=false;
    } catch (Exception e) {
        e.printStackTrace();
    }
}

isn't going to work. Since join is blocking, running=false will never be executed and the thread will never stop. running should also be volatile.

Having Application and Window extend from Canvas makes no sense. There is already a Window class in the AWT framework, so I'd be hesitant to re-use that name. Instead, simply start with the Game canvas and add it to what ever window instance you've created.

You should be VERY wary of "wild loops" (like the one you're using for your main rendering loop), as they can consume CPU cycles (running it hot). Unless you have a super screen that is running at 1000+hz, you're just wasting rendering cycles.


The BufferStrategy JavaDocs has an excellent example of how you should be using it.

Runnable example

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;

public class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
                // You could look up all the avaliable screen devices, but this is just 
                // an example.
                GraphicsDevice gd = ge.getDefaultScreenDevice();
                int refreshRate = gd.getDisplayMode().getRefreshRate();
                int frameRate = 1000 / 60;

                Application application = new Application(frameRate);
                JFrame frame = new JFrame();
                frame.add(application);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                application.start();
            }
        });
    }

    public class Application extends Canvas implements Runnable {
        public static final boolean CHECK_ERRORS = true;

        //--------------------running stuff---------------------------------
        private Thread thread;
        private volatile boolean running = false;

        public static final int WIDTH = 1100, HEIGHT = 700, SCALE = 1;

        private final int frameRate;

        //--------------------------init------------------------------------
        public Application(int frameRate) {
            this.frameRate = frameRate;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(WIDTH, HEIGHT);
        }

        //-----------------------start and stop-----------------------------
        public synchronized void start() {
            running = true;
            thread = new Thread(this);
            thread.start();
        }

        public synchronized void stop() {
            try {
                running = false;
                thread.join();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //---------------------------run------------------------------------
        public void run() {
            long timer = System.currentTimeMillis();
            int frames = 0;

            System.out.println("running = " + running);

            createBufferStrategy(3);

            while (running) {
                BufferStrategy bs = getBufferStrategy();
                while (bs == null) {
                    bs = getBufferStrategy();
                }
                do {
                    // The following loop ensures that the contents of the drawing buffer
                    // are consistent in case the underlying surface was recreated
                    do {
                        // Get a new graphics context every time through the loop
                        // to make sure the strategy is validated
                        Graphics graphics = bs.getDrawGraphics();

                        // Render to graphics
                        // ...
                        graphics.setColor(Color.RED);
                        graphics.fillRect(0, 0, 100, 100);
                        // Dispose the graphics
                        graphics.dispose();

                        // Repeat the rendering if the drawing buffer contents
                        // were restored
                    } while (bs.contentsRestored());
                    // Display the buffer
                    bs.show();
                    frames++;

                    if (System.currentTimeMillis() - timer > 1000) {
                        timer += 1000;
                        System.out.println("FPS: " + frames);
                        frames = 0;
                    }

                    // Repeat the rendering if the drawing buffer was lost
                } while (bs.contentsLost());
                try {
                    Thread.sleep(frameRate);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }

        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MadProgrammer