gpt4 book ai didi

Java Jpanel重画/更新问题

转载 作者:行者123 更新时间:2023-11-30 03:39:29 24 4
gpt4 key购买 nike

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

我有 5 节课:主要:运行 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();
}
}
}

View :

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

Controller :

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 中的按钮消失

重新绘制的图像 here更新图像 here

提前谢谢

最佳答案

我不能说我已经阅读了您所有的代码,但您的模型从未通知 View 。我的意思是模型类代码中没有调用 notifyView() 方法。模型有责任在其状态发生更改时调用此函数。

请注意:

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

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

此外,您的模型还包含 View 组件、Car 的 ArrayList、扩展 JPanel 的类,这是另一件永远不应该发生的事情,因为模型应该完全不知道 View ,但它知道某些事情可能会发生正在听它,它需要通知那些事情,仅此而已。相反,您的模型应该保存非 View 、非 JPanel 逻辑 Car 对象的 ArrayList。

<小时/>

编辑
您声明:

In the model i have the method: public void notifyView() which is called by the car's method public void Move() , That means whenever the thread calls the move method of the car, it calls the notifyView of the model

不,汽车不应该调用此方法 - 只有模型本身应该在其状态更改时调用此方法。

此外,我发现您使用 Thread#suspend()Thread#resume() 方法调用编写了非常危险的代码。这些方法已被弃用,因为它们被发现很危险。要了解原因,请查看API for Thread以及this useful article 。您肯定会希望避免使用它们。

<小时/>

建议

  • 使 Car 成为一个逻辑非 GUI 类,该类知道其位置并可以更改其位置。
  • 重写您的绘图 JPanels protected void PaintComonent(Graphics g) 方法并使用模型中的汽车信息来绘制汽车。换句话说,使用模型的状态来影响 View 的状态。
  • 使用 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 组件的另一个原因——避免这些隐藏的副作用。

删除或重命名这些方法。

关于Java Jpanel重画/更新问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27093808/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com