Splashscreen in Java

2019-07-25 14:02发布

问题:

I need to figure out where in this code I need to adjust it to move the line "Splash Screen!!!" to the middle of the screen and possibly make it bigger. I am not sure where in the code this is and it is driving me nuts.

import java.awt.*;
import javax.swing.*;

public class SplashScreen extends JWindow {

private int duration;

public SplashScreen(int d) {
    duration = d;
}

// A simple little method to show a title screen in the center
// of the screen for the amount of time given in the constructor
public void showSplash() {

    JPanel content = (JPanel)getContentPane();
    content.setBackground(Color.blue);

    // Set the window's bounds, centering the window
    int width = 700;
    int height = 450;
    Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    int x = (screen.width-width)/2;
    int y = (screen.height-height)/2;
    setBounds(x,y,width,height);

    // Build the splash screen
    JLabel label = new JLabel(new ImageIcon("java-tip.gif"));
    JLabel copyrt = new JLabel
        ("Splash Screen!!!", JLabel.CENTER);
    copyrt.setFont(new Font("Sans-Serif", Font.BOLD, 12));
    content.add(label, BorderLayout.CENTER);
    content.add(copyrt, BorderLayout.SOUTH);
    Color oraRed = new Color(200, 50, 20, 255);
    content.setBorder(BorderFactory.createLineBorder(oraRed, 10));

    // Display it
    setVisible(true);

    // Wait a little while, maybe while loading resources
    try { Thread.sleep(duration); } catch (Exception e) {}

    setVisible(false);
}
public void showSplashAndExit() {
    showSplash();
    System.exit(0);

}

public static void main(String[] args) {

    // Throw a nice little title page up on the screen first
    SplashScreen splash = new SplashScreen(10000);

    // Normally, we'd call splash.showSplash() and get on
    // with the program. But, since this is only a test...
    splash.showSplashAndExit();
}
}

I am not sure why but the add code feature in this forum always makes it look weird and not indented properly.

回答1:

There's a few ways this might be done, but lets keep it simple.

Basically, what this does is add the label (background) image to the center position of the content pane. It then applies a BorderLayout to label and adds copyrt to the center position of label...

public void showSplash() {

    JPanel content = (JPanel) getContentPane();
    content.setBackground(Color.blue);

    // Set the window's bounds, centering the window
    int width = 700;
    int height = 450;
    Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
    int x = (screen.width - width) / 2;
    int y = (screen.height - height) / 2;
    setBounds(x, y, width, height);

    // Build the splash screen
    JLabel label = new JLabel(new ImageIcon("java-tip.gif"));
    JLabel copyrt = new JLabel("Splash Screen!!!", JLabel.CENTER);

    content.add(label, BorderLayout.CENTER);

    // Fun starts here...    
//        copyrt.setFont(new Font("Sans-Serif", Font.BOLD, 12));
//        content.add(copyrt, BorderLayout.SOUTH);

    label.setLayout(new BorderLayout());
    Font font = copyrt.getFont();
    copyrt.setFont(font.deriveFont(Font.BOLD, 24f));
    label.add(copyrt);

    Color oraRed = new Color(200, 50, 20, 255);
    content.setBorder(BorderFactory.createLineBorder(oraRed, 10));

    // Display it
    setVisible(true);

    // Don't do this, as it will cause the EDT to be stopped.  Instead
    // setup some kind of callback that can tell when the resources are 
    // loaded and start the rest of the application from there...
    // Wait a little while, maybe while loading resources
    //try {
    //    Thread.sleep(duration);
    //} catch (Exception e) {
    //}

    //setVisible(false);
}

It's also a bad idea to do anything within the context of the EDT that may prevent it from processing further events, like using sleep or long running/infinite loops.

All UI interactions should executed from within the context of the EDT and all long running or potentially blocking tasks should run on a separate thread.

Take a look at Concurrency in Swing for more details

Updated

If I try to run your example, the splash screen never appears, because Thread.sleep is preventing to from being show on the screen. The fact that you "might" get it working is actually a fluke, as you are probably calling the showSplash method from the "main" thread and not the EDT.

Instead, if I replace Thread.sleep with a SwingWorker, I not only get the splash screen to show up, but I also get the added benefit of being able to control things like, progress updates and scheduling for disposing of the splash screen...

For example...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SplashDemo extends JWindow {

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

    public SplashDemo() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                showSplash();

            }
        });
    }

    public void showSplash() {

        JPanel content = (JPanel) getContentPane();
        content.setBackground(Color.blue);

        // Set the window's bounds, centering the window
        int width = 700;
        int height = 450;
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (screen.width - width) / 2;
        int y = (screen.height - height) / 2;
        setBounds(x, y, width, height);

        // Build the splash screen
        JLabel label = new JLabel(new ImageIcon(getClass().getResource("/java_animated.gif")));
        JLabel copyrt = new JLabel("Splash Screen!!!", JLabel.CENTER);

        content.add(label, BorderLayout.CENTER);

        label.setLayout(new GridBagLayout());
        Font font = copyrt.getFont();
        copyrt.setFont(font.deriveFont(Font.BOLD, 24f));

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        label.add(copyrt, gbc);

        ImageIcon wait = new ImageIcon(getClass().getResource("/wait.gif"));
        label.add(new JLabel(wait), gbc);

        Color oraRed = new Color(200, 50, 20, 255);
        content.setBorder(BorderFactory.createLineBorder(oraRed, 10));

        // Display it
        setVisible(true);
        toFront();

        new ResourceLoader().execute();
    }

    public class ResourceLoader extends SwingWorker<Object, Object> {

        @Override
        protected Object doInBackground() throws Exception {

            // Wait a little while, maybe while loading resources
            try {
                Thread.sleep(5000);
            } catch (Exception e) {
            }

            return null;

        }

        @Override
        protected void done() {
            setVisible(false);
        }


    }

}

If you like, I used the following images...



回答2:

You are using BorderLayout which means your container is divided into EAST, WEST NORTH, SoUTH AND CENTER. You are adding "Splash Screen" to the south. Thats why it's not centering:

content.add(copyrt, BorderLayout.SOUTH);

You need to change the layout managers to one of the grid layouts. Alternatively, create multiple panels and add your content to them, then add to the parent container.