【发布时间】:2012-07-16 17:44:21
【问题描述】:
我只是无法通过 JLayeredPanes 上的第一格。 (请参阅我的original question of yesterday。我一直在研究 JLayeredPane 教程和 API。这些教程与我最终尝试制作的内容有些不同。
回到第一点,我采用了 Oracle 的 JFrame 示例并对其进行了修改以包含分层窗格。
代码如下:
package components;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/* FrameDemo.java requires no other files. */
public class FrameDemo {
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainLayer = new JPanel(new BorderLayout());
mainLayer.setPreferredSize(new Dimension(640, 480));
frame.setContentPane(mainLayer);
frame.getLayeredPane().add(mainLayer, JLayeredPane.DEFAULT_LAYER, 0);
JLabel emptyLabel = new JLabel("LABEL");
emptyLabel.setPreferredSize(new Dimension(320, 240));
mainLayer.add(emptyLabel, BorderLayout.NORTH);
JPanel subLayer = new JPanel(new BorderLayout());
JLabel subLabel = new JLabel("SUBLABEL");
subLabel.setPreferredSize(new Dimension( 200, 100));
subLabel.setBackground(Color.YELLOW);
subLayer.add(subLabel, BorderLayout.SOUTH);
subLayer.setVisible(true);
subLabel.setVisible(true);
frame.getLayeredPane().add(subLayer, JLayeredPane.PALETTE_LAYER, 0);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
为什么它不起作用? IOW,为什么子标签不显示?它比主层更高。
一个想法是为什么我将 mainLayer 添加到内容窗格和分层窗格中?如果我不这样做,什么都不会出现。即,通过注释掉这一行,我只会得到一个空白框。
// frame.setContentPane(mainLayer);
显然,我不明白一些事情。但它是什么?
我应该补充一点,这个简单的演示可以在没有分层窗格的情况下完成。但我的最终目标是拥有一个可以通过编程方式打开和关闭的层。但我什至无法让这个简单的案例起作用。如果我能克服这个困难,我想剩下的会更容易。
附录:
下面的代码说明了我想要实现的目标,它与下面的 TrashGod 设置非常相似,并且可以正常工作。有一个 JLayeredPane 具有一个常量层(在 Integer(0) 处分层)和一个浮动层,最初在 Integer(-1) 处分层,但可通过 Integer(-1) 层和 Integer(1) 之间的 F7 和 F8 键击切换层,从而允许它浮动在常量层之上或之下。
package components;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/* MyLayeredPaneDemo.java requires no other files. */
public class MyLayeredPaneDemo {
private JFrame frame;
private JLayeredPane mainPanel;
private JPanel constantLayer;
private JPanel floatingLayer;
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private MyLayeredPaneDemo() {}
private void createAndShowGUI() {
//Create and set up the window.
this.frame = new JFrame("MyLayeredPaneDemo");
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frame.setPreferredSize(new Dimension(640, 480));
mainPanel = new JLayeredPane();
constantLayer = new JPanel(new BorderLayout(0,0));
floatingLayer = new JPanel(new BorderLayout(0,0));
// constantLayer.setPreferredSize();
constantLayer.setOpaque(true);
constantLayer.setBackground(Color.BLUE);
JLabel constantLabel = new JLabel("MAIN LAYER");
constantLayer.setPreferredSize(new Dimension(640, 480));
constantLayer.add(constantLabel, BorderLayout.CENTER);
JLabel subLabel = new JLabel("SUB LAYER");
floatingLayer.setBackground(Color.YELLOW);
floatingLayer.add(subLabel, BorderLayout.SOUTH);
floatingLayer.setOpaque(true);
floatingLayer.setVisible(true);
floatingLayer.setVisible(true);
subLabel.setBackground(Color.YELLOW);
mainPanel.add(constantLayer, new Integer(0), 0);
constantLayer.setBounds(0,0,640,480);
mainPanel.add(floatingLayer, new Integer(-1), 0);
floatingLayer.setBounds(100, 360, 300, 90 );
frame.add(mainPanel, BorderLayout.CENTER);
//Display the window.
mapKeyToAction(frame.getRootPane(),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0),
"Hide Layer",
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("F7 pressed");
mainPanel.setLayer(floatingLayer, new Integer(-1));
}
});
mapKeyToAction(frame.getRootPane(),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0),
"Show Layer",
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("F8 pressed");
mainPanel.setLayer(floatingLayer, new Integer(1));
}
});
frame.pack();
frame.setVisible(true);
frame.getRootPane().setFocusable(true);
boolean ok = frame.getRootPane().requestFocusInWindow();
System.out.println("focus ok: " + ok);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MyLayeredPaneDemo().createAndShowGUI();
}
});
}
private static void mapKeyToAction(JComponent component,
int whichMap, KeyStroke keystroke,String key, Action action) {
component.getInputMap(whichMap).put(keystroke, key);
component.getActionMap().put(key, action);
}
}
但是,在我的实际情况下,我无法让它发挥作用。两者之间的区别在于,在这里,我的 JLayeredPane 由 Frame 拥有,而在我的实际应用程序中,我希望 JLayeredPane 由 JPanel 拥有,因为 Frame 包含层次结构中的某些级别,其大小为由其父级中的 GridBagLoyout 设置,因此在调用其构造函数时大小是未知的,因此很难调用我需要对 JLayeredPane 的子级执行的 setBounds()。
进一步的附录。我知道 Oracle 教程提到了 case where Layouts rather than absolute positioning is used with a JLayeredPane。这种情况和我的不同之处在于,在我的情况下,层在不同层上占据相同的水平空间,而在这种情况下,不同层上的组件占据不同的水平空间。就好像我们需要一个 3D 布局管理器一样!
【问题讨论】:
-
进一步评论。我看过 Oracle 的 RootLayeredPaneDemo 教程。这是一个非常混乱的演示。框架将其分层窗格传递给主类,该主类是一个 JPanel,它成为框架的内容窗格。然后在此 JPanel 的构造函数中将几个组件添加到该分层窗格中,即使主 (JPanel) 类中没有包含分层窗格。我上面的代码似乎遵循 RootLayeredPaneDemo 的包含模型,但事实并非如此。事物被实例化、添加到容器和可见的顺序是否重要?
-
我没有时间详细分析,但我突然想到的一件事是,您将 maimLayer 设置为内容,然后将其添加到框架分层窗格中。一个组件只能有一个父级,这有效地删除了内容 psne
-
这个评论说的很对。这让我一分钱一分货。不幸的是,我仍然遇到 JLayeredPanes 的问题,我将在此处或稍后在新问题中进行描述。
标签: java swing jlayeredpane