Как рисовать компоненты JPanel без фона?

Итак, у меня есть класс GameCourt, который расширяет JPanel. Этот класс перезаписывает код paintComponent, чтобы он рисовал несколько компонентов (лабиринт, персонаж и несколько монет). Этот JPanel является частью класса, расширяющего JLayeredPane двумя слоями: один для рисования фона (с использованием класса BackgroundPanel, который расширяет JPanel), а другой — для рисования всех элементов, которые я хочу (кнопка сброса, метка..)

Итак, я хочу, чтобы GameCourt, который находится над фоном в JLayeredPane, не рисовал его фон, чтобы я мог просматривать красивое изображение.

Я попробовал setOpaque(false) в GameCourt,но тогда отображается только фон.

Я попробовал setBackground (новый цвет (0,0,0,0)), но это не сработало. Это потому, что за GameCourt JPanel есть еще один черный фон, я понятия не имею, откуда он взялся. Я попробовал super.setBackground, но это ничего не дало.

Я попытался изменить индекс фона в JLayeredPane, чтобы сделать его выше GameCourt (JPanel), но это не имеет значения. (Это странно, так как он должен по крайней мере рисовать фон над GameCourt JPanel.

Кроме того, я попытался сделать: add(background, new Integer(0)) как в образце кода в JavaDocs, но он сказал «Исключение недопустимого аргумента».

Я действительно не знаю, что не так... Я думаю, что неправильно понял код JLayeredPane, потому что, когда я использую setOpaque(false), но не добавляю фон в JLayeredPane, он отображает все правильно. Кроме того, как изменение add(background,0) на add(background,2) не имеет значения??

Вот код «GameCourt» (упрощенный): m.draw(g), монеты.drawCoins(g) и т. д. просто нарисуйте кучу изображений png.

 public class GameCourt extends JPanel {

 public GameCourt(JLabel status) {

 //     setOpaque(false);    
    setBackground(new Color(0,0,0,0));
 // Game constants
public static final int COURT_WIDTH = 1275;
public static final int COURT_HEIGHT = 765;
}

/**
 * (Re-)set the game to its initial state.
 */
public void reset() {
    playing = true;
    status.setText("Running...");

    // Make sure that this component has the keyboard focus
    requestFocusInWindow();
}

/**
 * This method is called every time the timer defined in the constructor
 * triggers.
 */
private void tick() {
    if (playing) {
        repaint();
    }
}
@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    m.drawMaze(g);
    player.draw(g);
    coins.drawCoins(g);
}

@Override
public Dimension getPreferredSize() {
    return new Dimension(COURT_WIDTH, COURT_HEIGHT);
}
}

Вот код JLayeredPanel (тоже немного упрощенный):

public class LayeredGameCourt extends JLayeredPane {

package Game;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class LayeredGameCourt extends JLayeredPane {


    private GameCourt court;
    public LayeredGameCourt()    {

        setPreferredSize(new Dimension(GameCourt.COURT_WIDTH, GameCourt.COURT_HEIGHT+90));
        setLayout(new BorderLayout());

        final JBackgroundPanel background = new JBackgroundPanel();
        add(background,0);
        background.setBounds(0,0,GameCourt.COURT_WIDTH,GameCourt.COURT_HEIGHT+90);

        // Status panel
        final JLabel status = new JLabel("Running...");

        // Main playing area
        final GameCourt court = new GameCourt(status);
        this.court=court;
        add(court, 1);
        court.setBounds(0,90,GameCourt.COURT_WIDTH,GameCourt.COURT_HEIGHT);

        // Reset button
        final JPanel control_panel = new JPanel();
        add(control_panel, 1);


        final JButton reset = new JButton("Reset");
        reset.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                court.reset();
            }
        });
        control_panel.add(status);
        control_panel.add(reset);
        // Start game
        court.reset();
    }

    public void requestFocusForGC(){
        court.requestFocusInWindow();
    }

    }

И, наконец, (бесполезный) код backgroundPanel, если поможет:

@SuppressWarnings("serial")
public class JBackgroundPanel extends JPanel {

    private BufferedImage background;
    public JBackgroundPanel() {
        try {
            if (background == null) {
                background = ImageIO.read(new File("background.png"));
            }
        } catch (IOException e) {
            System.out.println("Internal Error:" + e.getMessage());
        } 
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(background, 0, 0,null);  
        System.out.println("attempting to paint");
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(GameCourt.COURT_WIDTH, GameCourt.COURT_HEIGHT+90);
    }
}

person QuantumHoneybees    schedule 07.12.2015    source источник


Ответы (1)


Ничего, взялся за дело!

Для других людей, у которых может быть такая же проблема. Вот как прошел мой мыслительный процесс.

Почему я не могу добавить (фон, новое целое число (0))?

Может быть, это потому, что фон не является компонентом? Неа. Просмотрел документы Java и понял, что они не устанавливают тип макета. Возможно, мой .add вызывает .add для BorderLayout, который я добавил, поэтому он терпит неудачу.

Я удалил его и все заработало!!!

Все, что мне нужно было сделать, это закомментировать одну строку, которую я по какой-то чертовой причине решил, что она должна быть там.

Но это работает!!!!

Для уточнения: я удалил эту строку:

setLayout(new BorderLayout());

Спасибо (если) всем, кто пытался помочь!

person QuantumHoneybees    schedule 07.12.2015
comment
Как описано в Как использовать многоуровневые панели - При добавлении компонента в многоуровневую панель вы указываете слой с целым числом. При использовании setLayer для изменения слоя компонента вы используете int. Вы можете подумать, что если вы используете int вместо Integer с методом add, компилятор будет жаловаться или ваша программа выдаст исключение с недопустимым аргументом. Но компилятор ничего не говорит, что приводит к общей проблеме многоуровневой панели. - person MadProgrammer; 07.12.2015
comment
По умолчанию JLayeredPane не имеет менеджера компоновки по умолчанию, вы можете использовать их, но тогда вы ограничены тем, как работает этот менеджер компоновки, например, BorderLayout будет управлять только одним компонентом в любом из 5 доступных слотов, если вы добавляете больше компонентов в ту же позицию, только последний будет управляться - person MadProgrammer; 07.12.2015
comment
Да, именно поэтому у меня тоже были проблемы с фокусировкой, я думаю, спасибо! - person QuantumHoneybees; 08.12.2015