簡體   English   中英

如何在Java中的for循環中的每個update()之后強制重繪()?

[英]How can I force a repaint() after every update() in a for loop in Java?

我寫了一個小的,基本的,萬花筒類型的程序,應該在六個不同的點和不同的方向逐漸繪制相同的模式(隨着時間的推移)。

為此,我創建了一個數組來存儲每個像素的顏色(它的初始顏色是黑色,用數字0表示),然后數組中的6個起始點的顏色變為綠色(由數字1表示)。 這些點應出現在屏幕上,然后根據之前的6個點位置創建另外6個點。 然后應顯示更新的屏幕。 重復,重復,重復......

我的問題是,在繪制屏幕之前,所有針對新像素的更新都在執行。 我已經檢查了一些其他帖子和網絡教程等,並收集AWT是足夠的,以避免浪費時間重新繪制微小的變化。 似乎還有一些叫做paintManager東西。 我相信問題是我在for循環中重新繪制。 我發現這非常令人沮喪,因為在我看來,這應該是一件簡單的事情。 確實有一種簡單的方法來說服java以我想要的方式描繪這些微小的變化嗎?

我已將代碼全部包含在下面:

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

    }

}

和...

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

發生了什么事情,你被困在你的for-loop直到它完成處理然后你重繪。 您應該做的是,因為您正在擴展JPanel ,所以您可以訪問Component的paintComponent方法,該方法在您第一次繪制和重新繪制組件時調用。

像那樣

@Override
public void paintComponent(Graphics g) {

}

而不是你的

public void paint(Graphics g) {

}

但是,當您覆蓋paintComponent時,您需要確保將其稱為parent的paintComponent

像這樣:

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
}

當我們在這里時,我們可以在你的所有繪畫之前或之后調用你的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.
}

一定要刪除for循環; 當然,如果你想在繪圖之前獲得大量數據,你可以隨時保留它。

如果你真的想要你可以保持完全相同的代碼,但遵循我上面所說的類似模式。

像這樣:

public void paint(Graphics g) {
    update();


    // All of your painting methodology


    repaint(); // Force the component to repaint so this gets called over and over.
}

這里的一個主要問題是你在paint方法中調用Thread.sleep() - 這不是一個好主意,因為將停止在那段時間內進一步重新繪制你的應用程序。 (事件調度線程/繪圖線程不得用於任何慢速操作)

您希望在此處實現的通常流程如下(可能比您需要的更詳細):

  1. 創建一個包含所有數字變量的模型類,特別您的數字(沒有UI代碼)也創建各種getter以允許UI稍后訪問這些數字。
  2. 允許將此模型類傳遞給視圖類(在您的情況下為Trip1 )並設置為實例變量。
  3. 從主控制類創建一個新的線程或計時器,根據需要定期調整您的型號/內部。
  4. 為模型上的更改創建一個偵聽器interface (例如ModelChangedListener等)
  5. 在模型中添加一個監聽器列表 - 使用register方法簡單地將監聽器添加到列表中。
  6. 使模型的任何更改,即數字更新時,這些都會激活已注冊的偵聽器。
  7. 在你的主控制類中,為這個模型注冊一個監聽器, trip2Panel.repaint();調用: trip2Panel.repaint();

  8. 在面板的paint()方法中......只需繪制當前的模型。

完整代碼發布:

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

package paranoid;

public interface TripModelListener {
    void modelChanged();
}

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

旅行模型

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