我正在尝试用 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);
}
}
最佳答案
I run the factoring code on a separate thread
嗯,是的,也不是。您的 Factorer 类实现了 runnable,但您从不将该类视为单独的线程。
相反,您只需使用:
fact.run();
如果您尝试将此类用作可重用的单独线程,那么在代码中的某个位置您将拥有:
new Thread( new Factorer() ).start();
实际启动线程。
但是,由于 JVM 在与事件调度线程 (EDT) 不同的线程中启动,因此您的代码在单独的线程上运行,但这更多是出于偶然而不是设计。
此外,Factorer
类中的逻辑将不起作用,因为当您调用 getProgress() 方法时,您将始终获得相同的返回值。也就是说,factoroRandomNumbers()
数字在程序开始时执行一次,然后 numOn
和 numsTotal
将被初始化为其最终值.
public void paint(Graphics g){
你不应该重写paint()。自定义绘制是通过重写 JPanel 上的 paintComponent(...)
来完成的,然后将面板添加到框架中。
您的计时器逻辑不正确。您所做的就是调用 repaint(),但正如我之前所说,返回的值永远不会改变。您真正需要做的是调用像 getNextValue() 这样的方法。此方法将从包含随机数的 List
中获取一个值。
为了更好地理解 Swing 的工作原理,您需要阅读 Swing Tutorial 。您可能想从以下部分开始:
- Swing 中的并发
- 进行定制绘画
使用 SwingWorker
可能会更容易(如 Swing 中的并发部分所述)。这将为您创建一个单独的线程。然后你有循环代码生成一个随机值并“发布”这个值。发布此值后,您可以使用该值重新绘制框架。
关于java - 如何在 Java 中正确实现自定义加载屏幕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42347658/