Java Swing:结合CardLayout和JLayeredPane的效果
Java Swing: combine effects of CardLayout and JLayeredPane
我试图将一些 JPanel
一个放在另一个之上,完全重叠。
我使用 JLayeredPane
将它们置于不同的 "depth" 中,这样我就可以更改深度和不透明度以查看某个面板 "under" 另一个。
这是我做的一个小测试,它工作正常:
public class LayeredCardPanel extends JPanel {
private static final String BLUE_PANEL = "blue ";
private static final String RED_PANEL = "red ";
private static final String GREEN_PANEL = "green";
private String[] panelNames = { BLUE_PANEL, RED_PANEL, GREEN_PANEL };
private Color[] panelColors = { Color.BLUE, Color.RED, Color.GREEN };
private List<JPanel> panels = new ArrayList<>();
private final int TOP_POSITION = 30;
private static final int PANELS_FIRST_POS = 10;
private JLayeredPane layeredPane;
public LayeredCardPanel() {
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(createControlPanel());
layeredPane = new JLayeredPane();
////////////////////////////////////////////////////////////////
//setting layout here results in all grey, non functioning panel.
//layeredPane.setLayout(new CardLayout(0, 0));
//////////////////////////////////////////////////////////////
add(layeredPane);
//adding 3 panel
for (int i = 0; i < panelNames.length; i++) {
JPanel panel = new JPanel();
panel.setBackground(panelColors[i]);
layeredPane.add(panel);
layeredPane.setLayer(panel, PANELS_FIRST_POS + i);
panels.add(panel);
}
////////////////////////////////////////////////////////////
//setting the card here, after adding panels, works fine
layeredPane.setLayout(new CardLayout(0, 0));
//////////////////////////////////////////////////////////
}
测试结果如下所示:
正如您在 ////// 注释行之间看到的那样,仅当我将 CardLayout
设置为 JLayeredPane
after[=38 时,此测试才能正常工作=] 我添加 JPanel
s 到它。
在我看来,JPanel
是使用默认布局管理器添加到 JLayeredPane
中的。布局(设置和更改边界以填充 JLayeredPane
)由后来应用的 CardLayout
.
完成
我的问题是:虽然这符合我的需要,但解决方案(使用一个布局管理器添加,然后替换它以实现我想要的布局)并没有看起来是一个优雅的解决方案。我正在寻找更好的方法来做到这一点。
这是整个 SSCE:
public class LayeredCardPanel extends JPanel {
private static final String BLUE_PANEL = "blue ";
private static final String RED_PANEL = "red ";
private static final String GREEN_PANEL = "green";
private String[] panelNames = { BLUE_PANEL, RED_PANEL, GREEN_PANEL };
private Color[] panelColors = { Color.BLUE, Color.RED, Color.GREEN };
private List<JPanel> panels = new ArrayList<>();
private final int TOP_POSITION = 30;
private static final int PANELS_FIRST_POS = 10;
private JLayeredPane layeredPane;
public LayeredCardPanel() {
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(createControlPanel());
layeredPane = new JLayeredPane();
add(layeredPane);
//add 3 panel
for (int i = 0; i < panelNames.length; i++) {
JPanel panel = new JPanel();
panel.setBackground(panelColors[i]);
layeredPane.add(panel);
layeredPane.setLayer(panel, PANELS_FIRST_POS + i);
panels.add(panel);
}
layeredPane.setLayout(new CardLayout());
}
private JPanel createControlPanel() {
ActionListener aListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() instanceof JButton ) {
moveToTop(((JButton) e.getSource()).getActionCommand() );
}
}
};
JPanel controls = new JPanel();
controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS));
JButton blueViewBtn = new JButton(BLUE_PANEL);
blueViewBtn.setActionCommand(BLUE_PANEL);
blueViewBtn.addActionListener(aListener);
controls.add(blueViewBtn);
JButton redViewBtn = new JButton(RED_PANEL);
redViewBtn.setActionCommand(RED_PANEL);
redViewBtn.addActionListener(aListener);
controls.add(redViewBtn);
JButton greenViewBtn = new JButton(GREEN_PANEL);
greenViewBtn.setActionCommand(GREEN_PANEL);
greenViewBtn.addActionListener(aListener);
controls.add(greenViewBtn);
return controls;
}
private void moveToTop(String panelName) {
for(int i = 0; i < panelNames.length; i++) {
if(panelNames[i].equals(panelName)) {
layeredPane.setLayer(panels.get(i),TOP_POSITION);
} else {
layeredPane.setLayer(panels.get(i), PANELS_FIRST_POS + i);
}
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Layered Card Panel Simulation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new LayeredCardPanel();
newContentPane.setPreferredSize(new Dimension(300,100));
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
});
}
}
基本上您没有使用 CardLayout。即使您没有 setLayout(...)
语句,您的代码也能正常工作。
当您使用 CardLayout 时:
- 布局管理器只能跟踪您设置布局管理器后添加的卡片。
- 一次只显示一个组件,这是你不想要的,因为你想玩面板透明度
编辑:
当您在将面板添加到分层窗格后设置 CardLayout 时,CardLayout 不会处理它们。结果,所有面板都保持可见。显然,所有发生的事情都是 CardLayout 将设置每个面板的大小以填充可用的 space,因此绘画似乎可以正常工作。
当我修改您的 SSCCE 以在添加面板之前设置 CardLayout 时,CardLayout 会管理面板。因此 CardLayout 在除第一个添加的面板之外的所有面板上调用 setVisible(false),这在 SSCCE 中是蓝色面板。因此,即使您尝试将不同的面板移到前面,您也只会看到蓝色面板。
通过对 SSCCE 进行以下更改可以轻松验证这一点:
layeredPane.setLayer(panel, PANELS_FIRST_POS + i);
System.out.println(panel.isVisible());
所以是的,使用 CardLayout 确实是一种 hack,不是 CardLayout 的预期使用方式或 JLayeredPane 的预期使用方式。
JLayeredPane 实际上是要与空布局一起使用,这意味着您负责设置每个组件的大小。为了获得更好的解决方案,我建议您需要将 ComponentListener
添加到分层窗格。然后你应该处理 componentResized(...)
事件。然后,您将遍历添加到分层窗格的所有组件,并将每个组件的大小设置为等于分层窗格的大小。
我应用的解决方案如下:我更改了承包商,因此 layeredPane 使用自定义布局管理器 Layout()
:
public LayeredCardPanel() {
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(createControlPanel());
layeredPane = new JLayeredPane();
layeredPane.setLayout(new Layout());
add(layeredPane);
//add 3 panel
for (int i = 0; i < panelNames.length; i++) {
JPanel panel = new JPanel();
panel.setBackground(panelColors[i]);
layeredPane.add(panel);
layeredPane.setLayer(panel, PANELS_FIRST_POS + i);
panels.add(panel);
}
}
Layout()
扩展 CardLayout
覆盖 addLayoutComponent
不做任何事情:
class Layout extends CardLayout{
@Override
public void addLayoutComponent(String name, Component comp) {
// override to do nothing
}
}
我试图将一些 JPanel
一个放在另一个之上,完全重叠。
我使用 JLayeredPane
将它们置于不同的 "depth" 中,这样我就可以更改深度和不透明度以查看某个面板 "under" 另一个。
这是我做的一个小测试,它工作正常:
public class LayeredCardPanel extends JPanel {
private static final String BLUE_PANEL = "blue ";
private static final String RED_PANEL = "red ";
private static final String GREEN_PANEL = "green";
private String[] panelNames = { BLUE_PANEL, RED_PANEL, GREEN_PANEL };
private Color[] panelColors = { Color.BLUE, Color.RED, Color.GREEN };
private List<JPanel> panels = new ArrayList<>();
private final int TOP_POSITION = 30;
private static final int PANELS_FIRST_POS = 10;
private JLayeredPane layeredPane;
public LayeredCardPanel() {
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(createControlPanel());
layeredPane = new JLayeredPane();
////////////////////////////////////////////////////////////////
//setting layout here results in all grey, non functioning panel.
//layeredPane.setLayout(new CardLayout(0, 0));
//////////////////////////////////////////////////////////////
add(layeredPane);
//adding 3 panel
for (int i = 0; i < panelNames.length; i++) {
JPanel panel = new JPanel();
panel.setBackground(panelColors[i]);
layeredPane.add(panel);
layeredPane.setLayer(panel, PANELS_FIRST_POS + i);
panels.add(panel);
}
////////////////////////////////////////////////////////////
//setting the card here, after adding panels, works fine
layeredPane.setLayout(new CardLayout(0, 0));
//////////////////////////////////////////////////////////
}
测试结果如下所示:
正如您在 ////// 注释行之间看到的那样,仅当我将 CardLayout
设置为 JLayeredPane
after[=38 时,此测试才能正常工作=] 我添加 JPanel
s 到它。
在我看来,JPanel
是使用默认布局管理器添加到 JLayeredPane
中的。布局(设置和更改边界以填充 JLayeredPane
)由后来应用的 CardLayout
.
我的问题是:虽然这符合我的需要,但解决方案(使用一个布局管理器添加,然后替换它以实现我想要的布局)并没有看起来是一个优雅的解决方案。我正在寻找更好的方法来做到这一点。
这是整个 SSCE:
public class LayeredCardPanel extends JPanel {
private static final String BLUE_PANEL = "blue ";
private static final String RED_PANEL = "red ";
private static final String GREEN_PANEL = "green";
private String[] panelNames = { BLUE_PANEL, RED_PANEL, GREEN_PANEL };
private Color[] panelColors = { Color.BLUE, Color.RED, Color.GREEN };
private List<JPanel> panels = new ArrayList<>();
private final int TOP_POSITION = 30;
private static final int PANELS_FIRST_POS = 10;
private JLayeredPane layeredPane;
public LayeredCardPanel() {
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(createControlPanel());
layeredPane = new JLayeredPane();
add(layeredPane);
//add 3 panel
for (int i = 0; i < panelNames.length; i++) {
JPanel panel = new JPanel();
panel.setBackground(panelColors[i]);
layeredPane.add(panel);
layeredPane.setLayer(panel, PANELS_FIRST_POS + i);
panels.add(panel);
}
layeredPane.setLayout(new CardLayout());
}
private JPanel createControlPanel() {
ActionListener aListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() instanceof JButton ) {
moveToTop(((JButton) e.getSource()).getActionCommand() );
}
}
};
JPanel controls = new JPanel();
controls.setLayout(new BoxLayout(controls, BoxLayout.Y_AXIS));
JButton blueViewBtn = new JButton(BLUE_PANEL);
blueViewBtn.setActionCommand(BLUE_PANEL);
blueViewBtn.addActionListener(aListener);
controls.add(blueViewBtn);
JButton redViewBtn = new JButton(RED_PANEL);
redViewBtn.setActionCommand(RED_PANEL);
redViewBtn.addActionListener(aListener);
controls.add(redViewBtn);
JButton greenViewBtn = new JButton(GREEN_PANEL);
greenViewBtn.setActionCommand(GREEN_PANEL);
greenViewBtn.addActionListener(aListener);
controls.add(greenViewBtn);
return controls;
}
private void moveToTop(String panelName) {
for(int i = 0; i < panelNames.length; i++) {
if(panelNames[i].equals(panelName)) {
layeredPane.setLayer(panels.get(i),TOP_POSITION);
} else {
layeredPane.setLayer(panels.get(i), PANELS_FIRST_POS + i);
}
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Layered Card Panel Simulation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new LayeredCardPanel();
newContentPane.setPreferredSize(new Dimension(300,100));
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
});
}
}
基本上您没有使用 CardLayout。即使您没有 setLayout(...)
语句,您的代码也能正常工作。
当您使用 CardLayout 时:
- 布局管理器只能跟踪您设置布局管理器后添加的卡片。
- 一次只显示一个组件,这是你不想要的,因为你想玩面板透明度
编辑:
当您在将面板添加到分层窗格后设置 CardLayout 时,CardLayout 不会处理它们。结果,所有面板都保持可见。显然,所有发生的事情都是 CardLayout 将设置每个面板的大小以填充可用的 space,因此绘画似乎可以正常工作。
当我修改您的 SSCCE 以在添加面板之前设置 CardLayout 时,CardLayout 会管理面板。因此 CardLayout 在除第一个添加的面板之外的所有面板上调用 setVisible(false),这在 SSCCE 中是蓝色面板。因此,即使您尝试将不同的面板移到前面,您也只会看到蓝色面板。
通过对 SSCCE 进行以下更改可以轻松验证这一点:
layeredPane.setLayer(panel, PANELS_FIRST_POS + i);
System.out.println(panel.isVisible());
所以是的,使用 CardLayout 确实是一种 hack,不是 CardLayout 的预期使用方式或 JLayeredPane 的预期使用方式。
JLayeredPane 实际上是要与空布局一起使用,这意味着您负责设置每个组件的大小。为了获得更好的解决方案,我建议您需要将 ComponentListener
添加到分层窗格。然后你应该处理 componentResized(...)
事件。然后,您将遍历添加到分层窗格的所有组件,并将每个组件的大小设置为等于分层窗格的大小。
我应用的解决方案如下:我更改了承包商,因此 layeredPane 使用自定义布局管理器 Layout()
:
public LayeredCardPanel() {
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(createControlPanel());
layeredPane = new JLayeredPane();
layeredPane.setLayout(new Layout());
add(layeredPane);
//add 3 panel
for (int i = 0; i < panelNames.length; i++) {
JPanel panel = new JPanel();
panel.setBackground(panelColors[i]);
layeredPane.add(panel);
layeredPane.setLayer(panel, PANELS_FIRST_POS + i);
panels.add(panel);
}
}
Layout()
扩展 CardLayout
覆盖 addLayoutComponent
不做任何事情:
class Layout extends CardLayout{
@Override
public void addLayoutComponent(String name, Component comp) {
// override to do nothing
}
}