简体   繁体   English

通过键盘在JPanel之间切换

[英]Switching between JPanels by keyboard

I have a JFrame class with multiple panels and I do all of my graphics by drawing using the paintComponent(Graphics g) method so there is no use in using a CardLayout. 我有一个带有多个面板的JFrame类,我使用paintComponent(Graphics g)方法绘制所有图形,因此使用CardLayout没有用处。 To switch frames, I simple hit a button such as enter but, the problem is that when I switch panels, the left over graphics from the paintCompenent are still there. 要切换帧,我简单点击一个按钮,如输入,但问题是当我切换面板时,paintCompenent的左侧图形仍然存在。 I also tried making the panels visible using panel.setVisible(false) and that somewhat helped except that the panel I am transitioning to is invisible still even after setting visible to true. 我也尝试使用panel.setVisible(false)使面板可见,这有点帮助,除了我转换到的面板即使在将visible设置为true之后仍然是不可见的。 The buttons and commands to the new panel work and transition back to the first panel so i know that the transition is working, its just not showing how i want it to. 新面板的按钮和命令工作并转换回第一个面板,所以我知道过渡是有效的,它只是没有显示我想要它。 here is the code to the 2 panels that interact and the JFrame class that handles them: 这是两个交互的面板的代码和处理它们的JFrame类:

//JFRAME CLASS
package main;

import gameStates.Instruction;
import gameStates.Menu;
import gameStates.State;

import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;

import javax.swing.JFrame;

@SuppressWarnings("serial")
public class GameFrame extends JFrame implements KeyListener{

    //panels for Game States in order:
    static ArrayList<State> panels = new ArrayList<State>();//holds all of the game states that the game will eventually reach

    private static int currentState=0;//STATES: 0 - Menu
                               //1 - Instruction
                               //2 - Level 1 and States 3 through 7 are the levels up one respectively up to level 6

    public GameFrame() {
        panels.add(new Menu(this));
        panels.add(new Instruction(this));

        addKeyListener(this);
        setSize(640,480);
        setPreferredSize(new Dimension(640,480));
        setResizable(false);
        setLocation(20,50);
        setName("FBLA: A Success Story");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        add(panels.get(1));
        add(panels.get(0));
        panels.get(1).setVisible(false);
        panels.get(0).setVisible(true);

        pack();
        setVisible(true);


    }

    @SuppressWarnings("unused")
    public static void main(String[] args) {
        GameFrame g = new GameFrame();
    }


    public void keyTyped(KeyEvent e) {
    }
    public void keyPressed(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
            System.exit(0);
        else {
            panels.get(currentState).buttons(e);
        }
    }
    public void keyReleased(KeyEvent e) {
    }

    public void nextState(int state) {
        panels.get(currentState).setVisible(false);
        panels.get(state).setVisible(true);
        currentState = state;
    }

}
//////////////////////INITIAL PANEL//////////////////////////
package gameStates;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import javax.swing.Timer;

import main.GameFrame;

@SuppressWarnings("serial")
public class Menu extends State {

    //general items
    public BufferedImage bg;
    public String[] options = new String[3];
    public double x, y, velX, velY;
    public int selected;
    public Graphics2D g2;

    //time stuff
    Timer t = new Timer(5,this);

    public Menu(GameFrame g) {
        super(g);
        setup();
    }
    public void setup() {
        try {
            bg = ImageIO.read(Menu.class.getResourceAsStream("/backgrounds/FBLAmenubg.gif"));
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        options[0] = "PLAY";
        options[1] = "INSTRUCTIONS";
        options[2] = "QUIT";
        selected = 0;

        x=y=velY=0;
        velX=-.1;

        t.start();
    }

    public void paintComponent(Graphics g) {
        g2 = (Graphics2D)g;
        g2.drawImage(bg, (int)x, (int)y, null);
        g2.drawImage(bg, (int)x + 640, (int)y, null);
        Font f = new Font("FreeSerif", Font.ROMAN_BASELINE, 48);
        g2.setFont(f);
        g2.setColor(Color.WHITE);
        for(int j=0;j<3;j++){
            if(selected == j)
                g2.setColor(Color.RED);
            g2.drawString(options[j], 120, 80 + j*48);
            g2.setColor(Color.WHITE);
        }

    }

    private void processSelection() {

        if(selected == 2)
            System.exit(0);
        else if (selected == 1) {
            parent.nextState(1);
        }
        else {

        }
    }

    public void buttons(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_DOWN) {
            selected++;
            if(selected == 3)
                selected=0;
        }
        if(e.getKeyCode() == KeyEvent.VK_UP) {
            selected--;
            if(selected == -1)
                selected=2;
        }
        if(e.getKeyCode() == KeyEvent.VK_ENTER) {
            processSelection();
        }
    }

