JPanel在另一个JPanel中按下按钮后不显示

时间:2017-04-04 11:06:53

标签: java swing jpanel

您好我正在构建一个游戏,其中包括JFrame,Startscreen,DrawingPanel和GameOver屏幕上的3个JPanel。如果我只是创建DrawingPanel并告诉GameController类开始更新它工作正常,但如果我创建一个带按钮的StartScreen来启动游戏,那么当我按下开始游戏按钮时,游戏窗口不会显示,尽管游戏代码运行。

编辑:

我创建了一个模仿JPanels创建的新程序,但排除了所有游戏代码,使其更容易理解。下面我列出了所有相关课程:

此类创建一个JFrame和两个JPanel。它还运行代码来更新游戏状态并告诉DrawingPanel重新绘制。

    public class TestController{

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
private final int FRAME_WIDTH = (int)screenSize.getWidth();
private final int FRAME_HEIGHT = (int)screenSize.getHeight();
public boolean gameStarted = false;
private JFrame gameWindow;
private TestDrawingPanel myDrawingPanel;
private TestStartGame startGame;
int counter;
Set<Rectangle> rects;

//creates a JFrame and all the JPanels
public TestController(String title)
{

    gameWindow = new JFrame(title);
    gameWindow.setSize(FRAME_WIDTH, FRAME_HEIGHT);
    gameWindow.setVisible(true);
    gameWindow.setResizable(false);

    gameWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    startGame = new TestStartGame(getAvailableWidth(), getAvailableHeight());
    startGame.addAL(new StartButton());
    myDrawingPanel = new TestDrawingPanel(getAvailableWidth(), getAvailableHeight());
    gameWindow.add(startGame);
    gameWindow.add(myDrawingPanel);
    myDrawingPanel.setVisible(false);
    myDrawingPanel.setEnabled(false);
    rects = new HashSet();
}

private int getAvailableWidth()
{
    return gameWindow.getWidth() - gameWindow.getInsets().left - gameWindow.getInsets().right;
}

private int getAvailableHeight()
{
    return gameWindow.getHeight() - gameWindow.getInsets().top - gameWindow.getInsets().bottom;
}

//starts the game running
public void startTheGame()
{   

    myDrawingPanel.setEnabled(true);
    startGame.setVisible(false);
    startGame.setEnabled(false);
    myDrawingPanel.setVisible(true);
    gameStarted = true;
    update();
}

public boolean getGameStarted()
{
    return gameStarted;
}

//loop that runs the game code
public void update()
{
    counter = 0;
    while(gameStarted)
    {
        updatePictureState();

        myDrawingPanel.draw(rects);
        myDrawingPanel.repaint();                
    }
}

//updates the game state
public void updatePictureState()
{
    rects.clear();
    for (int i = counter + 10; i < counter + 100; i = i + 10)
    {
        rects.add(new Rectangle(i,i,10,10));
    }
}

//an action listener to be added to the start screen
private class StartButton implements ActionListener
{
    public void actionPerformed(ActionEvent e)
    {
        Object buttonPressed = e.getSource();

        if(buttonPressed.equals(TestStartGame.start))
        {
            startTheGame();
        }
    }
}
}

这个类是一个扩展的JPanel,只有一个按钮来启动游戏:

    public class TestStartGame extends JPanel{

private final JPanel buttons;
public static JButton start;

//creates a JPanel with a single button to start the game    
public TestStartGame(int width, int height)
{
    setSize(width, height);
    setLayout(new GridLayout(2,1));
    setBackground(Color.GREEN);

    buttons = new JPanel();
    buttons.setSize(width, height / 2);
    buttons.setBackground(Color.red);
    start = new JButton("Start");
    buttons.add(start);
    add(buttons, BorderLayout.SOUTH);
}            

//adds an action listener to the button    
public void addAL(ActionListener al)
{
    start.addActionListener(al);
}   
}

这个类是一个扩展的JPanel,作为游戏的主屏幕,在每个游戏周期更新到显示它的当前状态:

    public class TestDrawingPanel extends JPanel{
Set<Rectangle> drawSet;

//creates the drawing panel and sets the size and background
public TestDrawingPanel(int width, int height)
{                
    setSize(width, height);
    this.setBackground(Color.CYAN);

    drawSet = new HashSet();        
}


public void draw(Set<Rectangle> platforms)
{
    drawSet.clear();
    drawSet = platforms;
}

//draws the game window
@Override
public void paintComponent(Graphics g)
{
    super.paintComponent(g);
    System.out.println("works here");
    g.setColor(Color.red);
    for (Rectangle r : drawSet)
    {
        g.fillRect((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
    }
}    
}

如果我只是添加TestDrawingPanel,它显示正常,但如果我从TestStartScreen开始,那么当我单击开始游戏按钮时,TestStartScreen不会消失,并且TestDrawingPanel永远不会显示。有趣的是,如果我有两个屏幕,但没有调用更新方法是TestController,那么开始游戏按钮正常工作并显示TestDrawingPanel,但显然没有任何反应,因为更新方法是游戏状态改变的地方。

我发现问题是如果TestDrawingPanel不是唯一创建的JPanel,那么重绘它的调用将失败。

2 个答案:

答案 0 :(得分:0)

下面:

Thread.sleep(20);

你最有可能睡在Event Dispatcher Thread上。这会冻结整个申请。您必须退后一步并查看invokeLater以确保您的UI中的“正确”线程。

答案 1 :(得分:0)

问题解决了@ Andrew-Thompson的礼遇:

&#34; while(gameStarted)..不,没有一千次没有。无限循环可能会冻结GUI。使用基于Swing的Timer在ActionListener的actionPerformed方法中调用循环中的代码语句&#34;