Как я могу переключаться между 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
, который будет иметь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(); } }); } }