    public void actionPerformed(ActionEvent e) {
        x += velX;
        if(x<=-640)
            x=0;;
        repaint();
    }

}

/////////////////////TRANSITION TO THIS PANEL////////////////////////////
package gameStates;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import javax.swing.Timer;

import main.GameFrame;

@SuppressWarnings("serial")
public class Instruction extends State{

    public BufferedImage bg;
    public Graphics2D g2;
    public Timer t;

    public Instruction(GameFrame g) {
        super(g);
        setup();
    }


    public void buttons(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_SPACE)
            parent.nextState(0);
    }

    public void setup() {

        try {
            bg = ImageIO.read(Menu.class.getResourceAsStream("/backgrounds/Instructionsbg.gif"));
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        t = new Timer(5,this);
        t.start();

    }

    public void actionPerformed(ActionEvent e) {
        repaint();
    }

    public void paintComponent(Graphics g) {

        g2 = (Graphics2D) g;
        g2.setColor(Color.WHITE);
        g2.fillRect(0,0,640,480);
        g2.drawImage(bg,0,0,null);
        Font f = new Font("FreeSerif", Font.ROMAN_BASELINE, 20);
        g2.setFont(f);
        g2.setColor(Color.RED);
        g2.drawString("SPACE BAR to go back to menu.", 600, 400);

    }

}

so there is no use in using a CardLayout. 所以使用CardLayout是没有用的。

This has nothing to do with custom painting. 这与自定义绘画无关。 You should be able to use CardLayout (or in fact, what ever layout manager you want). 您应该能够使用CardLayout (或者实际上,您想要的布局管理器)。

You never call super.paintComponent , which is responsible for preparing the Graphics context for painting.... 你永远不会调用super.paintComponent ,它负责为绘画准备Graphics上下文....

 // Should be protected...
 // Should have @Override annotation
 public void paintComponent(Graphics g) {
    // super.paintComponent(g) goes here...
    //...
}

public Graphics2D g2; also scares me, you should NEVER maintain a reference to any Graphics context you didn't explicitly create yourself (and no g.create doesn't count) 也吓到我了,你永远不应该保持对你自己没有明确创建的任何Graphics上下文的引用(并且没有g.create不计算)

The Graphics context in Swing is generally shared for all the components attached to the same native peer (or window in most cases). Swing中的Graphics上下文通常是为连接到同一本机对等体(或大多数情况下是窗口)的所有组件共享的。 This means, unless you clean it, what ever was painted to it last will still be there. 这意味着,除非你清理它,否则最后涂在它上面的东西仍然存在。

This also means that whatever you might have painted to the Graphics context before will be wiped clean, hence the reason we generally discourage the maintaining references to Graphics or painting to it outside of the a normal paint cycle. 这也意味着你之前可能已经绘制到Graphics上下文的任何内容都将被擦除干净,因此我们通常不鼓励维护对Graphics引用或在正常的绘制周期之外绘制它。

Take a look at Painting in AWT and Swing for more details 在AWT和Swing中查看绘画了解更多详情

You may also find that, overtime, you KeyListener stops responding, even randomly. 您可能还会发现,加班, KeyListener停止响应,甚至是随机的。 KeyListener has focus issues which makes it in appropropriate for managing multiple components and you will find the Key Bindings API more suited to your needs KeyListener具有焦点问题,使其适用于管理多个组件,您会发现Key Bindings API更适合您的需求

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM