Как я могу переключаться между jpanels?
Я все еще очень новичок в программировании на java, поэтому, пожалуйста, помогите мне исправить любые ошибки, которые я мог бы упустить или дать советы о том, как улучшить эту программу.
Итак, многие проблемы были решены, и теперь у меня есть CardLayout, но у меня все еще есть вопросы о том, как я должен сделать так, чтобы мои трубы показывались внутри него.Когда я попытался добавить таймер частоты обновления и таймер скорости, у меня возникли проблемы с объявлением и инициализацией булевых переменных.
Также, когда я скомпилировав и запустив эту игру, я получаю такие файлы, как Game$1.class. Есть ли у меня способ убрать это, и может ли кто-нибудь объяснить, почему это происходит?  Влияют ли они на конечный продукт? (Когда игра собрана и упакована в банку.) 
Я хочу установить playerIsReady в true при нажатии кнопки play. И оттуда, когда оператор if истинен, переключитесь на панель, которая отображает трубы, и начните перемещать трубу по экрану. Предпочтительно 3 экземпляра этой трубы, каждый из них начинается в разное время, но все, что вы можете помочь, прекрасно.
Часть этого кода нуждается в доработке, поэтому я прокомментировал некоторые части и оставил заметки.
Мои другие вопросы об этой игре можно найти здесь.
Это мой текущий код
Игра.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);
    }
}
Трубы.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 ответа:
Лучший способ приблизиться к этому-использовать
CardLayout.
Примечания
- кнопка с
 ActionListenerнамного лучше, чемMouseListenerнад прямоугольником.
- кнопка будет показывать фокус, когда на нее наведена мышь, или компонент будет выбран с помощью клавиатуры.
 - кнопка доступна с клавиатуры.
 - кнопка имеет возможность поддерживать несколько встроенных иконок (например, для "начального взгляда", фокусировки, нажатия и т.д.)
 - пустое пространство в графическом интерфейсе обеспечивается вокруг панели меню и игры путем добавления
 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, просто в силу привычки.То, что вы хотите сделать, это иметь
mainPanel, который будет иметьCardLayoutCardLayout card = new CardLayout(); JPanel mainPanel = new JPanel();Затем вы хотите добавить свои панели в
mainPanel. То, что делаетCardLyaout, является слоем панели, делая только один видимым одновременно. Первый, который вы добавите, будет на переднем плане. Кроме того, когда вы добавляете панель, вы также захотите выдать ей ключ , из которого она может быть вызвана. Ключом может быть любая строка, которая вам нравится.mainPanel.add(gameMenu, "menu"); mainPnael.add(pipes, "pipe");Теперь
gameMenu- единственная показанная панель. Чтобы показатьpipes, все, что вы делаете, это используете этот метод
public void show(Container parent, String name)- переключается наparent, который был добавлен в этот макет с указаннымname, используя addLayoutComponent. Если нет такая составляющая существует, тогда ничего не происходит.Так что вы бы использовали,
card.show(mainPanel, "pipes");Все, что даже вы хотите вызвать показ
pipes, просто добавьте эту строку в этот обработчик событий. Вы можете добавить кнопку или что-то вGameMenu, что позволит перемещаться к панелиPipes.
Это работает с помощью щелчка мыши в меню. Вы можете изменить его позже, нажав на какую-нибудь кнопку или что вы хотите.
Я добавил
MouseListenerв классGame. Когда пользователь нажимает мышью наmenu JPanel, он добавляетPipes JPanelкJFrameи вызывает методpack.Игра.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(); } }); } }

