通过键盘在不同的JPanels之间进行切换

3

我有一个JFrame类,其中包含多个面板,我通过使用paintComponent(Graphics g)方法进行绘图,所以没有必要使用CardLayout。为了切换框架,我只需点击一个按钮,例如enter,但是问题在于当我切换面板时,paintComponent中剩余的图形仍然存在。我还尝试使用panel.setVisible(false)使面板可见,这在某种程度上有所帮助,除了我正在过渡到的面板仍然不可见,即使设置visible为true也是如此。新面板的按钮和命令可以正常工作并且可以回到第一个面板,因此我知道过渡是有效的,只是它没有按照我想要的方式显示。这里是交互的两个面板以及处理它们的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);

    }

}
1个回答

2

因此,使用CardLayout没有任何作用。

这与自定义绘制无关。您应该可以使用CardLayout(实际上是任何您想要的布局管理器)。

您从未调用super.paintComponent,它负责准备Graphics上下文以进行绘制....

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

public Graphics2D g2; 这也让我感到害怕,你绝不能保留对任何你没有明确创建的Graphics上下文的引用(而且g.create也不算)

在Swing中,Graphics上下文通常为所有附加到相同本机对等体(或大多数情况下的窗口)的组件共享。这意味着,除非您清除它,否则最后绘制到它的任何内容仍将存在。

这也意味着,您可能已经在Graphics上下文中绘制了任何内容,都将被擦除,因此我们通常不鼓励保留对Graphics的引用或在正常绘制周期之外进行绘制。

请查看AWT和Swing中的绘图以获取更多详细信息

您还可能发现,随着时间的推移,您的KeyListener停止响应,甚至是随机的。 KeyListener具有焦点问题,这使其不适合管理多个组件,您将发现Key Bindings API更适合您的需求


super.paintComponent实际上并没有做什么,但是由于我没有完全理解CardLayout,所以我不知道该怎么做。所以,感谢您的建议!在重新研究后它起作用了! - Silimerse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接