我正在尝试做两件事。一个要求用户按空格键启动,一个启动游戏。我想要有两个构造函数,一个要求用户按空格键,一个启动游戏。问题是如果我创建两个教师,我会得到两个不同的帧,而不是一个帧同时具有这两个帧。
import javax.swing.*;
import java.awt.*;
import java.text.DecimalFormat;
public class DuckHunt extends JPanel {
private ImageIcon imgBackground, imgForeground, imgCursor;
private Cursor cursor;
private int score, hits;
private double accuracy;
private DecimalFormat df;
private Font f;
private static final int PANEL_WIDTH = 640;
private static final int PANEL_HEIGHT = 480;
public static void main(String[] args) {
new DuckHunt();
}
public DuckHunt(String text) {
// THIS IS WHERE IM TRYING TO DO THE SPACEBAR THING
// how do I do it so it's all in one frame, instead of two seperate ones
}
public DuckHunt() {
df = new DecimalFormat("#%");
f = new Font("Neuropol", Font.BOLD, 18);
imgBackground = new ImageIcon("images\\background.png");
imgForeground = new ImageIcon("images\\foreground.png");
imgCursor = new ImageIcon("images\\cursor.png");
cursor = Toolkit.getDefaultToolkit().createCustomCursor(imgCursor.getImage(),
new Point(imgCursor.getIconWidth() / 2, imgCursor.getIconHeight() / 2), "");
setLayout(null);
setCursor(cursor);
setFocusable(true);
requestFocus();
JFrame frame = new JFrame();
frame.setContentPane(this);
frame.setTitle("Duck Hunt © Nintendo 1985");
frame.setSize(PANEL_WIDTH, PANEL_HEIGHT);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setFocusable(false);
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(imgBackground.getImage(), 0, 0, this);
g2.setFont(f);
g2.setColor(new Color(128, 208, 16));
g2.drawImage(imgForeground.getImage(), 0, 0, this);
g2.drawString("SCORE: " + score, 20, PANEL_HEIGHT - 50);
g2.drawString("HITS: " + hits, 250, PANEL_HEIGHT - 50);
g2.drawString("ACCURACY: " + df.format(accuracy), 450, PANEL_HEIGHT - 50);
}
}
答案 0 :(得分:2)
我会添加更多图层来产生你想要的效果,包括
firePropertyChange(...)
来通知任何侦听器它已被按下。然后在主GUI中,我监听这个属性更改并通过在CardLayout中交换JPanel来响应它。import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
@SuppressWarnings("serial")
public class DuckHunt2 extends JPanel {
public static final String NEXT_CARD = "next card";
private static final int PANEL_WIDTH = 640;
private static final int PANEL_HEIGHT = 480;
private CardLayout cardLayout = new CardLayout();
private DuckHuntIntro intro = new DuckHuntIntro();
private DuckHuntGame game = new DuckHuntGame();
public DuckHunt2() {
setLayout(cardLayout);
NextCardListener nextCardListener = new NextCardListener();
intro.addPropertyChangeListener(nextCardListener);
add(intro, intro.getClass().toString());
add(game, game.getClass().toString());
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
}
private class NextCardListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(NEXT_CARD)) {
cardLayout.next(DuckHunt2.this);
}
}
}
private static void createAndShowGui() {
DuckHunt2 mainPanel = new DuckHunt2();
JFrame frame = new JFrame("Duck Hunt © Nintendo 1985");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
@SuppressWarnings("serial")
class DuckHuntIntro extends JPanel {
private JButton startButton = new JButton(new StartAction("Press Button to Start"));
public DuckHuntIntro() {
startButton.setFont(startButton.getFont().deriveFont(Font.BOLD, 40f));
setLayout(new GridBagLayout());
add(startButton);
}
private class StartAction extends AbstractAction {
public StartAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
DuckHuntIntro.this.firePropertyChange(DuckHunt2.NEXT_CARD, null, DuckHunt2.NEXT_CARD);
}
}
}
@SuppressWarnings("serial")
class DuckHuntGame extends JPanel {
// game code goes here
public DuckHuntGame() {
JLabel dummyLabel = new JLabel("Your Main Game GUI Goes Here");
dummyLabel.setFont(dummyLabel.getFont().deriveFont(Font.PLAIN, 16f));
add(dummyLabel);
}
}
或者,可以使用上面相同的代码创建最初使用模态 JDialog再次请求的两个窗口场景,它可能看起来像:
private static void createAndShowGui2() {
JPanel introPanel = new DuckHuntIntro();
JDialog dialog = new JDialog((JFrame)null, "Duck Hunt", true);
introPanel.addPropertyChangeListener(pcEvent -> {
if (pcEvent.getPropertyName().equals(NEXT_CARD)) {
// make dialog go away
dialog.setVisible(false);
}
});
introPanel.setPreferredSize(new Dimension(500, 300));
dialog.add(introPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
// since the dialog is modal, all code flow stops here
// until dialog is no longer visible
JPanel gamePanel = new DuckHuntGame();
gamePanel.setPreferredSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT));
JFrame frame = new JFrame("Duck Hunt © Nintendo 1985");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gamePanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui2());
}
您可能会问为什么我遇到了使用属性更改侦听器的麻烦,而不是让介绍JPanel调用主GUI中保存的方法来告诉它交换视图。这样做的主要原因是它减少了不必要的耦合",多个类之间不必要的连接,这使您的代码更安全,更容易出错,并且更容易扩展。例如,因为我这样做,很容易将使用CardLayout的原始代码转换为使用模态JDialog的第2位代码,因为介绍JPanel没有直接连接到主GUI,不知道听众会是什么做一次状态更改通知,最重要的是,没有需要知道这些信息。