3

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 が必要であるかのようです!

4

2 に答える 2

4

「デフォルトでは、レイヤード ペインにはレイアウト マネージャーがありません。」—<a href="http://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html" rel="nofollow noreferrer">方法階層化されたペインを使用する

補遺:のレイヤード ペインの使用を避け Frame、代わりにレイヤード ペインを window に追加する必要があります。

はい、ルート ペインは のインスタンスでありJRootPane、これには が含まれていJLayeredPaneます。特に、「レイヤード ペインにはメニュー バーとコンテンツ ペインが含まれ、他のコンポーネントの Z オーダーが可能になります。」

ここに画像の説明を入力

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

public class FrameDemo {

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("FrameDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JLayeredPane mainLayer = new JLayeredPane();
        frame.add(mainLayer, BorderLayout.CENTER);

        JLabel label = new JLabel("LABEL", JLabel.CENTER);
        label.setBounds(100, 100, 200, 100);
        label.setOpaque(true);
        label.setBackground(Color.cyan);
        mainLayer.add(label, 1);

        JPanel subLayer = new JPanel(new BorderLayout());
        JLabel subLabel = new JLabel("SUBLABEL", JLabel.CENTER);
        subLabel.setBounds(20, 20, 200, 100);
        subLabel.setOpaque(true);
        subLabel.setBackground(Color.yellow);
        subLayer.add(subLabel, BorderLayout.SOUTH);
        mainLayer.add(subLabel, 2);

        frame.pack();
        frame.setSize(320, 240);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
于 2012-07-18T01:49:58.903 に答える
1

私が思いついた解決策は、ComponentListener を実装してコンポーネントのサイズ変更イベントをキャプチャすることです。その時点で、コンテナーの実際の境界を取得し、それを使用してレイヤー JPanels の実際の境界を設定できます。レイヤー JPanels は、それらを含むコンポーネントの境界に対して常に一定の関係にあります。できます。

Trashgod のソリューションも機能すると思いますが、試したことはありません。

于 2012-07-20T02:06:17.183 に答える