gpt4 book ai didi

java - GUI 未正确更新,组件消失

转载 作者:行者123 更新时间:2023-12-02 05:48:09 24 4
gpt4 key购买 nike

我已经为这个问题苦苦挣扎了一个多星期了,非常感谢您的帮助。我正在使用 GUI 开发我的第一个 Java 游戏,目前涉及大约 20 个类。该游戏是《星际迷航》的简单基于网格的表示,JLabel 图标在星系网格中移动。问题是,通常在大约 7 到 10 次移动之后,会发生以下两种情况之一:其一,我当前象限中的扇区网格将消失,仅在左上角留下一个扇区;一两次,企业图标将消失。

我没有处理线程的经验,但经过一些阅读后,我认为这可能是事件调度线程未与程序逻辑正确同步的结果。我阅读了更新 GUI 的正确方法,并用 invokeLater 和 invokeAndWait block 包围了对 GUI 有任何影响的所有语句(我认为)。

但是,这并没有解决问题。所以,今天我将所有内容重写为我能做到的最小可编译单元(它不是那么小,但我不知道如何使其更小),同时仍然保留我的基本游戏结构,看看这是否会改变任何东西。事实并非如此。 7 到 10 次移动后,GUI 仍然会损坏。

我已经无计可施了。如果您能提供一些帮助,我将不胜感激。

这是我的代码。它按原样编译并运行。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import javax.swing.SwingUtilities;
import javax.swing.border.BevelBorder;


public class GUI extends JFrame
{
int screenwidth;
int screenheight;

public static void main(String[] args)
{
GUI gui = new GUI();
run(gui);

}

public static void run(final GUI gui)
{
Quadrant[][] galaxy = new Quadrant[8][8];

//populate galaxy with quadrants
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
galaxy[i][j] = new Quadrant(i, j);
}

}


//Quadrant to put in the view when game starts
Quadrant startingQuadrant = galaxy[0][0];
final QuadrantView quadrantView = startingQuadrant.getQuadrantView();

Enterprise enterprise;
Sector startingSector;

//add SectorViews to the QuadrantView
for (int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
startingQuadrant.getQuadrantView().addSectorView(startingQuadrant.getSectorArray()[i][j].getSectorView(), i, j);
}
}



SwingUtilities.invokeLater(new Runnable() {


@Override
public void run() {

//initialize gui with the starting quadrant quadrantView
gui.intiGUI(quadrantView);
}

});

//start on sector (0, 0)
startingSector = startingQuadrant.getSectorArray()[0][0];
enterprise = new Enterprise(startingQuadrant, startingSector);
startingSector.setContainsEnterprise(true);

Scanner input = new Scanner(System.in);
Sector destinationSector;

int qRow; //destination quadrant row
int qCol; //destination quadrant column
int sRow; //destination sector row
int sCol; //destination sector column

while(true)
{
System.out.println("Enter quadrant row: ");
qRow = input.nextInt();

System.out.println("Enter quadrant column: ");
qCol = input.nextInt();

System.out.println("Enter sector row: ");
sRow = input.nextInt();

System.out.println("Enter sector column: ");
sCol = input.nextInt();


destinationSector = galaxy[qRow][qCol].getSectorArray()[sRow][sCol];
enterprise.move(destinationSector, galaxy[qRow][qCol], gui);

}

}

public GUI()
{
super("Star Trek");



//create an anonymous listener to close window and end game
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
dispose();
System.exit(0);
}
});

// get user's screen width and height
screenwidth = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth();
screenheight = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight();

//set layout
getContentPane().setLayout(new BorderLayout());

resizeGUI();
setVisible(true);
validate();

}

private void resizeGUI()
{
// set window size
if (screenwidth >= 1280)
setSize(1024, 768);
else if (screenwidth >= 1024)
setSize(800, 600);
else if (screenwidth >= 800)
setSize(640, 480);

// maximize window
setExtendedState(this.getExtendedState() | this.MAXIMIZED_BOTH);
}

//initialize this gui with the starting QuadrantView
public void intiGUI(QuadrantView quadrantView)
{
getContentPane().add(quadrantView, BorderLayout.CENTER);
validate();
}

//reset the gui to hold the new QuadrantView
public void resetGUI(QuadrantView newQuadrantView)
{
getContentPane().add(newQuadrantView, BorderLayout.CENTER);
validate();

}



