JLayeredPanes で振り出しを通過できません。(昨日の元の質問を参照してください。私は JLayeredPane チュートリアルと API を研究してきました。これらのチュートリアルは、私が最終的に作成しようとしているものとは多少異なります。
振り出しに戻ると、私は Oracle の JFrame Example を取り上げ、レイヤード ペインを含めるように修正しました。
コードは次のとおりです。
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、サブラベルが表示されないのはなぜですか? メインレイヤーよりも高いレベルにあります。
考えられることの 1 つは、コンテンツ ペインとレイヤード ペインの両方に mainLayer を追加する理由です。そうしないと、何も表示されません。つまり、この行をコメントアウトすると、空白のフレームが表示されます。
// frame.setContentPane(mainLayer);
明らかに、私は何かを理解していません。しかし、それは何ですか?
明らかに、この単純なデモはレイヤード ペインなしで実行できることを付け加えておきます。しかし、私の最終的な目標は、プログラムでオンとオフを切り替えることができるレイヤーを用意することです。しかし、この単純なケースを機能させることさえできません。このこぶを乗り越えることができれば、あとは楽になると思います。
補遺:
私が達成したいことは、次のコードで示されています。これは、TrashGod が以下に設定したものと非常によく似ており、機能します。定数レイヤー (Integer(0) でレイヤー化) と最初に Integer(-1) でレイヤー化されたフローティング レイヤーを持つ JLayeredPane がありますが、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);
}
}
ただし、実際のケースではこれを機能させるのに問題があります。この 2 つの違いは、ここでは JLayeredPane が Frame によって所有されているのに対し、実際のアプリケーションでは JLayeredPane が JPanel によって所有されるようにしたいということです。これは、Frame から包含階層のいくつかのレベルが下がっており、そのサイズが親の GridBagLoyout によって設定されるため、コンストラクターが呼び出された時点ではサイズがわからないため、JLayeredPane の子で行う必要がある setBounds() の呼び出しが困難になります。
さらなる補遺。Oracle チュートリアルでは、絶対配置ではなくレイアウトが JLayeredPane で使用されるケースについて言及していることを知っています。この場合と私の場合の違いは、私の場合、レイヤーは異なるレイヤーで同じ水平方向のスペースを占めるのに対し、この場合、異なるレイヤーのコンポーネントは異なる水平方向のスペースを占めることです。まるで 3D Layout Manager が必要であるかのようです!