【问题标题】:How do I move from one JFrame window to another on clicking the space bar?如何在单击空格键时从一个 JFrame 窗口移动到另一个窗口?
【发布时间】:2021-12-06 15:53:16
【问题描述】:

这是我创建主方法的主文件。我在此处添加了 JFrame 以使其更易于理解。我在第二个文件中创建了一个布尔变量,只要按下空格键,该变量就会更新为 true。然后我通过在主类中创建一个对象来使用该变量,然后添加条件语句以使 1 帧可见,反之亦然。

import javax.swing.JFrame;  

public class MainCode{
    public static void main(String args[]){  

        JFrame f=new JFrame();
        Gameplay GP = new Gameplay();

        GameplayLv2 g2 = new GameplayLv2();
        JFrame frame2 = new JFrame();


        
   
        f.setBounds(10,10,1000,700);
        f.setTitle("Breakout Ball");
        f.setResizable(false);
        f.setVisible(true);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(GP);


        if(GP.flagCheck==true){
        f.setVisible(false);
        f.remove(GP);

        frame2.setBounds(10,10,1000,700);
        frame2.setTitle("Breakout Ball");
        frame2.setResizable(false);
        frame2.setVisible(true);
        frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame2.add(g2);
        }           
        }

}

这是游戏文件,级别 1。我一直面临的问题是这段代码的底部,即 keyEvent 块。

import javax.swing.JPanel;
import java.awt.*;
import java.awt.Graphics2D;

