JButton не отображается должным образом в GIF - PullRequest
1 голос
/ 10 мая 2019

У меня есть программа, которая по сути должна быть титульным экраном для нескольких игр. Фон - это GIF (я не уверен, что это усугубляет проблему), и мне нужно немного JButtons, чтобы я мог запускать настоящие игры. Проблема в том, что JButton иногда появляется, только когда я наводю на него курсор (и на долю секунды), иначе он невидим. Работает просто отлично, идет в игру и все, это просто невидимо.

Я пытался выяснить, заключается ли проблема в том, что я использую GIF, а также метод paintComponent(), хотя он просто не отображается при использовании JPEG.

Вот код:

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

Извините, я знаю, что это довольно много кода, но я чувствую, что мне нужно показать все это, поскольку я не совсем уверен, откуда возникла проблема.

Я ожидал, что кнопка появится над GIF, но кажется, что это происходит наоборот

Ответы [ 3 ]

3 голосов
/ 11 мая 2019

Этот MCVE включает в себя так много изменений, что лучше пройтись по коду и посмотреть комментарии.

enter image description here

Обратите внимание, что в качестве BG в коде используется анимированный GIF.Я бы сказал, что это было использовано для явной демонстрации того, что это был GIF, но правда в том, что страница примеров изображений содержит только анимированные GIF.Формат не очень хорош для чего-либо еще, поскольку PNG будет поддерживать прозрачность и намного больше цветов, чем 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)));
    }
}
1 голос
/ 10 мая 2019

В дополнение к предложениям @ Fracool:

Вы делаете:

window.add(new ImagePanel());

, что совпадает с:

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

Позже вы делаете:

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

Это означает, что вы добавляете «imagePanel» и «snakeButtonPanel» на панель содержимого.

Когда несколько компонентов добавляются на одну панель, последний добавленный компонент окрашивается первым.Таким образом, в этом случае сначала отображается «snakeButtonPanel», а затем «imagePanel».Вы не хотите добавлять два компонента в панель содержимого.Вы хотите иметь родительские / дочерние отношения между фоновым изображением и кнопкой.

Также нет необходимости в «snakeButtonPanel», вы можете напрямую добавить «snakeButton».

Таким образом, вместо такой структуры, как:

- contentPane
    -imagePanel
    - snakeButtonPanel
        - snakeButton

Вы должны иметь такую ​​структуру:

- contentPane
    -imagePanel
        - snakeButton

И основной код будет выглядеть так:

JButton snakeButton = new JButton(...);

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

window.add( imagePanel );

Если вы сохраните менеджер макетов по умолчанию (который является BorderLayout), тогда панель изображений заполнит весь кадр, и кнопка будет расположена на панели изображений в соответствии с правилами FlowLayout, который является менеджером макетов по умолчанию для JPanel..

public class TestingGrounds extends JFrame{

Не расширять JFrame.Вы не добавляете новую функциональность в класс JFrame, и код в вашем конструкторе создает JFrame, то есть фрейм, в который вы добавляете все компоненты.

1 голос
/ 10 мая 2019

Я не проверял ваш код, но вот некоторые вещи, которые вам нужно изменить:

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

Эти две строки доставят вам проблемы. Почему?

  1. Первый должен называться ПОСЛЕ вы добавили все компоненты в свой window кадр, а не раньше (т.е. последняя строка в вашей программе). Это, вероятно, как вы можете решить вашу проблему.

  2. Второй ... null layout - Зло! и нахмурились . Пожалуйста, взгляните на Как использовать Layout Manager , вы даже можете комбинировать их. Это то, что происходит , если вы используете пустой макет и запускаете программу на другом компьютере с разными ОС / PLAFs / разрешением экрана / и т. Д.

  3. Нет необходимости звонить:

    snakeButtonPanel.setVisible(true);
    
  4. Согласно моему комментарию выше, если вы не уверены, связана ли ваша проблема с GIF или нет, удалите GIF и проверьте его, если он не связан, вообще удалите его из своего вопроса, если так и есть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...