Java初始屏幕无法在Mac OSX上运行,但在PC上运行

时间:2016-11-02 13:19:04

标签: java eclipse macos splash-screen executable-jar

下面的代码是我用Eclipse开发的小型Java应用程序的启动画面的实现。启动画面在PC上运行良好,但在MAC上运行不正常。在MAC OSX上,首先出现的帧在2秒内出现灰色区域,然后在4秒的剩余时间内出现图像。图像通常应立即显示,持续时间为4秒。您是否知道为什么在图像出现在MAC上之前有延迟,而一切都在PC上运行良好? PS:我已经将应用程序部署为可执行的Jar,并且我在所有计算机上都使用Java 8。谢谢。

public static void main(String[] args)
{
    SplashScreen splSplashScreen = new SplashScreen();
    //Main window
    FenetrePrincipale fenetrePrincipale = new FenetrePrincipale();
}
public class SplashScreen extends JWindow
{
    /**
     * Numéro de série
     */
    private static final long serialVersionUID = 1592663893301307318L;

    private final static long TEMP_AFFICHAGE = 4000;

    /**
     * Constructeur par initialisation
     * @param p_Frame Frame
     * @param p_TempsAffichage Temps d'affichage en millisecondes
     */
    public SplashScreen()
    {
        super(new Frame());
        JLabel lblImage = new JLabel(new ImageIcon(this.getClass().getResource("/res/ui/splashScreen.jpg")));

        Container container = this.getContentPane();
        container.add(lblImage, BorderLayout.CENTER);
        pack();

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Dimension labelSize = lblImage.getPreferredSize();
        this.setLocation(screenSize.width/2 - (labelSize.width/2), screenSize.height/2 - (labelSize.height/2));

        this.setVisible(true);

        try
        {
            Thread.sleep(TEMP_AFFICHAGE);
        }
        catch (InterruptedException ex)
        {
            ApplicationLogger.getInstance().severe(ex.getLocalizedMessage());
        }
        finally
        {
            this.setVisible(false);
        }
    }
}

1 个答案:

答案 0 :(得分:2)

修改这与原始答案完全不同;我将在下面留下原来的答案。

看起来最初的JLabel渲染在OSX上是狗慢 - 删除所有睡眠仍然让我在Java呈现标签时暂停约2秒。所以我们改变了规则。

首先,我们创建一个采用缓冲图像的JPanel类:

class ImgPanel extends JPanel {
    private BufferedImage img;

    public ImgPanel(BufferedImage img) {
        this.img = img;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(img.getWidth(), img.getHeight());
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(img, 0, 0, null);
    }
}

然后我们像这样更改启动画面构造函数:

public SplashScreen()
{
    BufferedImage img = null;
    try {
        img = ImageIO.read(this.getClass().getResource("/res/ui/splashScreen.jpg"));
    } catch (Exception ex) {
    }

    ImgPanel panel = new ImgPanel(img);
    Container container = this.getContentPane();
    container.add(panel);
    pack();

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    this.setLocation(screenSize.width/2 - (img.getWidth()/2), screenSize.height/2 - (img.getHeight()/2));

    this.setVisible(true);
 }

一旦面板出现而没有暂停,这将呈现图像。

注意 - 我删除了整个睡眠代码以减少混淆 - 在单独的SwingWorker中可以更好地捕获逻辑,以执行启动画面的隐藏和主屏幕的显示:

class worker extends SwingWorker<String, Object> {
    private final static long TEMP_AFFICHAGE = 4000;
    private SplashScreen splash;
    private FenetrePrincipale principale;

    public worker(SplashScreen splash, FenetrePrincipale principale) {
        this.splash = splash;
        this.principale = principale;
        this.splash.setVisible(true);
    }

    @Override
    public String doInBackground() {
        try
        {
            Thread.sleep(TEMP_AFFICHAGE);
        }
        catch (InterruptedException ex)
        {
            ApplicationLogger.getInstance().severe(ex.getLocalizedMessage());
        }
        return "";
    }

    @Override
    protected void done() {
        splash.setVisible(false);
        principale.setVisible(true);
    }
};

然后主代码如下:

public static void main(String[] args)
{
    SplashScreen splSplashScreen = new SplashScreen();
    //Main window
    FenetrePrincipale fenetrePrincipale = new FenetrePrincipale();
    worker w = new worker(splSplashScreen, fenetrePrincipale);
    w.execute();
}

原始答案 - 将休眠线程放入SwingWorker仍然是一个好主意,因为它可以让您在初始化之前执行实际工作。

好的,一个简单的例子,使用你的启动代码将休眠放入gui线程 - 这段代码在this.setVisible(true)之后,并替换try {} catch {} finally {}子句:

    this.setVisible(true);

    worker do_work = new worker(this);
    do_work.execute();
}

class worker extends SwingWorker<String, Object> {
    private SplashScreen parent;

    public worker(SplashScreen parent) {
        this.parent = parent;
    }

    @Override
    public String doInBackground() {
        try
        {
            Thread.sleep(TEMP_AFFICHAGE);
        }
        catch (InterruptedException ex)
        {
            ApplicationLogger.getInstance().severe(ex.getLocalizedMessage());
        }
        return "";
    }

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

我只是创建一个SwingWorker,它以doWorkInBackground进行休眠,一旦结束,它就会关闭父帧,即启动画面。