简体   繁体   English

如何在Java中的for循环中的每个update()之后强制重绘()?

[英]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): 您希望在此处实现的通常流程如下(可能比您需要的更详细):

  1. Create a model class that contains all your number variables and specifically just your numbers (no UI code) also create various getters to allow the UI to access these numbers later. 创建一个包含所有数字变量的模型类,特别您的数字(没有UI代码)也创建各种getter以允许UI稍后访问这些数字。
  2. Allow this model class to be passed to the view class ( Trip1 in your case) and set to an instance variable. 允许将此模型类传递给视图类(在您的情况下为Trip1 )并设置为实例变量。
  3. Create a new Thread or Timer from the main controlling class that periodically adjusts your model numbers/internals as you desire. 从主控制类创建一个新的线程或计时器,根据需要定期调整您的型号/内部。
  4. Create a listener interface for changes on your model. 为模型上的更改创建一个侦听器interface (eg ModelChangedListener or such like) (例如ModelChangedListener等)
  5. Add in a list of listeners to your model - with a register method to simply add a listener to the list. 在模型中添加一个监听器列表 - 使用register方法简单地将监听器添加到列表中。
  6. Make it such that any changes to your model ie when numbers are updated, these fire calls to the registered listeners. 使模型的任何更改,即数字更新时,这些都会激活已注册的侦听器。
  7. In your main controlling class, register a listener to this model which solely calls: trip2Panel.repaint(); 在你的主控制类中,为这个模型注册一个监听器, trip2Panel.repaint();调用: trip2Panel.repaint();

  8. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM