0

我正在尝试在初始屏幕上制作自己的进度条。创建我的启动画面很简单:

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

我的 main 方法的第一行调用了这个:

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

这是启动类:

    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();
            }
        }
    }
}

我没有收到任何错误,但我确实在它下面有一个小盒子:

下图带有一个矩形。

如果我将 drawRects 更改为 (0, 0, width, height) 它没有区别。

我试过在摇摆 EDT 上调用:

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

但什么也没有发生。

任何人都可以看到问题吗?或者知道如何解决?

4

2 回答 2

4

您应该在从不同线程更新 GUI 时使用SwingUtilities.invokeLateror 。SwingUtilities.invokeAndWait

请参阅Swing 中的并发一章,其中解释了这背后的原因。

教程中的SplashScreen 示例Thread.sleep在 Swing 线程内部执行。如果在 SplashScreen 显示时不需要任何其他 GUI 刷新,这也很好。但是,您的加载代码应该发生在不同的线程中。

我建议向setPercent您的类添加一个设置器,该设置器创建一个Runnable以通过SwingUtilities.invokeLater. 这样,您甚至不需要轮询percent变量,并且SwingThread也可以自由呈现其他 UI 内容。

于 2013-02-10T21:38:13.650 回答
3

Bikeshedder 是对的 (+1),您正在阻止 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();
    }
}

使用SwingUtilities.invokeAndWait((new Splash()));将 放置Runnable到事件队列中,这意味着当您进入while循环时Thread.sleep,您将阻止事件队列调度任何新事件,包括重绘请求

您应该使用类似的东西SwingWorker来执行您的实际加载(在后台线程中),发布进度结果,启动屏幕可以显示......

在此处输入图像描述

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;
        }
    }
}
于 2013-02-10T23:35:57.610 回答