如何在Java中正确实现自定义加载屏幕

时间:2017-02-20 14:53:53

标签: java swing loading splash

我正在尝试用Java创建自定义加载屏幕(不使用JProgressBar)。现在我刚尝试制作一个加载条,用黑色矩形从左到右缓慢填充屏幕。为了测试这个,我制作了一个简单的程序来计算随机数。我在一个单独的线程上运行分解代码,我让图形每100毫秒获得一次因子分解的进度。但是,有时候应用程序在10秒内没有响应,然后继续运行。 如何在Java中正确实现自定义加载屏幕或我现在使用的代码有什么问题?

以下是代码:

public class Factorer implements Runnable, Loadable {

    private static Random r = new Random();

    private volatile int numOn;

    private volatile int numsTotal;

    public static void main(String[] args){

        Factorer fact = new Factorer(25);

        LoadingFrame f = new LoadingFrame(fact);
        fact.run();

    }

    public Factorer(int nNums){

        numsTotal = nNums;

    }

    public void factorRandomNumber(){

        int randomNumber = r.nextInt(Integer.MAX_VALUE);

        int n = randomNumber;

        List<Integer> factors = new ArrayList<Integer>();

        for (int i = 2; i <= n; i++) {

            while (n % i == 0) {

                factors.add(i);
                n /= i;

            }

        }

    }

    public void factorRandomNumbers(){

        for(numOn = 0; numOn < numsTotal; numOn++){

            factorRandomNumber();

        }

    }

    public float getProgress(){

        return ((float) numOn) / ((float) numsTotal);

    }

    @Override
    public void run() {

        factorRandomNumbers();

    }

}

这是可加载的界面:

public interface Loadable {

    public float getProgress();

}

这是图形类:

public class LoadingFrame extends JFrame {

    private static final long serialVersionUID = 8290713730328501888L;

    private static final int WIDTH = 400;
    private static final int HEIGHT = 400;

    private Loadable loadable;

    public LoadingFrame(Loadable l){

        super("Loading Test");

        this.loadable = l;

        this.setSize(WIDTH, HEIGHT);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        Timer t = new Timer(100, new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {

                repaint();

            }

        });

        t.start();

    }

    @Override
    public void paint(Graphics g){

        g.setColor(Color.BLACK);

        g.fillRect(0, 0, (int) (loadable.getProgress() * (float) WIDTH), HEIGHT);

    }

}

1 个答案:

答案 0 :(得分:1)

  

我在一个单独的线程上运行保理代码

嗯,是的,不是。您的Factorer类实现了runnable,但您从不将该类视为单独的Thread。

相反,你只需使用:

fact.run();

如果您尝试将此类用作可重复使用的单独Thread,那么您可以使用代码中的某个位置:

new Thread( new Factorer() ).start();

实际启动线程。

但是,因为JVM在与Event Dispatch Thread (EDT)不同的线程中启动,所以代码在单独的线程上运行,但是比设计更偶然。

Factorer类中的逻辑也不起作用,因为当您调用getProgress()方法时,您将始终获得返回的相同值。也就是说,factoroRandomNumbers()号码在程序开始时执行一次,numOnnumsTotal将初始化为最终值。

public void paint(Graphics g){

你不应该重写paint()。自定义绘画是通过覆盖JPanel上的paintComponent(...)完成的,然后将面板添加到框架中。

您的计时器逻辑不正确。你所做的只是调用repaint(),但正如我之前所说,返回的值永远不会改变。你真正需要做的是调用getNextValue()之类的方法。此方法会从包含随机数的List中获取值。

为了更好地了解Swing的工作原理,您需要阅读Swing Tutorial。您可能希望从以下部分开始:

  1. Swing中的并发
  2. 执行自定义绘画
  3. 使用SwingWorker可能更容易(如Swing中的Concurrency部分所述)。这将为您创建一个单独的线程。然后你有循环代码,生成一个随机值,&#34;发布&#34;这个价值。发布此值后,您将使用值重新绘制框架。