0

I'm trying to make my own progress bar, on my splash screen. Creating my splash screen was easy:

java -splash:EaseMailMain.jpg Main.class (From Eclipse)

The first line of my main method calls this:

new Thread(new Splash()).start();

And this is the splash class:

    public class Splash implements Runnable {
    public volatile static int percent = 0;
    @Override
    public void run() {
        System.out.println("Start");
        final SplashScreen splash = SplashScreen.getSplashScreen();
        if (splash == null) {
            System.out.println("SplashScreen.getSplashScreen() returned null");
            return;
        }
        Graphics2D g = splash.createGraphics();
        if (g == null) {
            System.out.println("g is null");
            return;
        }
        int height = splash.getSize().height;
        int width = splash.getSize().width;
        //g.drawOval(0, 0, 100, 100);
        g.setColor(Color.white);
        g.drawRect(0, height-50, width, 50);
        g.setColor(Color.BLACK);
        while(percent <= 100) {
            System.out.println((width*percent)/100);
            g.drawRect(0, height-50, (int)((width*percent)/100), 50);
            percent += 1;
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

I don't get any errors, but I do get a small box underneath it:

The image with a rectangle below.

If I change the drawRects to (0, 0, width, height) it makes no difference.

I've tried invoking on the swing EDT with:

SwingUtilities.invokeAndWait((new Splash()));

But nothing happens.

Can anyone see the problem? Or know how to fix it?

Adude11
  • 605
  • 5
  • 16

2 Answers2

4

You should use SwingUtilities.invokeLater or SwingUtilities.invokeAndWait when updating the GUI from a different thread.

Please see the Chapter Concurrency in Swing which explains the reasons behind this.

The SplashScreen Example from the Tutorial does the Thread.sleep inside the Swing thread. This is fine, too if you do not need any other GUI refresh while the SplashScreen is showing. Your loading code however should happen in a different thread.

I would recommend adding a setPercent setter to your class which creates a Runnable to update the GUI via SwingUtilities.invokeLater. That way you do not even need to poll the percent variable and the SwingThread is free to render other UI stuff, too.

bikeshedder
  • 7,337
  • 1
  • 23
  • 29
  • Oh forgot to add that bit, I'd already tested that, it makes no difference. – Adude11 Feb 10 '13 at 21:40
  • 1
    @Adude11 From you example code, no you didn't, or at least, no you didn't do it right...I've extended on bikeshedder's recommendations (+1) and tried to expand on the reasons why you're having trouble. If you find it useful, I would appropriate a up-vote, but you should give credit to bikeshedder for identifying the problem (an mark their answer as correct). – MadProgrammer Feb 10 '13 at 23:38
3

Bikeshedder is right (+1), you're blocking the EDT.

while(percent <= 100) {
    System.out.println((width*percent)/100);
    g.drawRect(0, height-50, (int)((width*percent)/100), 50);
    percent += 1;
    try {
        Thread.sleep(50);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Using SwingUtilities.invokeAndWait((new Splash())); is placing the Runnable onto the Event Queue, meaning when you enter your while loop and Thread.sleep, you're preventing the Event Queue from dispatching any new events, including repaint requests

You should be using something like a SwingWorker to perform your actually loading (in a background thread), publishing the progress results, which the splash screen can the display....

enter image description here

public class TestSplashScreen {

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

    public TestSplashScreen() {
        SplashScreenWorker worker = new SplashScreenWorker();
        worker.execute();
        try {
            worker.get();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        System.out.println("All Done...");
//        Launch main application...
//        SwingUtilities.invokeLater(...);
    }

    public class SplashScreenWorker extends SwingWorker<Void, Float> {

        private SplashScreen splash;

        public SplashScreenWorker() {
            splash = SplashScreen.getSplashScreen();
            if (splash == null) {
                System.out.println("SplashScreen.getSplashScreen() returned null");
                return;
            }
        }

        @Override
        protected void process(List<Float> chunks) {
            Graphics2D g = splash.createGraphics();
            if (g == null) {
                System.out.println("g is null");
                return;
            }
            float progress = chunks.get(chunks.size() - 1);
            int height = splash.getSize().height;
            int width = splash.getSize().width;
            g.setComposite(AlphaComposite.Clear);
            g.fillRect(0, 0, width, height);
            g.setPaintMode();
            g.setColor(Color.WHITE);
            g.drawRect(0, height - 50, width, 50);
            g.setColor(Color.RED);
            int y = height - 50;
            g.fillRect(0, y, (int) (width * progress), 50);
            FontMetrics fm = g.getFontMetrics();
            String text = "Loading Microsoft Windows..." + NumberFormat.getPercentInstance().format(progress);
            g.setColor(Color.WHITE);
            g.drawString(text, (width - fm.stringWidth(text)) / 2, y + ((50 - fm.getHeight()) / 2) + fm.getAscent());
            g.dispose();
            splash.update();
        }

        @Override
        protected Void doInBackground() throws Exception {
            for (int value = 0; value < 1000; value++) {

                float progress = value / 1000f;
                publish(progress);
                Thread.sleep(25);

            }
            return null;
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366