static class Quadrant
{
private int row;
private int col;
private QuadrantView quadrantView;
private Sector[][] sectorArray;


public Quadrant(int r, int c)
{
// quadrant row
row = r;

// quadrant columns
col = c;

// the view object associated with this quadrant
setQuadrantView(new QuadrantView(8, 8));

// an array to hold the sectors in this quadrant (req. 3.1.0)
sectorArray = new Sector[8][8];


// create the 64 sectors in this quadrant and add them to the array (req. 3.1.0)
for (int i = 0; i < sectorArray.length; i ++)
{
for (int j = 0; j < sectorArray[i].length; j++)
{
sectorArray[i][j] = new Sector(i, j, this);
}
}
}

public int getRow()
{
return row;

}

public int getCol()
{
return col;

}

public void setRow(int r)
{
row = r;
}

public void setCol(int c)
{
col = c;
}

public Sector[][] getSectorArray()
{
return sectorArray;
}

public QuadrantView getQuadrantView()
{
return quadrantView;
}

public void setQuadrantView(QuadrantView quadrantView)
{
this.quadrantView = quadrantView;
}

}


static class Sector
{
//sector row
private int row;

//sector column
private int col;

//the quadrant this sector is in
private Quadrant quadrant;

//the view associated with this sector
private SectorView sectorView;

//boolean values to determine what this sector holds (Req. 4.1.0)
private boolean containsEnterprise;

//if the sector holds the Enterprise, store a reference to it
private Enterprise enterprise;

public Sector(int r, int c, Quadrant q)
{
row = r;
col = c;
quadrant = q;
setSectorView(new SectorView());
containsEnterprise = false;

//print the sector's coordinates on the gui
sectorView.setID(row + ", " + col);
}

public int getRow()
{
return row;

}

public int getCol()
{
return col;

}

public void setRow(int r)
{
row = r;
}

public void setCol(int c)
{
col = c;
}

public Quadrant getQuadrant()
{
return quadrant;
}


public boolean containsEnterprise()
{
return containsEnterprise;
}

public void setContainsEnterprise(boolean containsEnterprise)
{
this.containsEnterprise = containsEnterprise;
if (containsEnterprise)
{
sectorView.showEnterpriseIcon();
}
else
{
sectorView.hideEnterpriseIcon();
}
}

public Enterprise getEnterprise()
{
return enterprise;
}

public void addEnterprise(Enterprise enterprise)
{
this.enterprise = enterprise;
}

public void removeEnterprise()
{
enterprise = null;
}

public SectorView getSectorView()
{
return sectorView;
}

public void setSectorView(SectorView sectorView)
{
this.sectorView = sectorView;
}

public String toString()
{
return Integer.toString(row)+ "." + Integer.toString(col);
}
}
//end Sector class

static class SectorView extends JPanel
{

// default font for text
private final Font TREK_FONT = new Font("Verdana", Font.BOLD, 10);

// color for text
private final Color LABEL_COLOR = Color.BLACK;

// component layout
private SpringLayout layout;

// displays sector ID
private JLabel IDLabel;

//enterprise display
private JLabel enterpriseIcon;


/*
* create a new SectorView
*/
public SectorView()
{
super();

//create and set layout for child components
layout = new SpringLayout();
this.setLayout(layout);

//initialize child components
initComponents();

//position and display child components
layoutComponents();

//set background color
setBackground(Color.DARK_GRAY);

//set border
setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));

//set size of sectors
setPreferredSize(new Dimension(QuadrantView.SECTOR_SIZE, QuadrantView.SECTOR_SIZE));
}


/*
* initialize components
*/
private void initComponents()
{
// displays ID of this view
IDLabel = new JLabel("");
IDLabel.setFont(TREK_FONT);
IDLabel.setForeground(Color.WHITE);

// create an enterprise icon and make it invisible
enterpriseIcon = new JLabel("E");
enterpriseIcon.setForeground(Color.WHITE);
enterpriseIcon.setVisible(false);
}


/*
* lay out components and add them to this view
*/
private void layoutComponents()
{
// position components:

// ID label
layout.putConstraint(SpringLayout.WEST, IDLabel, 1, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, IDLabel, 1, SpringLayout.NORTH, this);


// enterprise icon
layout.putConstraint(SpringLayout.WEST, enterpriseIcon, 5, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, enterpriseIcon, 30, SpringLayout.NORTH, this);

// add to view
this.add(IDLabel);
this.add(enterpriseIcon);

}

