我正在尝试用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);
}
}
答案 0 :(得分:1)
我在一个单独的线程上运行保理代码
嗯,是的,不是。您的Factorer
类实现了runnable,但您从不将该类视为单独的Thread。
相反,你只需使用:
fact.run();
如果您尝试将此类用作可重复使用的单独Thread,那么您可以使用代码中的某个位置:
new Thread( new Factorer() ).start();
实际启动线程。
但是,因为JVM在与Event Dispatch Thread (EDT)
不同的线程中启动,所以代码在单独的线程上运行,但是比设计更偶然。
此Factorer
类中的逻辑也不起作用,因为当您调用getProgress()方法时,您将始终获得返回的相同值。也就是说,factoroRandomNumbers()
号码在程序开始时执行一次,numOn
和numsTotal
将初始化为最终值。
public void paint(Graphics g){
你不应该重写paint()。自定义绘画是通过覆盖JPanel上的paintComponent(...)
完成的,然后将面板添加到框架中。
您的计时器逻辑不正确。你所做的只是调用repaint(),但正如我之前所说,返回的值永远不会改变。你真正需要做的是调用getNextValue()之类的方法。此方法会从包含随机数的List
中获取值。
为了更好地了解Swing的工作原理,您需要阅读Swing Tutorial。您可能希望从以下部分开始:
使用SwingWorker
可能更容易(如Swing中的Concurrency部分所述)。这将为您创建一个单独的线程。然后你有循环代码,生成一个随机值,&#34;发布&#34;这个价值。发布此值后,您将使用值重新绘制框架。