gpt4 book ai didi

java - 为什么重复调用 repaint() 方法不起作用

转载 作者:行者123 更新时间:2023-12-02 11:35:46 25 4
gpt4 key购买 nike

我的目标是在 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);
}
}
}

最佳答案

I have also provided another code which works as expected but has no buttons to trigger the animation.

这两段代码之间的区别在于调用它们的上下文。

“有效”的代码实际上是在“主”线程中的偶数调度线程的上下文之外更新的,这意味着执行诸如 Thread.sleep 之类的操作不会阻止UI 已更新。

使用事件调度线程的内容(来自 ActionListener)更新不起作用的代码,这会阻止 EDT 在 之后处理新的绘制请求>actionPerformed 方法返回

当您决定更新圆圈的位置时,您将面临的另一个问题有关。

paintComponent 可以因多种不同原因而被调用,其中许多原因是您无法控制的。绘画应该专注于描绘当前的状态,而不应该(直接或间接)修改它。相反,您应该使用某种 update 方法,其作用是更新圆的 x/y 位置并触发新的绘制周期。

我强烈建议您停下来花点时间阅读:

您的问题是菜鸟错误,源于不了解 API 的实际工作原理以及不了解可用于解决它的工具

还有许多其他“问题”会导致不良行为,例如最后没有调用 setVisible,因此无需再次更新 UI 以确保添加的组件是可见。

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();
}
}

}
}

关于java - 为什么重复调用 repaint() 方法不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48960441/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com