Tengo un programa que esencialmente se supone que es una pantalla de título para algunos juegos. El fondo es un GIF (no estoy seguro de si eso está contribuyendo al problema), y necesito tener algunos JButtons que me permitan ejecutar los juegos reales. El problema es que JButton solo aparece a veces cuando paso el mouse sobre él (y durante una fracción de segundo, de lo contrario), de lo contrario es invisible. Funciona bien, va al juego y todo, es invisible.

Traté de ver si el problema es el hecho de que estoy usando un GIF, así como el método paintComponent(), aunque simplemente no apareció cuando usé un JPEG.

Aquí está el código:

public class TestingGrounds extends JFrame{
     //declarations
     JButton snakeButton;
     JPanel snakeButtonPanel;
     JFrame window;
     Container con;
     TitleScreenHandler tsHandler = new TitleScreenHandler();
     //constructor
     public TestingGrounds(){
          //main JFrame
          window = new JFrame("Title Screen");
          window.add(new ImagePanel());
          window.setResizable(false);
          window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          window.setSize(1831, 1030);
          window.setVisible(true);
          window.setLocationRelativeTo(null);
          window.setLayout(null);

          con = window.getContentPane();

          //panel for the button to go to the snake game
          snakeButtonPanel =  new JPanel();
          snakeButtonPanel.setBounds(100,100,600,150);

          //button to go to snake game
          snakeButton = new JButton("Snake");
          snakeButton.setBackground(Color.BLACK);
          snakeButton.setForeground(Color.WHITE);
          snakeButton.setFont(new Font("Times New Roman", Font.ITALIC, 30));
          snakeButton.addActionListener(tsHandler);
          snakeButton.setFocusPainted(false);
          //adding button to panel
          snakeButtonPanel.add(snakeButton);
          //adding panel to container
          con.add(snakeButtonPanel);
          //setting the panel as visible
          snakeButtonPanel.setVisible(true);

     }
     //main method for running constructor
     public static void main(String[] args) {
          new TestingGrounds();
     }

     //what to do if the button is pressed
     public class TitleScreenHandler implements ActionListener {
          public void actionPerformed(ActionEvent event){
               //goes to main game screen if start button is pressed
               new SnakeGame();
          }
     }
}
//class for using the gif
class ImagePanel extends JPanel {
     Image image;
     public ImagePanel() {
          image = Toolkit.getDefaultToolkit().createImage("C:/Users/eklut/Desktop/Coding/ICS4U1/src/graphicsstuff/snek/source.gif");
     }

     public void paintComponent(Graphics g) {
          super.paintComponent(g);
          g.drawImage(image, 0, 0, this);
     }
}

Lo siento, sé que es una buena cantidad de código, pero siento que tengo que mostrarlo todo, ya que no estoy exactamente seguro de dónde surge el problema.

Esperaba que el botón apareciera sobre el gif, pero casi parece que está sucediendo al revés

1
EkLuthra 10 may. 2019 a las 22:57

3 respuestas

La mejor respuesta

Este MCVE incluye tantos cambios que es mejor revisar el código y ver los comentarios.

enter image description here

Tenga en cuenta que el código utiliza un GIF animado como BG. Diría que se utilizó para demostrar explícitamente que era un GIF, pero la verdad es que la página de imágenes de ejemplo solo contiene GIF animados. El formato no es muy bueno para nada más, dado que un PNG admitirá translucidez y muchos más colores que un GIF.

import java.awt.*;
import java.awt.event.*;
import java.net.MalformedURLException;
import javax.swing.*;
import java.net.URL;

//public class TestingGrounds extends JFrame {
public class TestingGrounds {

    //declarations
    JButton snakeButton;
    JPanel snakeButtonPanel;
    JFrame window;
    TitleScreenHandler tsHandler = new TitleScreenHandler();

