CardLayout in Java change by action in one of the

2019-01-28 07:33发布

问题:

I am making a simple game using a JFrame. I have made a simple "Start" screen which basically consists of a String and a JButton. I am picking up the button click with the actionPerformed(ActionEvent e) method. I don't know how to change the cards using a button click. This may seem like a simple problem to solve, but the twist comes with this: My main JFrame, my StartScreen and my JPanel where the game takes place are all in separate files. My main file, Virus.java, is where I create the JFrame. My file VirusGamePanel.java is where the game takes place. My file StartScreen.java is the screen with the button. I want to change 'cards' to the game screen when the player clicks the button. How can I do this? My StartScreen.java file:

package virus;

import javax.swing.JPanel;
import java.awt.event.ActionListener;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.Color;
import javax.swing.JButton;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.CardLayout;




public class StartScreen extends JPanel implements ActionListener{
    private static final long serialVersionUID = 1L;
    JButton start = new JButton("Start");
    public StartScreen(){
        start.addActionListener(this);
        start.setBounds(new Rectangle(400,300,100,30));
        this.add(start);
    }
    public void paint(Graphics g){
        super.paint(g);
        g.setFont(new Font("Impact",Font.BOLD,72));
        g.setColor(Color.MAGENTA);
        g.drawString("Virus",275,300);
    }
    public void actionPerformed(ActionEvent e)
    {
        if(e.getSource()==start)
        {
            //what to do here?
        }
    }
}

My Virus.java file:

package virus;

import javax.swing.*;
import java.awt.CardLayout;
import virus.StartScreen;

public class Virus extends JFrame{
    private static final long serialVersionUID =1L;
    JFrame jf = new JFrame("Virus");
    static JPanel thegame = new JPanel(new CardLayout());
    JPanel game = new VirusGamePanel();
    JPanel start = new StartScreen();

    public Virus(){
        jf.setResizable(false);
        jf.setSize(600,600);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(EXIT_ON_CLOSE);
        jf.setVisible(true);
        jf.add(thegame);
        thegame.add(start);
        thegame.add(game);

    }

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

    }

}

回答1:

You simply have to right this in your actionPerformed(...) method :

public void actionPerformed(ActionEvent e)
{
    if(e.getSource()==start)
    {
        //what to do here?
        CardLayout cardLayout = (CardLayout) Virus.thegame.getLayout();
        cardLayout.next(Virus.thegame);
    }
}

As very much pointed out by @kleopatra (THE EMPRESS) herself, don't override paint() instead do your painting stuff inside paintComponent(Graphics g) method of any JPanel/JComponent. Moreover, first add the components to your JFrame, once it's size is realized, then only set it to Visible, not before that. Instead of setting sizes for the JFrame simply override the JPanel's method getPreferredSize(), make it return some valid Dimension Object.

Do watch this sequence, as you write your code the next time :

public Virus(){
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jf.setResizable(false);                               
    thegame.add(start);
    thegame.add(game);
    jf.add(thegame);        
    jf.pack();
    jf.setLocationRelativeTo(null);
    jf.setVisible(true);
}

Here is your full code :

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.event.ActionListener;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.CardLayout;

public class Virus extends JFrame{
    private static final long serialVersionUID =1L;
    JFrame jf = new JFrame("Virus");
    static JPanel thegame = new JPanel(new CardLayout());
    JPanel game = new VirusGamePanel();
    JPanel start = new StartScreen();

    public Virus(){
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setResizable(false);                               
        thegame.add(start);
        thegame.add(game);
        jf.add(thegame);        
        jf.pack();
        jf.setLocationRelativeTo(null);
        jf.setVisible(true);
    }

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

    }

}

class StartScreen extends JPanel implements ActionListener{
    private static final long serialVersionUID = 1L;
    JButton start = new JButton("Start");
    public StartScreen(){
        start.addActionListener(this);
        start.setBounds(new Rectangle(400,300,100,30));
        this.add(start);
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setFont(new Font("Impact",Font.BOLD,72));
        g.setColor(Color.MAGENTA);
        g.drawString("Virus",275,300);
    }

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

    public void actionPerformed(ActionEvent e)
    {
        if(e.getSource()==start)
        {
            //what to do here?
            CardLayout cardLayout = (CardLayout) Virus.thegame.getLayout();
            cardLayout.next(Virus.thegame);
        }
    }
}

class VirusGamePanel extends JPanel
{
    public VirusGamePanel()
    {
        JLabel label = new JLabel("I am ON", JLabel.CENTER);
        add(label);
    }

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


回答2:

Your StartScreen class has to have access to the instance of the CardLayout of the JFrame and the instance of the VirusGamePanel class. You can pass these instances in the constructor or a setLayout method and setVirusGamePanel method of your StartScreen class.

Something like:

layout.next(virusGamePanel);

should work.