如何在jpanel之间切换?

时间:2014-02-06 01:52:00

标签: java swing jframe jpanel awt

我仍然是java编程的新手,所以请帮助我纠正我可能忽略的任何错误或提供有关如何改进此程序的提示。

好的,所以很多问题都解决了,现在我有了一个CardLayout,但我仍然对如何让我的管道显示在里面有疑问。

当我尝试添加刷新率计时器和速度计时器时,我遇到了如何声明和初始化布尔变量的问题。

此外,当我编译并运行此游戏时,我会收到Game$1.class等文件。有没有办法让我清理它,有人可以解释为什么会这样吗?这些对成品有影响吗? (当游戏编译并打包成JAR时。)

我想在点击播放按钮时将playerIsReady设置为true。从那里,当if语句为真时,然后切换到显示管道的面板,并开始在屏幕上移动管道。最好是3个管道的实例,每个实例在不同的时间开始,但无论你能提供什么帮助都很好。

这些代码中的一些需要工作,所以我已经评论了一些部分并留下了笔记。

我可以找到关于此游戏的其他问题here

这是我的当前代码

Game.java

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import javax.swing.SwingUtilities;

public class Game {

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {             
                // the GUI as seen by the user (without frame)
                final CardLayout cl = new CardLayout();
                final JPanel gui = new JPanel(cl);
                // remove if no border is needed
                gui.setBorder(new EmptyBorder(10,10,10,10));

                JPanel menu = new JPanel(new GridBagLayout());
                JButton playGame = new JButton("Play!");
                ActionListener playGameListener = new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        cl.show(gui, "game");
                    }
                };
                playGame.addActionListener(playGameListener);
                Insets margin = new Insets(20, 50, 20, 50);
                playGame.setMargin(margin);
                menu.add(playGame);
                gui.add(menu);
                cl.addLayoutComponent(menu, "menu");

                final JPanel pipes = new Pipes();
                gui.add(pipes);
                cl.addLayoutComponent(pipes, "game");

                JFrame f = new JFrame("Pipes Game");
                f.add(gui);
                // Ensures JVM closes after frame(s) closed and
                // all non-daemon threads are finished
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                // See https://stackoverflow.com/a/7143398/418556 for demo.
                f.setLocationByPlatform(true);

                // ensures the frame is the minimum size it needs to be
                // in order display the components within it
                f.pack();
                // should be done last, to avoid flickering, moving,
                // resizing artifacts.
                f.setVisible(true);

                /*if (playerIsReady) { 
                    Timer speed = new Timer(10, new ActionListener() {  //pipe speed
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            pipes.move();
                        }
                    });
                    speed.start();

                    Timer refresh = new Timer(30, new ActionListener() {    //refresh rate
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            pipes.repaint();
                        }
                    });
                    refresh.start();
                }*/
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}

Pipes.java

// What import(s) do I need for ArrayList?
public class Pipes {
    List<Pipe> pipes = new ArrayList<Pipe>();

    public Pipes() {
        pipes.add(new Pipe(50, 100));
        pipes.add(new Pipe(150, 100));
        pipes.add(new Pipe(250, 100));
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        for ( Pipe pipe : pipes ){
            pipe.drawPipe(g);
        }
    }
}

PipeObject.java

import java.awt.Graphics;

public class PipeObject {
    //Declare and initialiaze variables
    int x1 = 754;               //xVal start
    int x2 = 75;                //pipe width
                                //total width is 83
    int y1 = -1;                //yVal start
    int y2 = setHeightVal();    //pipe height
    int gap = 130;              //gap height

    public void drawPipe(Graphics g) {

        g.clearRect(0,0,750,500);                       //Clear screen
        g.drawRect(x1,y1,x2,y2);                        //Draw part 1
        g.drawRect(x1-3,y2-1,x2+6,25);                  //Draw part 2
        g.drawRect(x1-3,y2+25+gap,x2+6,25);             //Draw part 3
        g.drawRect(x1,y2+25+gap+25,x2,500-y2-49-gap);   //Draw part 4
    }

    public void move() {
        x1--;
    }

    public int getMyX() {   //To determine where the pipe is horizontally
        return x1-3;
    }

    public int getMyY() {   //To determine where the pipe is vertically
        return y2+25;
    }

    public int setHeightVal() {     //Get a random number and select a preset height
        int num = (int)(9*Math.random() + 1);
        int val = 0;
        if (num == 9)
        {
            val = 295;
        }
        else if (num == 8)
        {
            val = 246;
        }
        else if (num == 7)
        {
            val = 216;
        }
        else if (num == 6)
        {
            val = 185;
        }
        else if (num == 5)
        {
            val = 156;
        }
        else if (num == 4)
        {
            val = 125;
        }
        else if (num == 3)
        {
            val = 96;
        }
        else if (num == 2)
        {
            val = 66;
        }
        else
        {
            val = 25;
        }
        return val;
    }
}

3 个答案:

