[英]How can I force a repaint() after every update() in a for loop in Java?
I have written a small, basic, kaleidoscope type program that should gradually draw the same pattern (over time) at six different points and at different orientations. 我写了一个小的,基本的,万花筒类型的程序,应该在六个不同的点和不同的方向逐渐绘制相同的模式(随着时间的推移)。
To do this I have created an array to store each pixel's colour (it's initial colour being black and represented by number 0) and then 6 starting points in the array have their colour changed to green (represented by number 1). 为此,我创建了一个数组来存储每个像素的颜色(它的初始颜色是黑色,用数字0表示),然后数组中的6个起始点的颜色变为绿色(由数字1表示)。 These points should appear on the screen and then, based on the previous 6 points' positions a further 6 points are created.
这些点应出现在屏幕上,然后根据之前的6个点位置创建另外6个点。 The updated screen should then be displayed.
然后应显示更新的屏幕。 Repeat, repeat, repeat...
重复,重复,重复......
My problem is that all of the updates, for new pixels, are being carried out before painting the screen. 我的问题是,在绘制屏幕之前,所有针对新像素的更新都在执行。 I have checked some other posts and web tutorials etc, and gather that AWT is kind enough to avoid wasting time repainting minor changes.
我已经检查了一些其他帖子和网络教程等,并收集AWT是足够的,以避免浪费时间重新绘制微小的变化。 There seems also to be something called
paintManager
involved in this. 似乎还有一些叫做
paintManager
东西。 I believe the problem is that I am repainting within a for loop. 我相信问题是我在for循环中重新绘制。 I am finding this really frustrating as, in my view, it should be a simple thing to do.
我发现这非常令人沮丧,因为在我看来,这应该是一件简单的事情。 Is there, indeed, a simple way to persuade java to plot these minor changes in the way I desire?
确实有一种简单的方法来说服java以我想要的方式描绘这些微小的变化吗?
I have included the code in its entirety below: 我已将代码全部包含在下面:
package paranoid;
import javax.swing.JFrame;
public class MasterFrame {
public static void main(String[] args) {
// TODO Auto-generated method stub
new MasterFrame();
}
public MasterFrame(){
JFrame f = new JFrame();
f.setTitle("Kaleidoscope");
f.add(new Trip2());
f.setSize(500,300);
f.setLocationRelativeTo(null);
f.setVisible(true);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
and... 和...
package paranoid;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Trip2 extends JPanel {
private static final long serialVersionUID = 1L;
private int xmin = 0,
xmax = 499,
ymin = 0,
ymax = 279;
private int x = 120;
private int y = 80;
private int dx = 1;
private int dy = 1;
private int temp = 0;
private int update_counter = 0;
private int repaint_counter = 0;
private int x_pos[] = new int[6];
private int y_pos[] = new int[6];
private int screen[][] = new int[500][280];
public Trip2() {
initialisation();
for(int i = 0; i < 5000; i++)
{
update();
System.out.println("Just returned from update()");
repaint(); //This repaint is not being activated until all updates
System.out.println("Just returned from paint()"); //have been completed, but I want a repaint after EVERY update.
}
}
public void initialisation(){
System.out.println("initialising...");
x_pos[0] = x;
y_pos[0] = y;
x_pos[1] = xmax - x;
y_pos[1] = y;
x_pos[2] = x;
y_pos[2] = ymax - y;
x_pos[3] = xmax - x;
y_pos[3] = ymax - y;
x_pos[4] = (int)(xmax/2)-50;
y_pos[4] = (int)(ymax/2);
x_pos[5] = (int)(xmax/2)+50;
y_pos[5] = (int)(ymax/2);
for(int j = 0; j<280; j++){
for(int i = 0; i<500; i++){
screen[i][j] = 0;
}
}
} //end of initialisation()
public void update(){
System.out.println("updating... for the "+update_counter+"th time");
temp = (int)Math.floor(Math.random()*100);
if(temp < 40){ // 40% chance that the direction is changed
dx = (int)Math.floor(Math.random()*3);
dy = (int)Math.floor(Math.random()*3);
dx = dx - 1;
dy = dy - 1;
}
x_pos[0] = x_pos[0]+dx;
y_pos[0] = y_pos[0]+dy;
x_pos[1] = x_pos[1]-dx;
y_pos[1] = y_pos[1]+dy;
x_pos[2] = x_pos[2]+dx;
y_pos[2] = y_pos[2]-dy;
x_pos[3] = x_pos[3]-dx;
y_pos[3] = y_pos[3]-dy;
x_pos[4] = x_pos[4]-dy;
y_pos[4] = y_pos[4]-dx;
x_pos[5] = x_pos[5]+dy;
y_pos[5] = y_pos[5]+dx;
for(int k = 0; k < 6; k++){
if(x_pos[k] < 0){
x_pos[k] = 0;
}
if(x_pos[k] > 499){
x_pos[k] = 499;
}
}
for(int k = 0; k < 6; k++){
if(y_pos[k] < 0){
y_pos[k] = 0;
}
if(y_pos[k] > 279){
y_pos[k] = 279;
}
}
screen[x_pos[0]][y_pos[0]] = 1;
screen[x_pos[1]][y_pos[1]] = 1;
screen[x_pos[2]][y_pos[2]] = 1;
screen[x_pos[3]][y_pos[3]] = 1;
screen[x_pos[4]][y_pos[4]] = 1;
screen[x_pos[5]][y_pos[5]] = 1;
update_counter = update_counter + 1;
} //end of update()
public void paint(Graphics g){
System.out.println("painting screen for the "+repaint_counter+"th time");
g.setColor(Color.BLACK);
g.fillRect(xmin, ymin, xmax, ymax);
for(int j = 0; j<280; j++){
for(int i = 0; i<500; i++){
if(screen[i][j] == 0){
g.setColor(Color.BLACK);
} else
{
g.setColor(Color.GREEN);
}
g.drawLine(i,j,i,j); //plots pixel
}
}
try{
Thread.sleep(100);
}
catch(InterruptedException e){
}
repaint_counter = repaint_counter + 1;
}//end of paint(Graphics g)
}//end of Trip2 class
What's happening is you are stuck in your for-loop
until it is done processing and then you repaint. 发生了什么事情,你被困在你的
for-loop
直到它完成处理然后你重绘。 What you should do is, since you are extending JPanel
you have access to the Component's paintComponent
method which is called when you first paint and on repaint of the component. 您应该做的是,因为您正在扩展
JPanel
,所以您可以访问Component的paintComponent
方法,该方法在您第一次绘制和重新绘制组件时调用。
Like So 像那样
@Override
public void paintComponent(Graphics g) {
}
Rather than your 而不是你的
public void paint(Graphics g) {
}
When you override paintComponent
, however, you need to make sure you call it's parent's paintComponent
但是,当您覆盖
paintComponent
时,您需要确保将其称为parent的paintComponent
Like so: 像这样:
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
And while we are at it we can call your Update method before or after all of your painting, I chose before everything in my example: 当我们在这里时,我们可以在你的所有绘画之前或之后调用你的Update方法,我在我的例子中选择了所有内容:
@Override
public void paintComponent(Graphics g) {
update();
super.paintComponent(g); // Super is used to reference the parent
// All of your painting methodology
repaint(); // Force the component to repaint so this gets called over and over.
}
Be sure to remove that for-loop; 一定要删除for循环; of course you could always keep it if you wanted to have a lot of data before drawing.
当然,如果你想在绘图之前获得大量数据,你可以随时保留它。
And if you really wanted you could always keep the exact same code you have but follow the similar pattern as I said above. 如果你真的想要你可以保持完全相同的代码,但遵循我上面所说的类似模式。
Like this: 像这样:
public void paint(Graphics g) {
update();
// All of your painting methodology
repaint(); // Force the component to repaint so this gets called over and over.
}
One of the main issues here is that you are calling Thread.sleep()
in the paint method - this is not a good idea as will halt the further repainting of your application for that period. 这里的一个主要问题是你在paint方法中调用
Thread.sleep()
- 这不是一个好主意,因为将停止在那段时间内进一步重新绘制你的应用程序。 (the Event Dispatch thread/Painting thread must not be use for any slow operations) (事件调度线程/绘图线程不得用于任何慢速操作)
The usual flow for what you want to achieve here is as follows (poss way more detail than you need): 您希望在此处实现的通常流程如下(可能比您需要的更详细):
Trip1
in your case) and set to an instance variable. Trip1
)并设置为实例变量。 interface
for changes on your model. interface
。 (eg ModelChangedListener
or such like) ModelChangedListener
等) In your main controlling class, register a listener to this model which solely calls: trip2Panel.repaint();
在你的主控制类中,为这个模型注册一个监听器,
trip2Panel.repaint();
调用: trip2Panel.repaint();
In the paint()
method of your panel... just draw the model as it currently stands. 在面板的
paint()
方法中......只需绘制当前的模型。
Full code posted: 完整代码发布:
package paranoid;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.Timer;
public class MasterFrame {
public static void main(String[] args) {
// TODO Auto-generated method stub
new MasterFrame();
}
public MasterFrame(){
JFrame f = new JFrame();
f.setTitle("Kaleidoscope");
final Trip2 trip2UI = new Trip2();
final TripModel model = new TripModel();
model.update();
Timer timer = new Timer(1, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
model.update();
}
});
timer.setRepeats(true);
timer.start();
model.addListener(new TripModelListener() {
@Override
public void modelChanged() {
trip2UI.repaint();
}
});
trip2UI.setModel(model);
f.add(trip2UI);
f.setSize(500,300);
f.setLocationRelativeTo(null);
f.setVisible(true);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
TripModelListener TripModelListener
package paranoid;
public interface TripModelListener {
void modelChanged();
}
Trip2 (the ui) Trip2(ui)
package paranoid;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Trip2 extends JPanel {
private static final long serialVersionUID = 1L;
private TripModel model;
public void paint(Graphics g){
g.setColor(Color.BLACK);
g.fillRect(model.getXMin(), model.getYMin(), model.getXMax(), model.getYMax());
for (int j = 0; j < 280; j++) {
for (int i = 0; i < 500; i++) {
if (model.getScreen()[i][j] == 0) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.GREEN);
}
g.drawLine(i, j, i, j); //plots pixel
}
}
}
public void setModel(TripModel model) {
this.model = model;
}
}//en
The Trip Model 旅行模型
package paranoid;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class TripModel {
private List<TripModelListener> listeners = new CopyOnWriteArrayList<TripModelListener>();
private int xmin = 0,
xmax = 499,
ymin = 0,
ymax = 279;
private int x = 120;
private int y = 80;
private int dx = 1;
private int dy = 1;
private int temp = 0;
private int update_counter = 0;
private int x_pos[] = new int[6];
private int y_pos[] = new int[6];
private int screen[][] = new int[500][280];
public TripModel() {
initialisation();
}
public void initialisation(){
System.out.println("initialising...");
x_pos[0] = x;
y_pos[0] = y;
x_pos[1] = xmax - x;
y_pos[1] = y;
x_pos[2] = x;
y_pos[2] = ymax - y;
x_pos[3] = xmax - x;
y_pos[3] = ymax - y;
x_pos[4] = (int)(xmax/2)-50;
y_pos[4] = (int)(ymax/2);
x_pos[5] = (int)(xmax/2)+50;
y_pos[5] = (int)(ymax/2);
for(int j = 0; j<280; j++){
for(int i = 0; i<500; i++){
screen[i][j] = 0;
}
}
} //end of initialisation()
public void update(){
//System.out.println("updating... for the "+update_counter+"th time");
temp = (int)Math.floor(Math.random()*100);
if(temp < 40){ // 40% chance that the direction is changed
dx = (int)Math.floor(Math.random()*3);
dy = (int)Math.floor(Math.random()*3);
dx = dx - 1;
dy = dy - 1;
}
x_pos[0] = x_pos[0]+dx;
y_pos[0] = y_pos[0]+dy;
x_pos[1] = x_pos[1]-dx;
y_pos[1] = y_pos[1]+dy;
x_pos[2] = x_pos[2]+dx;
y_pos[2] = y_pos[2]-dy;
x_pos[3] = x_pos[3]-dx;
y_pos[3] = y_pos[3]-dy;
x_pos[4] = x_pos[4]-dy;
y_pos[4] = y_pos[4]-dx;
x_pos[5] = x_pos[5]+dy;
y_pos[5] = y_pos[5]+dx;
for(int k = 0; k < 6; k++){
if(x_pos[k] < 0){
x_pos[k] = 0;
}
if(x_pos[k] > 499){
x_pos[k] = 499;
}
}
for(int k = 0; k < 6; k++){
if(y_pos[k] < 0){
y_pos[k] = 0;
}
if(y_pos[k] > 279){
y_pos[k] = 279;
}
}
screen[x_pos[0]][y_pos[0]] = 1;
screen[x_pos[1]][y_pos[1]] = 1;
screen[x_pos[2]][y_pos[2]] = 1;
screen[x_pos[3]][y_pos[3]] = 1;
screen[x_pos[4]][y_pos[4]] = 1;
screen[x_pos[5]][y_pos[5]] = 1;
update_counter = update_counter + 1;
fireModelChangedListener();
} //end of update()
private void fireModelChangedListener() {
for (TripModelListener listener : listeners) {
listener.modelChanged();
}
}
public int getXMin() {
return xmin;
}
public int getYMin() {
return ymin;
}
public int getYmin() {
return ymin;
}
public void setYmin(int ymin) {
this.ymin = ymin;
}
public int getXMax() {
return xmax;
}
public int getXmax() {
return xmax;
}
public void setXmax(int xmax) {
this.xmax = xmax;
}
public int getYMax() {
return ymax;
}
public int[][] getScreen() {
return screen;
}
public void addListener( TripModelListener listener) {
listeners.add(listener);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.