2017-05-24 21 views
-1

我正在嘗試做兩件事。一個要求用戶按空格鍵開始,另一個開始遊戲。我想要有兩個構造函數,一個要求用戶按空格鍵和一個開始遊戲。問題是,如果我創建兩個教師,我會得到兩個不同的框架,而不是將這兩個框架都放在一起。如何使用重載構造函數,但保持在同一個JFrame中?

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); 
    } 
} 
+1

不要爲此使用兩個構造函數。問題結束。而是在主要方法中調用一個窗口,也許是一個模態JDialog,然後在從JDialog返回後創建並顯示主JFrame GUI。 –

+1

另一個也許更好的選擇:使用CardLayout來交換視圖 - 首先按空格鍵視圖,然後再使用遊戲。 –

+0

請參閱編輯以回答。如果有任何混淆,請提問。 –

回答

2

我會加入更多的層來生成所需包括

  • 從JFrame中
  • 提取你的遊戲的JPanel客場創造更多JPanels的影響,其中包括引進視圖
  • 顯示這些單獨的JPanel作爲單獨的「視圖」
  • 這可以通過在模式JDialog中顯示引入JPanel,甚至是一個JOptionPane,以及主遊戲JPanel in僅在模式對話框不再可見之後才顯示的主JFrame
  • 或者更好(我認爲)通過CardLayout交換視圖。這使您可以在同一頂層窗口中交換卡片組件「視圖」。您需要另一個JPanel才能使用CardLayout作爲其佈局管理器,然後使用JPanel將您的介紹JPanel和您的遊戲JPanel添加到此卡片佈局。該教程可以在這裏找到:CardLayout tutorial
  • 在下面的例子中,我使用了PropertyChangeListener。 Swing組件連線以允許默認使用這個,所以爲什麼不利用這個。介紹的JButton只是通過調用firePropertyChange(...)關於組件的屬性更改支持來通知任何監聽器它已被按下。然後在主GUI中,我偵聽此屬性更改並通過交換CardLayout中的JPanel來響應它。

例如:enter image description here

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); 
    } 
} 

可替換地,上面的相同的代碼可以被用來CRE吃了你最初請求再次使用模式的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的代碼的第二位,因爲介紹JPanel與主GUI沒有直接連接,不知道哪些偵聽器會做過一次通知其狀態的變化,最重要的是沒有需要知道這個信息。

相關問題