    //constructor
    public TestingGrounds() {
        //main JFrame
        window = new JFrame("Title Screen");
        try {
            JPanel imagePanel = new ImagePanel();
            imagePanel.setLayout(new BorderLayout());
            window.add(imagePanel);
            //window.setResizable(false);
            window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            // Don't guess sizes needed. They will be wrong on other 
            // PLAFs or platforms.
            //window.setSize(850, 600);

            // should be last
            //window.setVisible(true);
            window.setLocationRelativeTo(null);
            //window.setLayout(null);

            //con = window.getContentPane();
            //panel for the button to go to the snake game
            snakeButtonPanel = new JPanel(new GridBagLayout());
            snakeButtonPanel.setOpaque(false);
            //snakeButtonPanel.setBounds(100, 100, 600, 150);

            //button to go to snake game
            snakeButton = new JButton("Snake");
            snakeButton.setMargin(new Insets(10,40,10,40));
            snakeButton.setBackground(Color.BLACK);
            snakeButton.setForeground(Color.WHITE);
            snakeButton.setFont(new Font("Times New Roman", Font.ITALIC, 30));
            snakeButton.addActionListener(tsHandler);
            snakeButton.setFocusPainted(false);
            //adding button to panel
            snakeButtonPanel.add(snakeButton);
            //adding panel to container
            //con.add(snakeButtonPanel);
            // Adding the container to imagePanel
            imagePanel.add(snakeButtonPanel);

            //setting the panel as visible
            snakeButtonPanel.setVisible(true);

            window.pack();
            window.setVisible(true);
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
    }

    //main method for running constructor
    public static void main(String[] args) {
        new TestingGrounds();
    }

    //what to do if the button is pressed
    public class TitleScreenHandler implements ActionListener {

        public void actionPerformed(ActionEvent event) {
            //goes to main game screen if start button is pressed
            //new SnakeGame();
            JOptionPane.showMessageDialog(snakeButton, "Snake Game");
        }
    }
}
//class for using the gif

class ImagePanel extends JPanel {

    Image image;

    public ImagePanel() throws MalformedURLException {
        image = Toolkit.getDefaultToolkit().createImage(
                new URL("https://i.stack.imgur.com/OtTIY.gif"));
        MediaTracker mt = new MediaTracker(this);
        mt.addImage(image, 1);
        try {
            mt.waitForAll();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, this);
    }

    @Override
    public Dimension getPreferredSize() {
        // this allows us to pack() the window around the image
        return (new Dimension(image.getWidth(this), image.getHeight(this)));
    }
}
3
Andrew Thompson 11 may. 2019 a las 02:34

No he probado su código, pero aquí hay algunas cosas que debe cambiar:

window.setVisible(true);
window.setLayout(null);

Esas 2 líneas te darán problemas. ¿Por qué?

  1. El primero debe llamarse DESPUÉS que haya agregado todos los componentes a su marco window, no antes (es decir, la última línea de su programa). Probablemente así es como puede resolver su problema.

  2. El segundo ... null layout es Evil! y < a href = "https://stackoverflow.com/questions/6592468/why-is-it-frowned-upon-to-use-a-null-layout-in-swing"> mal visto . Eche un vistazo a Cómo utilizar un Layout Manager usted Incluso puede combinarlos. Esto es lo que sucede si usa un diseño nulo y ejecuta tu programa en una computadora diferente con diferentes sistemas operativos / PLAF / resolución de pantalla / etc.

  3. No hay necesidad de llamar:

    snakeButtonPanel.setVisible(true);
    
  4. Según mi comentario anterior, si no está seguro de si su problema está relacionado o no con un GIF, elimine el GIF y pruébelo; si no está relacionado, elimínelo de su pregunta, si es así, consérvelo.

1
Frakcool 10 may. 2019 a las 20:08

Además de las sugerencias de @ Fracool:

Tú lo haces:

window.add(new ImagePanel());

Que es lo mismo que:

window.getContentPane().add(new ImagePanel());

Más tarde lo haces:

con = window.getContentPane();
...
con.add(snakeButtonPanel);

Lo que significa que está agregando "imagePanel" y "snakeButtonPanel" al panel de contenido.

Cuando se agregan varios componentes al mismo panel, el último componente agregado se pinta primero. Entonces, en este caso, se pinta primero el "snakeButtonPanel" y luego se pinta el "imagePanel". No desea agregar dos componentes al panel de contenido. Desea tener una relación padre / hijo entre la imagen de fondo y el botón.

Además, no es necesario el "snakeButtonPanel", puede agregar el "snakeButton" directamente.

Entonces, en lugar de tener una estructura como:

- contentPane
    -imagePanel
    - snakeButtonPanel
        - snakeButton

Deberías tener una estructura como:

- contentPane
    -imagePanel
        - snakeButton

Y el código básico sería como:

JButton snakeButton = new JButton(...);

JPanel imagePanel = new ImagePanel();
imagePanel.add( snakeButton );

window.add( imagePanel );

Si mantiene el administrador de diseño predeterminado (que es un BorderLayout), el panel de imágenes llenará todo el marco y el botón se colocará en el panel de imágenes según las reglas de FlowLayout, que es el administrador de diseño predeterminado para un JPanel.

public class TestingGrounds extends JFrame{

No extiendas JFrame. No está agregando una nueva funcionalidad a la clase JFrame y el código en su constructor crea un JFrame, que es el marco al que está agregando todos los componentes.

1
camickr 10 may. 2019 a las 20:51