import java.awt.Color;
import java.awt.Graphics;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

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

 public class Gameplay extends JPanel implements KeyListener, ActionListener{
     

     public boolean play=false;  //prevents game from starting on its own...
     public int score=0;        //scorebar will be 0 by default...

     public int totalBlocks = 30;  //no.of tiles/blocks player must knock down...

     public Timer speed;           //speed of ball...
     public int delay=5;           //speed of ball....

     public int playerX = 300;     //starting position of the slider..

     public int ballPosX = 210;    //starting position of the ball..(x-axis)
     public int ballPosY = 350;    //starting position of the ball..(y-axis)

     public int ballDirX = -1;     //direction for ball to start moving in...(x axis)
     public int ballDirY = -2;     //direction for ball to start moving in...(y axis) //ALSO CONTROLS SPEED OF BALL ALONG Y-AXIS

     public boolean flagCheck;
      
     MapGen map;

     Color ball_color = new Color(255, 252, 37);        //Setting custom colors for every element using RGB values...
     Color border_color = new Color(232, 20, 171);
     Color border2_color = new Color(20, 232, 213);
     Color slider_color = new Color(0, 240, 255);
     Color bg_color = new Color(11,10,30);
     Color tiles_color = new Color(255, 255, 255);

     JFrame frame1 = new JFrame();

    
     


    
    public Gameplay(){
         map = new MapGen(3,10);
         addKeyListener(this);
         setFocusable(true);
         setFocusTraversalKeysEnabled(false);
         speed = new Timer(delay,this);
         speed.start();  
         flagCheck = false; 
     }


     public void paint(Graphics g){

        g.setColor(bg_color);
        g.fillRect(1, 1, 1000, 700);
        
        //drawing the map(tiles)
        map.draw((Graphics2D)g);

        // adding borders so that whenever ball hits border, game ends..
         g.setColor(border_color);
         g.fillRect(0, 0, 10, 1000);

         g.setColor(border_color);
         g.fillRect(975, 0, 10, 1000);

         g.setColor(border2_color);
         g.fillRect(0, 0, 1000, 10);

        // editing the slider/player...
        g.setColor(slider_color);
        g.fillRect(playerX, 620, 120, 5);

        // editing the ball...
        g.setColor(ball_color);
        g.fillOval(ballPosX, ballPosY, 20, 20);

        //scoring system
        g.setColor(Color.white);
        g.setFont(new Font("helvetica", Font.BOLD, 20));
        g.drawString("SCORE:"+score, 800, 650);

        
        if(ballPosY>670){                                     //what'll happen when the ball moves out of screen?(anything after y-axis670)? This...
            play=false;
            ballDirX=0;
            ballDirY=0;

            g.setColor(bg_color);                          //this BG will act as a layer on top of the previous screen, hence, covering unnecessarry elements...
            g.fillRect(1, 1, 1000, 700);

            g.setColor(slider_color);
            g.setFont(new Font("helvetica", Font.BOLD, 25));     //scoreboard display after game ends..
            g.drawString("SCORE:"+score, 440, 200);
            
             g.setColor(slider_color); 
             g.setFont(new Font("helvetica", Font.BOLD, 40));     //game over text displayed after game ends..
             g.drawString("GAME OVER!", 370, 300);
            
            g.setColor(slider_color); 
            g.setFont(new Font("helvetica", Font.BOLD, 40));      //restart text displayed after game ends..
            g.drawString("Press enter to retry", 260, 405);
            

        }

        if(score==30){  //make it 150                                   //what'll happen when the score is 150, ie win
            play=false;
            ballDirX=210;
            ballDirY=350;
            

            g.setColor(bg_color);                          //this BG will act as a layer on top of the previous screen, hence, covering unnecessarry elements...
            g.fillRect(1, 1, 1000, 700);

            g.setColor(slider_color);
            g.setFont(new Font("helvetica", Font.BOLD, 25));     //scoreboard display after game ends..
            g.drawString("SCORE:"+score, 420, 200);
            
             g.setColor(slider_color); 
             g.setFont(new Font("helvetica", Font.BOLD, 40));     //game over text displayed after game ends..
             g.drawString("YOU WIN", 400, 300);
            
            g.setColor(slider_color); 
            g.setFont(new Font("helvetica", Font.BOLD, 40));      //go to next level text displayed after game ends..
            g.drawString("Press space to continue to next level", 155, 405);

        }
         
        g.dispose();
     }
      


     @Override
    public void actionPerformed(ActionEvent e) {
        speed.start();

        if(play==true){

            if(new Rectangle(ballPosX, ballPosY, 20, 20).intersects(new Rectangle(playerX, 620, 120, 10)))   
            //creates an invisible rectangle around the slider and ball which helps with interaction control
            {
                ballDirY=-ballDirY;
            }

            A: for(int i=0; i<map.map.length; i++){                        //one of the maps are MapGen map; while the other map is from @mapGen class to access the double dimensional array...
                for(int j=0; j<map.map[0].length; j++){
                    if(map.map[i][j]>0){
                        int tX = j*map.tW+80;
                        int tY = i*map.tH+50;
                        int tW = map.tW;
                        int tH = map.tH;

                        Rectangle rect = new Rectangle(tX, tY, tW, tH);                 //creates invisible rects around tiles to detect interaction with ball...
                        Rectangle ballRect = new Rectangle(ballPosX, ballPosY, 20, 20);
                        Rectangle tileRect = rect;

                        if(ballRect.intersects(tileRect)){                              //removes one triangle everytime interaction takes place and increases the score by 5...
                            map.setTileValue(0, i, j);
                            totalBlocks--;
                            score+=5;
                        

                        if(ballPosX+19 <= tileRect.x || ballPosX+1 >= tileRect.x + tileRect.width){    //specifies which direction the ball must head to after interacting with the tiles...
                            ballDirX=-ballDirX;
                        }
                        else{
                            ballDirY=-ballDirY;
                        }
                        break A;
                        }
                        
                    }

                }
            } 

        ballPosX+=ballDirX;
        ballPosY+=ballDirY;


         //specifies where the ball will have to shift position. In this case, on hitting either of the borders, position(x-y-coordinates) will change....
        if(ballPosX<0)
        ballDirX=-ballDirX;             
        if(ballPosY<0)
        ballDirY=-ballDirY;
        if(ballPosX>960)
        ballDirX=-ballDirX;      
        }

        repaint();                                    //will re-draw every element(slider etc)... 
    }


    @Override
    public void keyTyped(KeyEvent e) {}                 //unnecessarry methods that when removed produced error...so..yeah...
    @Override
    public void keyReleased(KeyEvent e) {}
    

    @Override
    public void keyPressed(KeyEvent e) {

        
        if(e.getKeyCode()==KeyEvent.VK_RIGHT)
        {
            if(playerX>=855)                  //prevents the paddle/slider from moving out of the screen
            playerX=855;

            else
            moveRight();

        }
        
        if(e.getKeyCode()==KeyEvent.VK_LEFT)  
        {
            if(playerX<=10)                   //prevents the paddle/slider from moving out of the screen
            playerX=10;

            else
            moveLeft();

        }
        if(e.getKeyCode()==KeyEvent.VK_ENTER){       //What actions must take place when "ENTER" key is pressed. In this context, restarting  of game...
            if(!play){
                play=false;
                 ballPosX = 210;   
                 ballPosY = 350;   

                 ballDirX = -1;    
                 ballDirY = -2;

                 playerX = 300;
                 score=0;
                 totalBlocks=30;
                 map=new MapGen(3,10);

                 repaint();

            }        
        }

        if(e.getKeyCode()==KeyEvent.VK_SPACE){    //what actions must take place when "SPACE" key is pressed. In this context, moving to new level-to be implmented...     
                if(!play && score==30){    
                    flagCheck=true;
                    System.out.println(flagCheck); //console stuff
                }        
        }  
    }

    public void moveRight(){            //helps with the movement of slider. +values move right on x-axis whereas -values move left on x-axis
        play=true;
        playerX+=40;
    }
    public void moveLeft(){
        play=true;
        playerX-=40;
    } 
      
}

