Repaint() 只工作了一半
Repaint() working only half times
我对应该是一个简单的练习有疑问。
我被要求制作一个打印绿色椭圆形(填充)的小程序,该椭圆形在到达边界之前变大,然后开始变小。
这应该一直持续到您关闭小程序。
好吧,我想出了这个代码
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JApplet;
public class Disco extends JApplet{
private int x;
private int y;
private int r;
private boolean enlarge;
MakeLarger makeLarger;
MakeSmaller makeSmaller;
public void init() {}
public void start() {
x = getWidth()/2;
y = getHeight()/2;
r = 50;
enlarge = true;
makeLarger = new MakeLarger();
makeLarger.start();
}
public void paint(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x - r, y- r, r*2, r*2);
}
public void update() {
if(enlarge) {
makeLarger = new MakeLarger();
makeLarger.start();
} else {
makeSmaller = new MakeSmaller();
makeSmaller.start();
}
}
private class MakeLarger extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(getWidth() > getHeight()) {
if(r < getHeight()/2) {
r++;
repaint();
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
} else {
if(r < getWidth()/2) {
r++;
repaint();
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
private class MakeSmaller extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(r > 50) {
r--;
repaint();
revalidate();
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = true;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
当我启动我的小程序时,椭圆开始正确增长,直到到达边界然后突然停止。
我首先想到的是它没有正确变小。但是一点 System.out.println 的工作告诉我所有计算都在正确进行,问题是小程序仅在 makeLarger 线程处于活动状态时才重绘,当 makeSmaller 线程在工作时,对 repaint() 的调用不会工作!
如果我在 makeSmaller Thread 工作时调整小程序 window 的大小,它会正确地重新绘制,显示椭圆变小了。
有人可以就这种奇怪的行为启发我吗?
我错过了什么?
感谢大家的帮助,如果我的英语很差,请见谅!
我不能说我已经查看了所有代码,但有几点建议:
- 在 JPanel 的
paintComponent
覆盖中绘制。
- 这是关键:在覆盖的第一行调用
super.paintComponent
方法。这摆脱了先前的图像,使图像可以变小。
- 通过将 JPanel 添加到小程序来在 JApplet 中显示它。
- 我自己,我会为动画循环使用一个 Swing Timer,并会使用一个布尔值来决定调整大小的方向。
- 但是无论我使用的是 Swing Timer 还是放置在 Thread 中的 Runnable,我都会尽量保持简单,这意味着使用单个 Timer 来改变调整大小的方向或单个 Runnable/Thread,它根据布尔值更改调整大小的大小。您正在执行的这种线程交换只会使事情过于复杂且不必要地复杂化,并且很可能是错误的根源。
- 作为附带建议,您几乎不想扩展 Thread。更好的方法是创建实现 Runnable 的 类,然后当你需要在后台线程中 运行 它们时,创建一个线程,将你的 Runnable 传递到线程的构造函数中,然后调用
start()
在线程上。
首先,谢谢大家对我的帮助!
我试图解决的问题是:
Make an applet which shows a green oval getting larger until it hits the borders, then it should start getting smaller up to a fixed radius (50), then it should start over (and over) again. Solve the problem by making two threads (by extending Thread).
只是为了解释为什么算法如此奇怪!
好吧,阅读您的建议我修正了我的代码,现在 运行 正确了。这是代码,如果有人需要的话。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JApplet;
import javax.swing.Timer;
public class Disco extends JApplet{
private int x;
private int y;
private int r;
private boolean enlarge;
MakeLarger makeLarger;
MakeSmaller makeSmaller;
public void init() {}
public void start() {
x = getWidth()/2;
y = getHeight()/2;
r = 50;
enlarge = true;
makeLarger = new MakeLarger();
makeLarger.start();
Timer timer = new Timer(1000/60, new ActionListener() {
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
public void paint(Graphics g) {
BufferedImage offScreenImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_4BYTE_ABGR_PRE);
Graphics2D g2D = (Graphics2D) offScreenImage.getGraphics();
g2D.clearRect(0, 0, getWidth(), getHeight());
g2D.setColor(Color.GREEN);
g2D.fillOval(x - r, y- r, r*2, r*2);
g.drawImage(offScreenImage, 0, 0, this);
}
public void update() {
if(enlarge) {
makeLarger = new MakeLarger();
makeLarger.start();
} else {
makeSmaller = new MakeSmaller();
makeSmaller.start();
}
}
private class MakeLarger extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(getWidth() > getHeight()) {
if(r < getHeight()/2) {
r++;
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
} else {
if(r < getWidth()/2) {
r++;
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
private class MakeSmaller extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(r > 50) {
r--;
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = true;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
我对应该是一个简单的练习有疑问。 我被要求制作一个打印绿色椭圆形(填充)的小程序,该椭圆形在到达边界之前变大,然后开始变小。 这应该一直持续到您关闭小程序。
好吧,我想出了这个代码
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JApplet;
public class Disco extends JApplet{
private int x;
private int y;
private int r;
private boolean enlarge;
MakeLarger makeLarger;
MakeSmaller makeSmaller;
public void init() {}
public void start() {
x = getWidth()/2;
y = getHeight()/2;
r = 50;
enlarge = true;
makeLarger = new MakeLarger();
makeLarger.start();
}
public void paint(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x - r, y- r, r*2, r*2);
}
public void update() {
if(enlarge) {
makeLarger = new MakeLarger();
makeLarger.start();
} else {
makeSmaller = new MakeSmaller();
makeSmaller.start();
}
}
private class MakeLarger extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(getWidth() > getHeight()) {
if(r < getHeight()/2) {
r++;
repaint();
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
} else {
if(r < getWidth()/2) {
r++;
repaint();
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
private class MakeSmaller extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(r > 50) {
r--;
repaint();
revalidate();
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = true;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
当我启动我的小程序时,椭圆开始正确增长,直到到达边界然后突然停止。
我首先想到的是它没有正确变小。但是一点 System.out.println 的工作告诉我所有计算都在正确进行,问题是小程序仅在 makeLarger 线程处于活动状态时才重绘,当 makeSmaller 线程在工作时,对 repaint() 的调用不会工作! 如果我在 makeSmaller Thread 工作时调整小程序 window 的大小,它会正确地重新绘制,显示椭圆变小了。
有人可以就这种奇怪的行为启发我吗? 我错过了什么?
感谢大家的帮助,如果我的英语很差,请见谅!
我不能说我已经查看了所有代码,但有几点建议:
- 在 JPanel 的
paintComponent
覆盖中绘制。 - 这是关键:在覆盖的第一行调用
super.paintComponent
方法。这摆脱了先前的图像,使图像可以变小。 - 通过将 JPanel 添加到小程序来在 JApplet 中显示它。
- 我自己,我会为动画循环使用一个 Swing Timer,并会使用一个布尔值来决定调整大小的方向。
- 但是无论我使用的是 Swing Timer 还是放置在 Thread 中的 Runnable,我都会尽量保持简单,这意味着使用单个 Timer 来改变调整大小的方向或单个 Runnable/Thread,它根据布尔值更改调整大小的大小。您正在执行的这种线程交换只会使事情过于复杂且不必要地复杂化,并且很可能是错误的根源。
- 作为附带建议,您几乎不想扩展 Thread。更好的方法是创建实现 Runnable 的 类,然后当你需要在后台线程中 运行 它们时,创建一个线程,将你的 Runnable 传递到线程的构造函数中,然后调用
start()
在线程上。
首先,谢谢大家对我的帮助!
我试图解决的问题是:
Make an applet which shows a green oval getting larger until it hits the borders, then it should start getting smaller up to a fixed radius (50), then it should start over (and over) again. Solve the problem by making two threads (by extending Thread).
只是为了解释为什么算法如此奇怪!
好吧,阅读您的建议我修正了我的代码,现在 运行 正确了。这是代码,如果有人需要的话。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JApplet;
import javax.swing.Timer;
public class Disco extends JApplet{
private int x;
private int y;
private int r;
private boolean enlarge;
MakeLarger makeLarger;
MakeSmaller makeSmaller;
public void init() {}
public void start() {
x = getWidth()/2;
y = getHeight()/2;
r = 50;
enlarge = true;
makeLarger = new MakeLarger();
makeLarger.start();
Timer timer = new Timer(1000/60, new ActionListener() {
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
public void paint(Graphics g) {
BufferedImage offScreenImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_4BYTE_ABGR_PRE);
Graphics2D g2D = (Graphics2D) offScreenImage.getGraphics();
g2D.clearRect(0, 0, getWidth(), getHeight());
g2D.setColor(Color.GREEN);
g2D.fillOval(x - r, y- r, r*2, r*2);
g.drawImage(offScreenImage, 0, 0, this);
}
public void update() {
if(enlarge) {
makeLarger = new MakeLarger();
makeLarger.start();
} else {
makeSmaller = new MakeSmaller();
makeSmaller.start();
}
}
private class MakeLarger extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(getWidth() > getHeight()) {
if(r < getHeight()/2) {
r++;
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
} else {
if(r < getWidth()/2) {
r++;
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = false;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}
private class MakeSmaller extends Thread {
public void run() {
while(true) {
x = getWidth()/2;
y = getHeight()/2;
if(r > 50) {
r--;
try {
sleep(25);
} catch(InterruptedException e) {
e.printStackTrace();
}
} else {
enlarge = true;
update();
Thread.currentThread().interrupt();
return;
}
}
}
}
}