public void showEnterpriseIcon()
{
enterpriseIcon.setVisible(true);
}

public void hideEnterpriseIcon()
{
enterpriseIcon.setVisible(false);
}


//the sector's (row, col) coordinates within the quadrant
public void setID(String id)
{
IDLabel.setText(id);
}

}
//end SectorView class

static class QuadrantView extends JPanel
{
//size of sectors
public final static int SECTOR_SIZE = 100;

private final Color BACKGROUND_COLOR = Color.DARK_GRAY;

private SpringLayout layout;


/*
* create a new QuadrantView with the specified width
* and height
*
* @param quadrantHeight height of quad. in sectors
* @param quadrantWidth width of quad. in secors
*/
public QuadrantView(int quadrantHeight, int quadrantWidth)
{
//call JPanel constructor
super();

//create and set the layout
layout = new SpringLayout();
setLayout(layout);

//set the size of the QuadrantView we are creating using the inherited JComponent method
setPreferredSize(new Dimension(quadrantWidth * SECTOR_SIZE, quadrantHeight * SECTOR_SIZE));

//set background color using the inherited JComponent method
setBackground(BACKGROUND_COLOR);
}

/*
* add the specified Sector to this view
*
* each sector is represented by a (row, column) pair
* @param sectorView SectorView to be added to the QuadrantView
* @param row row coordinate
* @param col column coordinate
*/
public void addSectorView(SectorView sectorView, int row, int col)
{
//position the sector
layout.putConstraint(SpringLayout.WEST, sectorView, col * SECTOR_SIZE, SpringLayout.WEST, this);
layout.putConstraint(SpringLayout.NORTH, sectorView, row * SECTOR_SIZE, SpringLayout.NORTH, this);

//add sectorView to the layout using inherited method of Container class
this.add(sectorView);

}

}

static class Enterprise
{
protected Sector sectorLocation;
protected Quadrant quadrantLocation;




public Enterprise(Quadrant quadrant, Sector sector)
{

sectorLocation = sector;
quadrantLocation = quadrant;

sector.addEnterprise(this);
sector.setContainsEnterprise(true);

}


// Requirement 9.4.0
public boolean move(Sector destinationSector, final Quadrant destinationQuadrant, final GUI gui)
{

//if the destination quadrant is not our current quadrant, we need to update the gui (is updating this way causing a problem?)
if (!destinationQuadrant.equals(this.quadrantLocation))
{
//Put the new SectorViews in the new quadrant.
for (int i = 0; i < 8; i++)
{
for(int j = 0; j < 8; j++)
{
destinationQuadrant.getQuadrantView().addSectorView(destinationQuadrant.getSectorArray()[i][j].getSectorView(), i, j);
}
}


SwingUtilities.invokeLater(new Runnable() {


@Override
public void run() {
//initialize gui with the starting quadrant quadrantView

//replace the old quadrant view with the new one
gui.resetGUI(destinationQuadrant.getQuadrantView());
}

});

}

//remove the reference to this starship from the current sector
sectorLocation.removeEnterprise();

//sector no longer contains the Enterprise
sectorLocation.setContainsEnterprise(false);

//move to destination quadrant
quadrantLocation = destinationQuadrant;

//move to destination sector
sectorLocation = destinationSector;

//add a reference to this starship to the new sector
sectorLocation.addEnterprise(this);

//new sector now contains Enterprise
sectorLocation.setContainsEnterprise(true);

return true;
}

}//end Enterprise class
}

最佳答案

  1. 限制线程之间交换的数据量。唯一需要交换的数据是键盘的输入。特别是避免在线程之间共享字段 - 这会导致竞争条件。您的主循环应如下所示:

    while(true)
    {
    final int qRow = input.nextInt();
    final int qCol = input.nextInt();
    final int sRow = input.nextInt();
    final int sCol = input.nextInt();

    SwingUtilities.invokeAndWait(new Runnable() {
    @Override
    public void run() {
    move(qRow,qCol,sRow,sCol);
    }
    });

    }
  2. 删除所有其他 invokeAndWaitinvokeLater。根本不要使用invokeLater。它使您的程序变得不可预测。

  3. 尝试在变量初始化之前声明变量并将其标记为final。可变状态会导致错误。

  4. 我无法弄清楚为什么表格缩小到 1x1。尝试使用 GridLayout 而不是 SpringLayout。它似乎更适合这种情况。

关于java - GUI 未正确更新,组件消失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23848756/

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