繁体   English   中英

Java Jpanel重涂/更新问题

[英]Java Jpanel Repaint/update probleme

我对jpanel的Repaint方法有问题。 我正在尝试使用Java Swing并遵循MVC架构来制作“赛车比赛”:

我有5个班级:Main:运行MVC

public class Main {
    private static Model model;
    private static View view;
    private static Controller controller;

    public static void main(String[] args) {
        model = new Model();
        view =  new View();
        controller = new Controller();

        model.addObserver(view);

        controller.addModule(model);
        controller.addView(view);

        view.addContoller(controller);
    }
}

型号:

import java.util.ArrayList;
import java.util.Observable;


public class Model extends Observable{
    private ArrayList<Car> cars;// List of cars

    public Model() {
        cars = new ArrayList<Car>();
        cars.add(new Car(this,0, 50));
        cars.add(new Car(this,0, 50));
        cars.add(new Car(this,0, 50));
    }

    public void startCar(int i){
        //i is the index of the selected element in the checkbox
        //if i==0 then the selected element is "All cars" else is a specific car
        if(i>0)
            cars.get(i-1).start();
        else{
            for(int j=0;j<cars.size();j++)
                cars.get(j).start();
        }
    }

    public void speedUpCar(int i) {
        if(i>0)
            cars.get(i-1).incVitess();
        else{
            for(int j=0;j<cars.size();j++)
                cars.get(j).incVitess();
        }
    }

    public void notifyView(){
        setChanged();
        notifyObservers(cars);
    }

    public void speedDownCar(int i) {
        if(i>0)
            cars.get(i-1).decVitess();
        else{
            for(int j=0;j<cars.size();j++)
                cars.get(j).decVitess();
        }
    }

    public void stopCar(int i) {
        if(i>0)
            cars.get(i-1).stop();
        else{
            for(int j=0;j<cars.size();j++)
                cars.get(j).stop();
        }
    }
}

风景 :

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class View implements Observer {
    private JFrame fen;
    private JPanel btnPanel,panel;
    private JButton play,speedUp,speedDown,stop;
    private JComboBox<String> listeCar;
    private boolean test = false;

    public View() {
        fen = new JFrame();
        fen.setTitle("Car Racing");
        fen.setSize(900, 400);
        fen.setLocationRelativeTo(null);
        fen.setResizable(false);

        Vector<String> v = new Vector<String>();
        v.add("All cars");v.add("car 1");v.add("car 2");v.add("car 3");
        listeCar = new JComboBox<String>(v);

        play = new JButton("Play");
        speedUp = new JButton("+");
        speedDown = new JButton("-");
        stop = new JButton("stop");

        panel = new JPanel(new GridLayout(3,1));
        btnPanel = new JPanel();

        btnPanel.add(listeCar);
        btnPanel.add(play);
        btnPanel.add(speedUp);
        btnPanel.add(speedDown);
        btnPanel.add(stop);

        Container c = fen.getContentPane();

        c.setLayout(new BorderLayout());

        c.add(btnPanel, BorderLayout.SOUTH);
        c.add(panel, BorderLayout.CENTER);

        fen.setVisible(true);

        fen.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });


    }

    public void addContoller(Controller controller){
        play.addActionListener(controller);
        speedUp.addActionListener(controller);
        speedDown.addActionListener(controller);
        stop.addActionListener(controller);
    }

    @Override
    public void update(Observable arg0, Object c) {
        ArrayList<Car> cars = (ArrayList<Car>)c;
        for(int i=0;i<cars.size();i++){
            Car car = cars.get(i);
            if(!test){ // if its the first tima, add the cars to the panel
                panel.add(car);
            }else{
                car.repaint(); // << the Problem is HERE
            }
        }
        test = true;
    }

    public JButton getPlay() {
        return play;
    }

    public JButton getSpeedUp() {
        return speedUp;
    }

    public JButton getSpeedDown() {
        return speedDown;
    }

    public JButton getStop() {
        return stop;
    }

    public JComboBox<String> getListeCar() {
        return listeCar;
    }
}

控制器:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class Controller implements ActionListener{
    private Model model;
    private View view;

    public Controller() {

    }

    public void addModule(Model m) {
        model = m;
        model.notifyView();
    }

    public void addView(View v){
        view = v;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == view.getPlay()){
            model.startCar(view.getListeCar().getSelectedIndex());
        }else if(e.getSource() == view.getSpeedUp()){
            model.speedUpCar(view.getListeCar().getSelectedIndex());
        }else if(e.getSource() == view.getSpeedDown()){
            model.speedDownCar(view.getListeCar().getSelectedIndex());
        }else if(e.getSource() == view.getStop()){
            model.stopCar(view.getListeCar().getSelectedIndex());
        }
    }
}

