我的目标是在JFrame上放一个按钮和一个圆圈。当我单击按钮时,圆圈应在面板/框架上随机移动。
但是当我单击按钮时,圆圈只移动一次,在放入SOP语句后,我发现“ frame.repaint()”被多次调用,但此调用触发了“< em> paintComponent “方法只有一次,这是第一次(在类Panel1中定义)。很奇怪!
我还提供了另一个按预期工作但没有按钮来触发动画的代码。我已经读过 repaint()请求被合并在一起并执行一次,那么第二个程序是如何工作的呢?
import java.awt.event.*;
import java.awt.Graphics.*;
import javax.swing.*;
import java.awt.*;
public class SimpleGui3c_4 {
public static void main(String args[]) {
Frame1 frame = new Frame1();
frame.go();
}
}
class Frame1 {
JFrame frame;
Panel1 p;
void go() {
frame = new JFrame();
JButton button1 = new JButton("Color Change");
p = new Panel1();
frame.setSize(500,500);
frame.setVisible(true);
frame.getContentPane().add(BorderLayout.SOUTH, button1);
frame.getContentPane().add(BorderLayout.CENTER, p);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
button1.addActionListener(new ColorActionListener());
}
class ColorActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
for(int i=0;i<130;i++) {
System.out.println("Frame repaint started");
frame.repaint();
try {
Thread.sleep(5000);
}catch(Exception ex) {}
System.out.println("Frame repaint ended");
}
}
}
class Panel1 extends JPanel {
public void paintComponent(Graphics g) {
System.out.println("Inside the paint Component method");
int x = (int)(Math.random()*100);
int y = (int)(Math.random()*100);
g.setColor(Color.BLUE);
g.fillOval(x,y,100,100);
System.out.println("Exiting the paint component method");
}
}
}
代码可以工作,但没有按钮来触发动画,它一旦我运行代码就可以工作。我不确定为什么以下程序有效并且上述程序失败了!
import javax.swing.*;
import java.awt.*;
public class SimpleAnimation {
int x = 70;
int y = 70;
public static void main(String args[]) {
SimpleAnimation gui = new SimpleAnimation();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel drawPanel = new MyDrawPanel();
frame.getContentPane().add(drawPanel);
frame.setSize(300,300);
frame.setVisible(true);
for(int i = 0;i<130;i++) {
//x++;
//y++;
drawPanel.repaint();
try {
Thread.sleep(50);
}catch(Exception ex) {}
}
}//close go
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0,0,this.getWidth(), this.getHeight());
int x = (int)(Math.random()*70);
int y = (int)(Math.random()*70);
g.setColor(Color.green);
g.fillOval(x,y,40,40);
}
}
}
答案 0 :(得分:1)
我还提供了另一个按预期工作但没有按钮来触发动画的代码。
两段代码之间的区别在于它们被调用的上下文。
“工作”的代码实际上已在“主”线程中的偶数调度线程的上下文中更新,这意味着执行Thread.sleep
之类的操作不会阻止UI更新
使用事件调度线程的内容(来自ActionListener
)更新了无效的代码,这阻止了EDT在actionPerformed
之后处理新的绘制请求方法返回
您将面临的另一个问题与您决定更新圈子的位置有关。
可以出于各种不同的原因调用 paintComponent
,其中许多是您无法控制的。绘画应该专注于绘制当前状态,不应该直接或间接地修改它。相反,您应该使用某种update
方法,它的工作就是更新圆的x / y位置并触发新的绘制周期。
我强烈建议您停下来并花时间阅读:
你的问题是新手的错误,这是由于不了解API的实际工作方式而不是理解可用于解决它的工具
还有许多其他“问题”会导致不良行为,例如最后不调用setVisible
,因此不需要再次更新UI以确保添加的组件可见。< / p>
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimpleGui3c_4 {
public static void main(String args[]) {
new SimpleGui3c_4();
}
public SimpleGui3c_4() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Frame1 frame = new Frame1();
frame.go();
}
});
}
public interface Animatable {
public void update();
}
public class Frame1 {
JFrame frame;
Panel1 p;
void go() {
frame = new JFrame();
JButton button1 = new JButton("Color Change");
p = new Panel1();
frame.getContentPane().add(BorderLayout.SOUTH, button1);
frame.getContentPane().add(BorderLayout.CENTER, p);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
button1.addActionListener(new ColorActionListener(p));
frame.pack();
frame.setVisible(true);
}
class ColorActionListener implements ActionListener {
private Animatable parent;
public ColorActionListener(Animatable parent) {
this.parent = parent;
}
public void actionPerformed(ActionEvent e) {
JButton btn = (JButton) e.getSource();
btn.setEnabled(false);
Timer timer = new Timer(5000, new ActionListener() {
private int counter = 0;
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Frame repaint started");
parent.update();
counter++;
if (counter >= 130) {
((Timer)e.getSource()).stop();
btn.setEnabled(true);
}
}
});
timer.setInitialDelay(0);
timer.start();
}
}
class Panel1 extends JPanel implements Animatable {
private int xPos, yPos;
public Panel1() {
update();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Inside the paint component method");
g.setColor(Color.BLUE);
g.fillOval(xPos, yPos, 100, 100);
System.out.println("Exiting the paint component method");
}
@Override
public void update() {
System.out.println("Inside the update method");
xPos = (int) (Math.random() * 100);
yPos = (int) (Math.random() * 100);
repaint();
}
}
}
}