【问题讨论】:

  • 1) 在键监听器上使用键绑定。 2)使用布局。 3) Edit 添加minimal reproducible example。显示关键侦听器失败不需要 2 个类和 300 多行代码。他们可以在 20 LOC 内做到这一点。
  • 长答案是,不是那样的。除了使用键绑定之外,您不需要切换窗口,而是有一个“主”面板为您进行切换。另外,不要覆盖paint,也不要在正在运行的绘画过程中调用repaint
  • 谢谢你们的帮助!

标签: java swing


【解决方案1】:

你在一个事件驱动的环境中运行,也就是说,发生了一些事情,然后你做出响应。

您对设计采用了程序化方法。显示一个窗口和一些希望窗口的状态“阻止”执行工作流并允许您监视其他状态的方式。这不是(非模态)窗口的工作方式。

当您调用setVisible 时,它会(几乎)立即返回,之后的某个时间点会显示窗口,具体取决于操作系统和其他开销。

这意味着GP.flagCheck 也会失败。

相反,请停止尝试对 Windows 执行此操作。这很烦人(对用户而言)。相反,只需切换面板,例如...

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MasterPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class MasterPane extends JPanel {

        public MasterPane() {
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "spaced");
            am.put("spaced", new AbstractAction() {

                private int counter = 0;

                @Override
                public void actionPerformed(ActionEvent e) {
                    JPanel next = null;
                    if (counter == 0) {
                        counter = 1;
                        next = new LevelTwoPane();
                    } else if (counter == 1) {
                        counter = 0;
                        next = new LevelOnePane();
                    }
                    if (next != null) {
                        removeAll();
                        add(next);
                        revalidate();
                        repaint();
                    }
                }
            });

            setLayout(new BorderLayout());
            add(new LevelOnePane());
        }

    }

    protected abstract class AbstractGamePane extends JPanel {

        private Timer timer;

        protected abstract void tick();

        protected void start() {
            if (timer != null) {
                timer.stop();
                timer = null;
            }
            timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    tick();
                }
            });
            timer.start();
        }

        protected void stop() {
            if (timer == null) {
                return;
            }
            timer.stop();
            timer = null;
        }

        @Override
        public void addNotify() {
            super.addNotify();
            start();
        }

        @Override
        public void removeNotify() {
            super.removeNotify();
            stop();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }
    }

    public static class LevelOnePane extends AbstractGamePane {

        protected static final String TEXT = "Level one";

        private int xPos = 0;
        private int xDelta = 1;

        @Override
        protected void tick() {
            xPos += xDelta;
            FontMetrics fm = getFontMetrics(getFont());
            if (xPos > getWidth() - fm.stringWidth(TEXT)) {
                xPos = getWidth() - fm.stringWidth(TEXT);
                xDelta *= -1;
            } else if (xPos < 0) {
                xPos = 0;
                xDelta *= -1;
            }
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            FontMetrics fm = g2d.getFontMetrics();
            int yPos = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
            g2d.drawString(TEXT, xPos, yPos);
            g2d.dispose();
        }

    }

    public class LevelTwoPane extends AbstractGamePane {

        protected static final String TEXT = "Level two";

        private int xPos = 0;
        private int xDelta = 1;

        @Override
        protected void tick() {
            xPos += xDelta;
            FontMetrics fm = getFontMetrics(getFont());
            if (xPos > getWidth() - fm.stringWidth(TEXT)) {
                xPos = getWidth() - fm.stringWidth(TEXT);
                xDelta *= -1;
            } else if (xPos < 0) {
                xPos = 0;
                xDelta *= -1;
            }
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            FontMetrics fm = g2d.getFontMetrics();
            int yPos = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
            g2d.drawString(TEXT, xPos, yPos);
            g2d.dispose();
        }

    }
}

即使这是不必要的沉重。一个整体更好的解决方案是使用模型/视图/控制器。

模型会携带所有关于视图需要渲染它的级别的信息,控制器将管理视图和模型之间的交互(即用户点击一个按钮,视图告诉控制器并且控制器使决定需要做什么,例如更新模型或移动到下一个级别或其他任何事情)。

你真的应该看看How to Use Key BindingsKeyListeners 只是等待发生的麻烦。

您还可以查看Detecting multiple keypresses in java 以获得更详细的示例

您会注意到MainPane 绑定到 Space,但我也会设置键绑定,可能在 AbstractGamePane 中,假设所有游戏关卡都具有相同的控件,以管理游戏

您还应该查看How to Use Swing Timers 以更好地管理“游戏循环”。在运行的paint pass 中调用repaint 是自找麻烦(它最终会使你的CPU 发热)

【讨论】:

  • 谢谢!将调查上述!
猜你喜欢
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 2013-10-11
  • 2023-03-24
  • 2013-12-23
  • 2021-05-09
  • 2016-02-28
相关资源
最近更新 更多