2016-04-05 9 views
2

Ich möchte mein Hintergrundbild ganz unten in diesem Rahmen, und den Knopf an der Spitze. Der unten beschriebene Code funktioniert jedoch nicht. Kann jemand sehen, wo die Probleme sind?Wie setze ich mein Hintergrundbild unten

Eine andere Sache ist, dass, obwohl ich den Speicherort für meine Schaltfläche festlegen, es in der Mitte oben auf dem Rahmen angezeigt wird.

Bitte ignorieren Sie die Kommentarzeilen. (Ich war nur raten, und die Hoffnung, sie wird funktionieren, aber sie tun es nicht offenbar.)

public class Menu extends JFrame{ 
private JLayeredPane pane; 
private JLayeredPane pane2; 

public Menu(){ 
    final JFrame f = new JFrame("Chinese Chess"); 


    JButton play = new JButton("Play vs. AI"); 

    f.setLayout(new FlowLayout()); 
    f.setLocationRelativeTo(null); 
    f.setSize(800, 800); 
    f.setVisible(true); 
    f.setResizable(false); 
    //f.pack(); 

    pane = new JLayeredPane(); 
    pane2 = new JLayeredPane(); 
    f.add(pane); 
    f.add(pane2); 


    //background image 
    JLabel background = new JLabel(new ImageIcon("res/img/background.png")); 
    background.setLocation(0, 0); 
    background.setSize(800, 800); 
    pane.add(background, JLayeredPane.FRAME_CONTENT_LAYER); 
    pane2.add(play, JLayeredPane.DEFAULT_LAYER); 
    //pane.moveToBack(); 

    //button PlayAI 
    play.setLocation(500,500); 
    play.setPreferredSize(new Dimension(100,50)); 
    //f.setLayout(new FlowLayout()); 

    //frame menu 
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    //f.getContentPane().add(play); 


    play.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent ae) { 
      new PlayAI(); 
     } 
    }); 
} 

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

Antwort

5

Probleme/Lösungen:

  • setLocation(...) und setBounds(...) Arten von Anrufen von den meist Layout-Manager ignoriert werden. Der einzige Weg, sie zu benutzen, ist das Layout des Behälters auf null setzen über .setLayout(null);
  • Aber gesagt haben, dass, während Null-Layouts und setBounds() könnte Neulingen zu Swing scheinen, wie der einfachste und beste Weg, um komplexe GUIs zu erstellen, die mehr Schaukel GUI 's schaffen Sie die ernsteren Schwierigkeiten, denen Sie begegnen werden, wenn Sie sie benutzen. Sie werden die Größe Ihrer Komponenten nicht ändern, wenn die GUI die Größe ändert, sie sind eine royale Hexe, die verbessert oder beibehalten wird, sie scheitern komplett, wenn sie in Scrollpanels platziert werden. Sie sehen auf allen Plattformen oder Bildschirmauflösungen, die sich vom Original unterscheiden, grässlich aus .
  • Also in der Summe - tun Sie dies nicht, verwenden Sie keine Null-Layouts oder setBounds, sondern eher Nest JPanels, jeder mit seinem eigenen Layout-Manager, und damit leicht zu pflegen und anständige GUI's erstellen.
  • Wenn Sie möchten, dass ein Bild im Hintergrund ist, dann zeichnen Sie es in einem JPanel, das Sie als Container für Ihre GUI-Komponenten verwenden, indem Sie es in JPanels paintComponent(Graphics g)-Methode zeichnen, wie in vielen ähnlichen Fragen auf dieser Website gezeigt wurde - Ich werde in einer Sekunde einige von mir finden.
  • Wenn Sie JPanels oben auf diesem Bild, das JPanel zeichnet, hinzufügen, stellen Sie sicher, dass Sie sie durchsehen können, indem Sie setOpaque(false) auf diesen überlagernden JPanels aufrufen. Andernfalls verdecken Sie das Bild.
  • Ihr Code enthält zwei JFrames, wenn nur einer benötigt wird. Werde den, den du nicht benutzt, los.
  • Sie rufen setVisible(true) zu früh auf dem JFrame, bevor Komponenten der GUI hinzugefügt wurden - nicht. Rufen Sie es erst auf, nachdem Sie alles zur GUI hinzugefügt haben, so dass alle Anzeigen OK sind.
  • Sie erstellen zwei JLayedPanes und decken einander vollständig ab, indem Sie sie dem JFrame hinzufügen, ohne zu verstehen, wie das BorderLayout des JFrame zusätzliche Komponenten verarbeitet.
  • Ich schlage vor, dass Sie nicht einmal einen JLayeredPane verwenden, sondern stattdessen den JPanel wie oben erwähnt einzeichnen und diesen als Ihren Container verwenden.
  • Ihr Code scheint ein völlig neues GUI-Fenster zu öffnen, wenn die Wiedergabetaste gedrückt wird. Wenn dies der Fall ist, kann dies für den Benutzer schnell nervig werden. Erwägen Sie stattdessen, Ansichten mit einem CardLayout auszutauschen.

