我正在尝试制作一个非常基本的动画,其中ArrayList中的单词在屏幕上移动。为此,我使用了drawString()方法和一个计时器,以每设置的毫秒数更改x位置。目前,我的paintComponent方法设置为绘制两个不同的单词,第一个单词为“ Hello”,第二个单词为2.5秒。
我的问题是图形坐标系似乎正在移动,结果,我在第一个“ Hello”之后生成的单词的行为有所不同。单词“世界”设置为常数x = 0,但它在屏幕中间产生,并且与单词“ Hello”一起移动。另外,粉红色背景本身的移动速度似乎与文字不同!
让我最困扰的是,如果我摆脱了第32-38行(产生单词的代码),并且仅设置背景颜色,背景仍然会移动。但是,如果我摆脱了第80行(更改x的方法),背景就会停止移动。这意味着我的x值和背景之间肯定存在某种关系,但是我只是无法弄清楚它是什么。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Word extends JPanel{
private ArrayList<String> phrase;
int x;
private int y;
private int interval;
private Word(ArrayList<String> Phrase,int height,int Interval){
interval = Interval;
y = height;
phrase = Phrase;
this.setBackground(Color.WHITE);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.MAGENTA);
g.setColor(Color.BLACK);
g.setFont(new Font("TimesRoman", Font.BOLD, 30));
for (int num = 0; num < phrase.size(); num++){
if(num == 2){
g.drawString(phrase.get(num), 0, 100*(num+1));
}else{
g.drawString(phrase.get(num), x, 100*(num + 1));
}
}
}
public void changeX(){
x += 1;
}
public ArrayList<String> getPhrase(){
return phrase;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public int getInterval(){
return interval;
}
public static void main(String[] args){
final ArrayList<String> words = new ArrayList<String>();
words.add("Hello");
// words.add("World");
final Word test = new Word(words, 100, 50);
final JFrame frame = new JFrame("test");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.WHITE);
frame.add(test);
frame.setVisible(true);
Timer testTimer = new Timer();
TimerTask testTask = new TimerTask(){
int counter = 0;
boolean spawned = false;
public void run(){
test.changeX();
frame.repaint();
System.out.println(counter);
if(counter>50 && !spawned){
words.add("World");
spawned = true;
}
counter++;
}
};
testTimer.scheduleAtFixedRate(testTask, 0, test.getInterval());
}
}
我希望“世界”一词在框架的最左侧产生并保持静止。
答案 0 :(得分:0)
我的问题是图形坐标系似乎正在移动,结果,我在第一个“ Hello”之后生成的单词的行为有所不同。单词“世界”设置为常数x = 0,但它在屏幕中间产生,并且与单词“ Hello”一起移动。
好的,即时问题:
getX
(和getY
),这会更改组件用来确定其在屏幕上位置的值,这就是背景在移动的原因。for-loop
将永远不会到达2
,它将永远是0
或1
Swing也不是线程安全的,这意味着永远不要从事件调度线程的上下文之外(也不是ArrayList
)来更新UI(或UI依赖的内容)
有关更多详细信息,请参见Concurrency in Swing,有关可能的解决方案,请参见How to Use Swing Timers。
在下面的示例中,我尝试将每个元素的职责封装到其自己的类中,因此,文本的位置和动画变化量都浸泡在其自己的类中,这使您可以对每个片段应用不同的操作无需大量其他逻辑。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
WordPane wordPane = new WordPane();
wordPane.add(new Entity("Hello", new Point(0, 100), new Point(1, 0)));
final JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(Color.WHITE);
frame.add(wordPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer timer = new Timer(50, new ActionListener() {
int counter = 0;
boolean spawned = false;
@Override
public void actionPerformed(ActionEvent e) {
if (counter > 50 && !spawned) {
wordPane.add(new Entity("World", new Point(0, 200), new Point(0, 0)));
spawned = true;
}
counter++;
wordPane.tick();
wordPane.repaint();
}
});
timer.start();;
}
});
}
public class Entity {
private String text;
private Point point;
private Point delta;
public Entity(String text, Point point, Point delta) {
this.text = text;
this.point = point;
this.delta = delta;
}
public String getText() {
return text;
}
public Point getPoint() {
return point;
}
public void tick() {
point.x += delta.x;
point.y += delta.y;
}
}
public class WordPane extends JPanel {
private ArrayList<Entity> phrase = new ArrayList<>(25);
private int interval;
private WordPane() {
this.setBackground(Color.MAGENTA);
setFont(new Font("TimesRoman", Font.BOLD, 30));
}
public void tick() {
for (Entity entity : phrase) {
entity.tick();
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
FontMetrics fm = g.getFontMetrics();
for (Entity entity : phrase) {
int x = entity.getPoint().x;
int y = entity.getPoint().y + fm.getAscent();
g.drawString(entity.text, x, y);
}
}
public ArrayList<Entity> getPhrase() {
return phrase;
}
public void add(Entity entity) {
phrase.add(entity);
}
}
}