答案 0 :(得分:6)

解决此问题的最佳方法是使用CardLayout

enter image description here

enter image description here

备注

  • ActionListener的按钮远远优于矩形的MouseListener
    • 当鼠标指向该按钮时,该按钮将显示焦点,或者通过键盘将该组件标记为。
    • 该按钮可通过键盘访问。
    • 该按钮具有支持内置多个图标的功能(例如,用于“初始外观”,聚焦,按下等)。
  • 通过添加EmptyBorder
  • 在菜单面板和游戏周围提供GUI中的空白区域
  • 通过设置边距使按钮变大。
  • 根据需要调整边距,边框和首选尺寸。这些尺寸是由我设定的,以免使截图过大。
  • 请参阅代码注释中的更多提示。

代码

以下是生成上述屏幕截图的MCTaRE(最小完整测试和可读示例)。

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class PipesGame {

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                // the GUI as seen by the user (without frame)
                final CardLayout cl = new CardLayout();
                final JPanel gui = new JPanel(cl);
                // remove if no border is needed
                gui.setBorder(new EmptyBorder(10,10,10,10));

                JPanel menu = new JPanel(new GridBagLayout());
                JButton playGame = new JButton("Play!");
                ActionListener playGameListener = new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        cl.show(gui, "game");
                    }
                };
                playGame.addActionListener(playGameListener);
                Insets margin = new Insets(20, 50, 20, 50);
                playGame.setMargin(margin);
                menu.add(playGame);
                gui.add(menu);
                cl.addLayoutComponent(menu, "menu");

                JPanel pipes = new Pipes();
                gui.add(pipes);
                cl.addLayoutComponent(pipes, "game");

                JFrame f = new JFrame("Pipes Game");
                f.add(gui);
                // Ensures JVM closes after frame(s) closed and
                // all non-daemon threads are finished
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                // See https://stackoverflow.com/a/7143398/418556 for demo.
                f.setLocationByPlatform(true);

                // ensures the frame is the minimum size it needs to be
                // in order display the components within it
                f.pack();
                // should be done last, to avoid flickering, moving,
                // resizing artifacts.
                f.setVisible(true);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}

class Pipes extends JPanel {

    Pipes() {
        setBackground(Color.BLACK);
        setForeground(Color.WHITE);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawString("Pipes game appears here..", 170, 80);
    }

    @Override 
    public Dimension getPreferredSize() {
        // adjust to need
        return new Dimension(500,150);
    }
}

答案 1 :(得分:5)

  

“我有没有办法将我的GameMenu jpanel添加到我的jframe中,然后用Pipes jpanel替换它?”

正如其他人所建议的那样,你需要一个CardLayout。这对你来说很简单。就个人而言,我总是将CardLayout包裹在JPanel而不是JFrame,只是习惯的力量。

您要做的是拥有mainPanel

CardLayout
CardLayout card = new CardLayout();
JPanel mainPanel = new JPanel();

然后您要将面板添加到mainPanelCardLyaout所做的是图层面板,一次只能显示一个。您添加的第一个将在前景中。此外,当您添加面板时,您还需要发出一个,可以从中调用它。键,可以是你喜欢的任何字符串。

mainPanel.add(gameMenu, "menu");
mainPnael.add(pipes, "pipe");

现在gameMenu是显示的唯一面板。要显示pipes,您所做的只是使用此方法

所以你要使用card.show(mainPanel, "pipes");

即使您想要触发pipes的显示,也只需在该事件处理程序中添加该行。您可以在GameMenu添加一个按钮或其他内容,以便移动到Pipes面板。

答案 2 :(得分:3)

这可以在菜单上单击鼠标。您可以稍后更改,点击某个按钮或任何您想要的内容。

我在MouseListener课程中添加了Game。当用户在menu JPanel上按下鼠标时,会将Pipes JPanel添加到JFrame并调用pack方法。

Game.java:

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Game {

    GameMenu menu = new GameMenu();
    Pipes game;
    boolean start = false;
    JFrame f;
    Rectangle2D menuRect = new Rectangle2D.Double(20, 20, 60, 40);

    public Game() {
        f = new JFrame();

        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(menu);
        f.setTitle("Pipe Game");
        f.setResizable(false);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);



        menu.addMouseListener(new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {

                Point click = new Point(e.getX(), e.getY());
                System.out.println("Clicked on the Panel");

                if(menuRect.contains(click))
                {
                    System.out.println("Clicked inside the Rectangle.");

                    start = true; 
                    menu.setVisible(false);
                    game = new Pipes();
                    f.add(game);
                    f.pack();

                    Timer timer = new Timer(10, new ActionListener() {  //pipe speed
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            game.move();
                        }
                    });
                    timer.start();

                    Timer refresh = new Timer(30, new ActionListener() {    //refresh rate
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            game.repaint();
                        }
                    });
                    refresh.start();   
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
            }
        });

    }

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Game();
            }
        });
    }
}