我开始制作一个小型应用程序,但遇到了问题。我不知道如何在面板上的“ for”循环中,在确定的时间(5秒)后绘制一个字符(字符串),以使字符在面板上不会相互重叠,但是该程序不会停止工作,但是会停止!
import javax.swing.*;
import java.awt.*;
public class TestClass {
private static JFrame frame;
private static JPanel panel;
public static void main(String[] args) {
frame = new JFrame();
panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.setFont(new Font("ms mincho", Font.ROMAN_BASELINE, 20));
for (char c = '\u30A0'; c <= '\u30FF'; c++)
//Here the program should stop for a while, and the next character should not overlap the previous one.
// I tried using Thread.sleep() and IT DOESN't WORK AS it SHOULD, because the program is interrupted and the panel disappears.
g.drawString(String.valueOf(c), 0, 20);
}
};
panel.setBackground(Color.BLACK);
frame.add(panel);
frame.setSize(600, 800);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
如果您解决了这些问题,则还有另一个问题。在循环中,我每次都必须重新创建JPanel对象并在其上进行绘制。那就不好了。
谢谢)
答案 0 :(得分:0)
(我不是Swing专家,因此以下答案可能不是最佳选择,欢迎进行任何改进)
据我所知,Swing拥有自己的专用线程,该线程负责绘图组件和处理事件。因此,如果您在paintComponent
方法中放置过多的逻辑(循环等),它将使该线程无响应,直到完成处理该逻辑为止,这将使它看起来像您的应用程序停止工作了。
要解决此类问题,请使paintComponent
打印单个字符(这是简单的逻辑,摆动应该可以快速处理),但同时创建单独的线程,该线程将定期更新保存该字符的变量(并且更新后的角色会建议框架或面板再次重新粉刷自身。)
因此您的代码可能类似于:
class TestClass {
private static JFrame frame;
private static JPanel panel;
private static volatile char charToPrint = '\u30A0';
public static void main(String[] args) {
frame = new JFrame();
panel = new JPanel() {
Font ms_mincho = new Font("ms mincho", Font.ROMAN_BASELINE, 20);
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.setFont(ms_mincho);
g.drawString(String.valueOf(charToPrint), 0, 20);
}
};
panel.setBackground(Color.BLACK);
frame.add(panel);
frame.setSize(600, 800);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(() -> {
if (charToPrint == '\u30FF')//if last character in range
charToPrint = '\u30A0'; //start over from first
else
charToPrint++; //else set next character
frame.repaint(); //suggest frame to repaint its component
//probably can be change to panel.repaint()
}, 0, 100, TimeUnit.MILLISECONDS);
}
}
答案 1 :(得分:-1)
这是我的解决方案。您必须创建某种线程来 为您倒数时间。我在javax.swing中使用了一个:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.ArrayList;
import javax.swing.Timer;
public class TestClass {
private static JFrame frame;
private static JPanel panel;
private static List<Character> chars = new ArrayList<>();
private static int currentIndex = 0;
public static void main(String[] args) {
// create an array of characters up front...
for (char c = '\u30A0'; c <= '\u30FF'; c++) {
chars.add(Character.valueOf(c));
}
// delayedPaint() called when timer fires. Updates the index
// into the character array; resets when necessary. Calls
// repaint() to redraw the screen...
ActionListener delayedPaint = new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentIndex++;
if (currentIndex == 95) {
currentIndex = 0;
}
panel.repaint();
}
};
// Timer setup...
Timer timer = new Timer(500, delayedPaint);
timer.setInitialDelay(1000);
timer.setDelay(500);
timer.start();
frame = new JFrame();
panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.setFont(new Font("ms mincho", Font.ROMAN_BASELINE, 20));
// did you want these in a row? I wasn't sure...
int x = 10;
int y = 20;
for (int i = 0; i < currentIndex; i++) {
g.drawString(String.valueOf(chars.get(i)), x, y);
x += 20;
// bumps y to the next row...
if (x > panel.getWidth()) {
x = 0;
y += 20;
}
}
}
};
panel.setBackground(Color.BLACK);
frame.add(panel);
frame.setSize(600, 800);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}