在 JFrame 上的 JPanel 上添加 Canvas

Adding Canvas on JPanel on JFrame

我希望标题不会太混乱。 首先,我还是个初学者,我几个月前才开始学习 java,直到几周前才开始使用图形组件。这是我的问题: 我有一个 JFrame 作为容器,然后有一个 Canvas "canvas" 来存储 BufferedImages 和 JPanel "bPanel" 来容纳三个 JButton。出于某种原因,即使我使用 bPanel.setOpaque(false) and/or bPanel.setBackground(new Color(0, 0, 0, 0) JPanel 仍会阻止 Canvas,无论我先添加哪个,然后添加哪个,无论我是将 Canvas 添加到 JFrame 还是 JPanel 上。 我在互联网上浏览了几个小时,尝试了至少 5 种不同的解决方案,但均无效。出于某种原因,我无法通过 JPanel 加载图像来工作,可能是因为我的显示 class 没有扩展任何内容。 不管怎样,让我们​​继续: 这是我的代码(是的,我知道我可以使用 Display extends JFrame 但这并不能解决问题,我已经尝试过了)。

public class Display {

private Game game;

private JFrame frame;
private Canvas canvas;
private JPanel bPanel;

private String title;
private int width, height;

private JButton stand, draw, reset;
private Icon drawIMG, standIMG, resetIMG;
private int bwidth, bheight;

public Display(String title, int width, int height) {

    this.title = title;
    this.width = width;
    this.height = height;

    createDisplay();

}

private void createDisplay() {

    frame = new JFrame(title);
    frame.setSize(width, height);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(false);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

    canvas = new Canvas();
    canvas.setPreferredSize(new Dimension(width, height));
    canvas.setMaximumSize(new Dimension(width, height));
    canvas.setMinimumSize(new Dimension(width, height));
    canvas.setFocusable(false);

    bPanel = new JPanel();
    bPanel.setSize(width, height);
    bPanel.setPreferredSize(new Dimension(width, height));
    //bPanel.setOpaque(false);
    bPanel.setBackground(new Color(0, 0, 0, 0));
    bPanel.setLayout(null);

    drawIMG = new ImageIcon(this.getClass().getResource("/textures/button_draw.png"));
    standIMG = new ImageIcon(this.getClass().getResource("/textures/button_stand.png"));
    resetIMG = new ImageIcon(this.getClass().getResource("/textures/button_reset.png"));
    draw = new JButton(drawIMG);
    stand = new JButton(standIMG);
    reset = new JButton(resetIMG);
    draw.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent drawClicked) {
            if (game.getPhase() == 1)
                game.playerDraw();
        }
    });
    stand.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent standClicked) {
            if (game.getPhase() == 1)
            {
                game.setPhase(2);
                removeButtons();
            }
        }
    });
    reset.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent resetClicked) {
            game.reset();
        }
    });
    bwidth = 300;
    bheight = 100;
    //bPanel.add(new JLabel(new ImageIcon(getClass().getResource("/textures/background.png"))), BorderLayout.CENTER);
    addButton(draw);
    addButton(stand);
    addButton(reset);
    draw.setBounds(100, ((height/2)-(bheight/2)), bwidth, bheight);
    stand.setBounds(((width-100)-bwidth), ((height/2)-(bheight/2)), bwidth, bheight);
    reset.setBounds(((width/2)-40), (height-120), 80, 80);

    frame.add(canvas);
    frame.add(bPanel);
    frame.pack();

}

public void showImage(String path) {

    JLabel jl = new JLabel();
    jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(path)));
    frame.add(jl);
    frame.repaint();

}

public void setGame(Game game) {
    this.game = game;
}

public void addButton(JButton button) {
    bPanel.add(button);
    bPanel.setLayout(null);
}

public void showButtons() {
    draw.setVisible(true);
    stand.setVisible(true);
}

public void removeButtons() {
    draw.setVisible(false);
    stand.setVisible(false);
}

public void removePanel(JPanel panel) {
    frame.remove(panel);
}

public Canvas getCanvas() {
    return canvas;
}

public JFrame getFrame() {
    return frame;
}

public JPanel getBPanel() {
    return bPanel;
}

}

例如,在我的这个尝试中,图片仅在按下 JButton "stand" 后显示:

public void showImage(String path) {

    JLabel jl = new JLabel();
    jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(path)));
    frame.add(jl);
    frame.repaint();

}

我非常绝望,因为我花了很多时间试图找出加载图形的解决方案。 提前感谢您的帮助:D

几个问题:

  1. 不要使用空布局。 Swing 旨在与布局管理器一起使用。
  2. JFrame 的默认布局管理器是 BorderLayout。如果不指定约束,组件将添加到 CENTER。 CENTER 中只能显示一个组件。所以你不能只是不断地向框架添加组件。您需要有一个 parent/child 层次结构。
  3. 不要使用 Canvas。那是一个 AWT 组件。如果你想在 Swing 中进行自定义绘画,你可以使用 JPanel

所以你的代码可能是这样的:

//addButton(draw);
//addButton(stand);
//addButton(reset);
bPanel(draw);
bPanel(stand);
bPanel(reset);

JPanel 的默认布局管理器是 FlowLayout。所以按钮将从左到右添加并在面板上居中。

//frame.add(bPanel);
frame.add(bPanel, BorderLayout.PAGE_START);

现在所有按钮都将添加到框架的顶部。

//private Canvas canvas;
private JPanel canvas;
….
//canvas = new Canvas();
canvas = new JPanel(new BorderLayout());
…
//frame.add(canvas);
frame.add(canvas, BorderLayout.CENTER);

现在"canvas"将被添加到框架的BorderLayout的CENTER,这意味着它将占用所有按钮面板未使用的space。

public void showImage(String path) {

    JLabel jl = new JLabel();
    jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(path)));
    frame.add(jl);
    frame.repaint();

}

您不能将图像直接添加到框架中,因为您已经将其他组件添加到框架中。而是使用:

    //frame.add(jl);
    //frame.repaint();
    canvas.add(jl);
    canvas.repaint();

所以图像被添加到 canvas 中,而 canvas 又被添加到框架中,所以你有一个 parent/child 层次结构。

//draw.setBounds(100, ((height/2)-(bheight/2)), bwidth, bheight);
//stand.setBounds(((width-100)-bwidth), ((height/2)-(bheight/2)), bwidth, bheight);
//reset.setBounds(((width/2)-40), (height-120), 80, 80);

不需要以上代码,因为根据布局管理器的规则设置每个组件的大小和位置是布局管理器的工作。

所以基本上您需要重新开始并学习一些 Swing 基础知识。也许 Swing tutorial 会有所帮助。有如何使用每个布局管理器的演示。