车类:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;


public class Car extends JPanel{
    private int id,x,y,vitess;
    private Thread thread;
    private Model model;
    private boolean start = true;
    private boolean forward = true;
    private Color color;
    private boolean threadStarted = false;
    private BufferedImage bg; // background image

    public Car(Model model,int x,int y) {
        this.x =x;
        this.y = y;
        vitess = 7;
        this.model = model;

        try {
            bg = ImageIO.read(new File("road.png"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        color = changeColor(); // Random color

        thread = new Thread(new CarThread(this));

        start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(bg, 0, 0, null); 
        g.setColor(color);
        g.fillRect(x, y, 100, 50); // the car is a simple rectangle
    }

    public void start() {
        start = true;
        if(!threadStarted){
            threadStarted = true;
            thread.start();
        }else{
            thread.resume();
        }
    }

    public void move(){
        System.out.println("X:"+x);
        if(forward){
            if(x<this.getWidth()){
                x+=2;
            }else{
                color = changeColor();
                forward = false;
            }
        }else{
            if(x>0){
                x-=2;
            }else{
                color = changeColor();
                forward = true;
            }
        }

        model.notifyView();
    }

    private Color changeColor() {
        int r = (int)(Math.random()*255);
        int g = (int)(Math.random()*255);
        int b = (int)(Math.random()*255);
        return new Color(r,g,b);
    }

    public void stop(){
        start = false;
        thread.suspend();
    }

    public void incVitess(){
        if(vitess>1)
            vitess--;
    }

    public void decVitess(){
        if(vitess<6)
            vitess++;
    }

    public int getId() {
        return id;
    }


    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getVitess() {
        return vitess;
    }   

    public boolean getStart(){
        return start;
    }

    public void setStart(boolean m){
        this.start = m;
    }

    public Color getColor(){
        return color;
    }
}

CarThraed课程:

public class CarThread implements Runnable{
    private Car car;

    public CarThread(Car car) {
        this.car = car;
    }

    @Override
    public void run() {
        while(car.getStart()){
            car.move();
            try {
                Thread.sleep(car.getVitess());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

如果您运行该项目,则将注意,即使使用这些汽车,它们也不会到达框架的末端:

if(x<this.getWidth()) x++;

但是当我更换

car.repaint(); // << the Problem is HERE

car.update(car.getGraphics()); // << the Problem is HERE

现在,汽车可以到达车架的尽头了,但是btnJpanel中的按钮消失了

图像在这里重画图像在这里更新

先感谢您

我不能说我已经阅读了所有代码,但是您的模型从不通知视图。 我的意思是,在模型类的代码中,没有地方调用notifyView()方法。 每当其状态发生更改时,模型都有责任调用它。

注意:

car.update(car.getGraphics()); // << the Problem is HERE

不应使用,因为获得的图形不稳定。

此外,您的模型包含视图组件,Car的ArrayList,扩展JPanel的类,不应发生的另一件事,因为模型应完全不了解视图,但它知道某些内容可能正在侦听它,它需要通知那些事情,仅此而已。 相反,您的模型应该包含一个非视图,非JPanel逻辑Car对象的ArrayList。


编辑
您声明:

在模型中,我有方法:public void notifyView()由汽车的方法调用public void Move(),这意味着每当线程调用汽车的move方法时,它都会调用模型的notifyView

不,Car不应调用此方法,只有模型本身在状态更改时才应调用此方法。

另外,我看到使用Thread#suspend()Thread#resume()方法调用的代码非常危险。 这些方法被认为是危险的,因此已被弃用。 要找出原因,请查看Thread API这篇有用的文章 您绝对肯定会避免使用它们。


建议

  • 使Car成为逻辑非GUI类,该类知道其位置并且可以更改其位置。
  • 覆盖图形JPanels protected void paintComonent(Graphics g)方法,并使用模型中的Car信息绘制Cars。 换句话说,使用模型的状态来影响视图的状态。
  • 使用Swing Timer而不是后台线程来更改您的汽车位置。
  • 让模型并且只有模型在状态改变时才调用notifyView方法。

编辑
您的主要错误在这里:

class Car extends JPanel {
    private int id, x, y, vitess;

    //....

    public int getX() {
       return x;
    }

    public int getY() {
       return y;
    }

您无意间覆盖了Car JPanel的getX和getY方法,从而弄乱了这些组件的位置。 这是避免除非必要而覆盖Swing组件的另一个原因-避免这些隐藏的副作用。

摆脱或重命名这些方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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