如何在jpanel之间切换?

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

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

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

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

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

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

我可以在这里找到关于这个游戏的其他问题。

这是我目前的代码

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 pipes = new ArrayList(); 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; } } 

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

在此处输入图像描述

在此处输入图像描述

笔记

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

以下是产生上述屏幕截图的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); } } 

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

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

你想要做的是有一个将有CardLayoutmainPanel

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

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

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

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

  • public void show(Container parent, String name) – 使用addLayoutComponent翻转到使用指定name添加到此布局的parent 。 如果不存在这样的组件,则没有任何反应。

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

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

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

我在Game类中添加了一个MouseListener 。 当用户在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(); } }); } }