首页 > 解决方案 > 如何将两个 JPanel 层叠在一起?

问题描述

我尝试在地图(JPanel)的顶部分层三角形(JPanel)。我用 JLayeredPane 尝试过,但三角形和地图没有分层(见附图)。最后,我想为三角形设置一个位置并将其放置在地图上。我试图为三角形和地图设置绝对位置,setBounds()但它对我不起作用。结果相同。这是我的代码:

import javax.swing.*;
import java.awt.*;

public class MainFrame extends JFrame {
    Container mainContainer;
    JLayeredPane mapLayer;
    BackgroundMap bgMap;
    Mesocyclone meso1;

    public MainFrame() {
        initUI();
    }

    private void initUI() {
        mainContainer = getContentPane();
        bgMap = new BackgroundMap();
        mapLayer = new JLayeredPane();
        mapLayer.setLayout(new FlowLayout());

        mainContainer.setLayout(new FlowLayout(FlowLayout.LEFT));
        mainContainer.add(mapLayer);

        meso1 = new Mesocyclone();

        mapLayer.add(bgMap, JLayeredPane.DEFAULT_LAYER);
        mapLayer.add(meso1, JLayeredPane.POPUP_LAYER);

        setSize(900, 1000);
        setTitle("Mesodetect | v1.0  \u00A9 ");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

import javax.swing.*;
import java.awt.*;
import java.awt.geom.Path2D;

public class Mesocyclone extends JPanel {
    private static final int PREF_W = 100;
    private static final int PREF_H = PREF_W;
    private static final Color COLOR = Color.RED;
    private Path2D myPath = new Path2D.Double();

    public Mesocyclone() {
        double firstX = (PREF_W / 2.0) * (1 - 1 / Math.sqrt(3));
        double firstY = 3.0 * PREF_H / 4.0;

        myPath.moveTo(firstX, firstY);
        myPath.lineTo(PREF_W - firstX, firstY);
        myPath.lineTo(PREF_W / 2.0, PREF_H / 4.0);
        myPath.closePath();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        // to smooth out the jaggies
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setPaint(COLOR);  // just for fun!
        g2.fill(myPath);  // fill my triangle
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }
}

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

public class BackgroundMap extends JLabel {
    private Image image;
    private BevelBorder border;

    private int WIDTH = 620;
    private int HEIGHT = 850;

    public BackgroundMap() {
        setPreferredSize(new Dimension(WIDTH, HEIGHT));

        try {
            image = ImageIO.read(new File("res/map_bg.png"));
            this.setIcon(new ImageIcon(image));
        } catch (IOException e) {
            e.printStackTrace();
        }

        border = new BevelBorder(1);
        setBorder(border);
    }

    public Image getImage() {
        return this.image;
    }
}

import java.awt.*;

public class Application {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new MainFrame().setVisible(true);
            }
        });
    }
}

当前状态

标签: javaswinguser-interfacejlayeredpane

解决方案


    mapLayer = new JLayeredPane();
    mapLayer.setLayout(new FlowLayout());

    mainContainer.setLayout(new FlowLayout(FlowLayout.LEFT));
    mainContainer.add(mapLayer);

    meso1 = new Mesocyclone();

    mapLayer.add(bgMap, JLayeredPane.DEFAULT_LAYER);
    mapLayer.add(meso1, JLayeredPane.POPUP_LAYER);
  1. 您不应该为分层窗格设置布局管理器。这将导致组件显示在 FlowLayout 中,而不是分层显示,因为每个组件的位置将根据 FlowLayout 的规则设置。但是,如果您不设置布局管理器,您现在需要负责设置添加到分层窗格中的每个组件的大小/位置。

  2. 不要使用“DEFAULT_LAYER”和“POPUP_LAYER”,这些是分层面板使用的特殊图层。当您添加自己的组件时,您只是在使用“常规”层。所以你应该使用“new Integer(1)”和“new Integer(2)”。

阅读 Swing 教程中有关如何使用 LayeredPanes的部分,以获取上述两个建议的工作示例。

另一种选择是不使用分层窗格,而仅使用 Swings 组件之间的默认父/子关系。

因此,您的图像标签将成为父级,而三角形组件将成为子级。那么你的逻辑会变成:

JPanel child = new ...
child.setSize( child.getPreferredSize() );
child.setLocation(10, 10);

JLabel parent = new JLabel( new ImageIcon(...) );
parent.add( child );

请注意,您还需要在子组件上使用 setOpaque(false)。

只要子组件适合标签图像的边界,这是更简单的解决方案。


推荐阅读