【问题标题】:How do I draw on a JPanel from multiple outside classes?如何从多个外部类中绘制 JPanel?
【发布时间】:2019-01-04 16:45:59
【问题描述】:

我目前正在制作一款带有主菜单和您实际玩的世界的游戏。

我有一个名为Game 的类,它继承自JPanel 并实现了RunnableMouseListenerKeyListenerActionListener 接口 (仅包括重要部分)

我还有两个课程 InWorldHandlerOutWorldHandler 分别用于处理世界内外的机制。

Game 类:

public class Game extends JPanel implements Runnable, KeyListener, MouseListener, ActionListener
{
    protected JFrame frame;
    private Timer timer = new Timer(25, this);

    private World world;
    private Player player = new Player();

    private boolean draw;

    Game(World world)
    {
        frame = new JFrame("Minecraft 2D");
        this.world = world;
        player.enterWorld(world, this);
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        Graphics2D g2d = (Graphics2D)g;

        if(draw)
        {
            g2d.setColor(new Color(255, 255, 255));
            g2d.fillRect(0, 0, frame.getWidth(), frame.getHeight());

            draw = false;
            //Here, the in-game mechanics should be handled
            if(player.inWorld())
            {
                Chunk chunk = player.getLoadedChunk();
                for(int x = 0; x < 16; x++)
                {
                    for(int y = 0; y < 16; y++)
                    {
                        Block block = chunk.getBlockAt(x, y);
                        BufferedImage texture = block.getTexture();

                        g2d.drawImage(block.getTexture(), x*32, y*32, texture.getWidth()*2, texture.getHeight()*2, null);
                    }
                }
            }
            //Here, the out-game mechanics should be handled
            else
            {

            }
        }
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        this.repaint();
        draw = true;
    }

    @Override
    public void run()
    {
        draw = true;

        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.add(this);
        frame.setMinimumSize(new Dimension(518, 540));
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.addKeyListener(this);
        frame.addMouseListener(this);
        frame.setFocusable(true);
        frame.setVisible(true);
        frame.pack();
        timer.start();
    }
}

其他两个类目前都有空体。我只是不知道该怎么做。

我希望当玩家在游戏中时InWorldHandler 类在面板上绘制,当玩家在主菜单中时OutWorldHandler 类在Game 类中调用。我该怎么做?

【问题讨论】:

  • 一步一步来。首先获取JFrame 以正确显示JPanel,例如游戏面板。发布的代码没有。然后让它显示 another JPanel 说菜单面板。在两个面板之间切换学习如何使用CardLayout

标签: java swing user-interface jpanel custom-painting


【解决方案1】:

与其拥有一个JPanel,不如尝试使用CardLayout,并根据确定您在程序中位置的标志切换是显示InnerWorld还是OuterWorld在。

在您实施KeyListener 时,我认为这是为了让您能够移动您的角色,请查看此问题的公认答案:Keylistener not working for JPanel 并改用KeyBindings

同时避免使用 setMimimum/Maximum/PreferredSize() 并覆盖这些方法:Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

以这段代码为例:

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Game {
    private JFrame frame;
    private JButton button;
    private boolean status;
    private JPanel[] cards;
    private CardLayout cl;
    private JPanel gamePane;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Game().createAndShowGUI());
    }

    private void createAndShowGUI() {
        frame = new JFrame(getClass().getSimpleName());
        button = new JButton("Switch Worlds");
        status = true; //True = Inner / False = Outer

        cl = new CardLayout();

        gamePane = new JPanel(cl);
        cards = new JPanel[2];

        cards[0] = new InnerWorld();
        cards[1] = new OuterWorld();

        gamePane.add(cards[0], "innerWorld");
        gamePane.add(cards[1], "outerWorld");

        button.addActionListener(e -> {
            status = !status;
            if (status) {
                cl.show(gamePane, "innerWorld");
            } else {
                cl.show(gamePane, "outerWorld");
            }
        });

        frame.add(gamePane);
        frame.add(button, BorderLayout.SOUTH);

        frame.pack();
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

@SuppressWarnings("serial")
class InnerWorld extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

        g2d.drawString("Inner World", 50, 50);
    }

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

@SuppressWarnings("serial")
class OuterWorld extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g;

        g2d.drawString("Outer World", 50, 50);
    }

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

【讨论】:

  • 它工作了,但现在我遇到了一个问题,当我按下 JButton 时,键不再被识别(我使用主面板进行键绑定)
  • @Keheck 请在网站上提出另一个问题,展示您所做的工作以便我们提供更好的帮助,记得在我的回答中发布minimal reproducible example
  • @Frakcool 我自己解决了,但我还是会提出问题并回答它,所以其他人不必问:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多