Как я могу переключаться между 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 3

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, который будет иметь CardLayout

CardLayout 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();
            }
        });
    }
}