Zum Beispiel:

import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 

import javax.imageio.ImageIO; 
import javax.swing.*; 

// extend JPanel so you can draw to its background 
@SuppressWarnings("serial") 
public class Menu2 extends JPanel { 
    private BufferedImage bgImage = null; // our background image 
    private JButton playButton = new JButton(new PlayVsAiAction("Play Vs. AI", KeyEvent.VK_P)); 

    public Menu2(BufferedImage bgImage) { 
     this.bgImage = bgImage; 

     setLayout(new GridBagLayout()); // center our button 
     add(playButton); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     if (bgImage != null) { 
      g.drawImage(bgImage, 0, 0, this); 
     } 
    } 

    // to size our GUI to match a constant or the image. 
    @Override 
    public Dimension getPreferredSize() { 
     if (isPreferredSizeSet()) { 
      return super.getPreferredSize(); 
     } 

     // if you want to size it based on the image 
     if (bgImage != null) { 
      int width = bgImage.getWidth(); 
      int height = bgImage.getHeight(); 
      return new Dimension(width, height);    
     } else { 
      return super.getPreferredSize(); 
     } 

     // if you want to size the GUI with constants: 
     // return new Dimension(PREF_W, PREF_H); 
    } 

    private class PlayVsAiAction extends AbstractAction { 
     public PlayVsAiAction(String name, int mnemonic) { 
      super(name); // have our button display this name 
      putValue(MNEMONIC_KEY, mnemonic); // alt-key to press button 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      // TODO code to start program 

     } 
    } 

    private static void createAndShowGui() { 
     BufferedImage img = null; 
     String imagePath = "res/img/background.png"; 
     try { 
      // TODO: fix this -- use class resources to get image, not File 
      img = ImageIO.read(new File(imagePath)); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      System.exit(-1); 
     } 
     Menu2 mainPanel = new Menu2(img); 

     JFrame frame = new JFrame("Chinese Chess"); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> { 
      createAndShowGui(); 
     }); 
    } 
} 
+0

Vielen Dank! Es hilft wirklich bei den Erklärungen. Bitte geben Sie mir etwas Zeit, um meinen Code zu ändern, und ich werde Ihnen später einige Rückmeldungen [email protected] –

+0

Warum setzen Sie bgImage = null? @HovercraftFullOfEels –

+0

@AnthonyZhang: weil ich dem bgImage kein BufferedImage zuteile, wo ich die Variable deklariere - ich kann nicht, wie es unmöglich ist. Stattdessen weise ich es im Konstruktor zu (wie Sie sehen können). –

2

Neben der Lösung oben ... sollten Sie Ihre Swing-Anwendung auf diese Weise erstellen und starten:

public static void main(String[] args) { 
    //Schedule a job for the event-dispatching thread: 
    //creating and showing this application's GUI. 
    javax.swing.SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGUI(); 
     } 
    }); 
} 

private static void createAndShowGUI() { 
    // Instantiate your JFrame and show it 
} 
+0

Danke;) @HovercraftFullOfEels – Jorge

+0

Danke! Ich bin eigentlich ein Neuling in Java. Eine Zeile, die ich in beiden Codes nicht verstehe, ist "SwingUtilities.invokeLater (new Runnable())". Kannst du mir sagen, was es macht? @Jorge –

+0

@AnthonyZhang Beachten Sie, dass dies eine kurze Zusammenfassung ist !!! Ich hoffe, es hilft. Wenn Sie mit Swing arbeiten, müssen alle Aktualisierungen der Benutzeroberfläche im Ereignis-Dispatch-Thread (AWT Event Dispatch Thread) erfolgen. Daher sollte jeder Aufruf einer Methode, die ein Update für unsere GUI beinhaltet, von diesem Thread aus aufgerufen werden. Die Verwendung von invokeLater garantiert, dass Ihr Code in EDT ausgeführt wird. Es gibt andere Optionen (wie invokeAndWait), aber im speziellen Fall wird Ihr Code so bald wie möglich im EDT ausgeführt (nachdem alle anderen vorherigen Ereignisse verarbeitet wurden) – Jorge

Verwandte Themen