Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

BorderLayoutが機能しない?

JFrameクラスを経承したクラスで、
よく使うファイルメニューをセットし、
ステータスバーに見立てたJLabelをSOUTHに配置した、
そんなクラスを作りたいと思っています。
しかし、どういうわけか、JLabelが表示されません。
pack()をつけると、ラベル自身は表示されるものの、
SOUTHに上手く配置されませんでした。

いろいろ試してみたのですが、
私のカでは原因を発見できませんでした。
ご教授いただけると幸いです。

ちなみに、JDKは1.5です。


********************************************************
ソースコード(フィールドとコンストラクタのみを抜粋)
********************************************************

    private JMenuBar mbMenuBar;
    private JMenu mFile;
    private JMenuItem miEnd;

    private JPanel mainPanel;
    private JLabel statusBar;



    public CommonWindow(String strTitle){
        super(strTitle);

        mbMenuBar = new JMenuBar();

        mFile = new JMenu("ファイル");
        miEnd = new JMenuItem("プログラムの終了");

        setJMenuBar(mbMenuBar);

        mbMenuBar.add(mFile);
            mFile.add(miEnd);


        setLayout(new BorderLayout());

        mainPanel = new JPanel();
        statusBar = new JLabel("初期化されました...");


        add(mainPanel, BorderLayout.CENTER);
        add(statusBar, BorderLayout.SOUTH);
        //pack();



        miEnd.addActionListener(this);


        addWindowListener(
            new WindowAdapter(){
                public void windowClosing(WindowEvent eWinEvent){
                    System.exit(0);
                }
            }
        );


    }

5

回答

4594

閲覧

5件の回答

評価

0

抜粋されると実験するのにも一苦労なんですが。
ソースを見ただけで分かるエラーならともかく、そうでない場合は動かして確かめる必要があります。
そういう場合、回答者になるべく負担をかけないように、すべきではないでしょうか。
全部載せるとすごいことになるでしょうから、必要なのは「問題の箇所を含んだ、動作する最低限のコード」です。

評価

0

こんにちわ。

実行してみましたが特に問題なく、JLabelは表示されました。

ぱっとみ、正しく見えるこのコード。
これは、BorderLayoutは無罪です。

addを行ったあとに再描画が抜けています。
もしくわ、CommonWindow をインスタンス化した側が
再描画を忘れていませんか?
また、このWindowを表示させた後リサイズすると正しい位置に
描画されるはずで、これはリサイズに再描画を行っているからです。

たぶん、私が問題なく動かせたのは癖で呼び出し側に書いてるからでしょう。

pack()でうまくいかないのは、描画前のサイズで位置計算を行うからだと思います。
(コンストラクタ内ではまだ表示はされていない為サイズはデフォルト値となる)

Layoutクラスは大体自動的にサイズ補正を行いますので、
pack()はほとんど使わないで済むはずです。
以上、ご参考まで。

つらつら書きましたが「親コンポーネントの再描画を忘れずに」ということで。

評価

0

すみません。
mioさんのおっしゃる通りです。
複合的な要素でトラブルが生じているかもしれないのに、
BorderLayoutの近辺だけ載せても仕方ないですよね。

で、問題の生じる最小構成のプログラムを作ってみました。
すったかさんのおっしきるような、
再描画に関しては、大丈夫かと思います。


public class Sample {

    public static void main(String param[]){
        MainFrame mfMainFrame = new MainFrame();
        mfMainFrame.setSize(480, 320);

        mfMainFrame.setLayout(new BorderLayout());

        mfMainFrame.setVisible(true);
    }

}



class MainFrame extends CommonWindow {

    JMenuItem miNew, miOpen, miOverSave, miSave;

    public MainFrame(){
        super("Sample");

        miNew = new JMenuItem("新規作成");
        miOpen = new JMenuItem("開く");
        miOverSave = new JMenuItem("上書き保存");
        miSave = new JMenuItem("名前をつけて保存");

        add(miNew);
        add(miOpen);
        add(miOverSave);
        add(miSave);
    }



}

public class CommonWindow extends JFrame {

    private JMenuBar mbMenuBar;
    private JMenu mFile;
    private JMenuItem miEnd;

    private JPanel mainPanel;
    private JLabel statusBar;


    public CommonWindow(String strTitle){
        super(strTitle);

        mbMenuBar = new JMenuBar();

        mFile = new JMenu("ファイル");
        miEnd = new JMenuItem("プログラムの終了");

        setJMenuBar(mbMenuBar);

        mbMenuBar.add(mFile);
            mFile.add(miEnd);


        setLayout(new BorderLayout());

        mainPanel = new JPanel();
        statusBar = new JLabel("初期化されました...");


        add(mainPanel, BorderLayout.CENTER);
        add(statusBar, BorderLayout.SOUTH);


        addWindowListener(
            new WindowAdapter(){
                public void windowClosing(WindowEvent eWinEvent){
                    System.exit(0);
                }
            }
        );

    }



    public void add(JMenu m){        //メニューバーに新しいメニューを追加。
        mbMenuBar.add(m);
System.out.println("test1");
    }



    public void add(JMenuItem mi){        //メニューに新しいアイテムを追加。
        mFile.insert(mi, mFile.getMenuComponentCount()-1);
System.out.println("test2");
    }


}


実は、これを作る過程で、
addをオーバーロードするのではなく、
JMenuやJMenuBarのインスタンスを取得するメソッドを用意して、
それを利用すれば解決することを発見しました。
デザイン的にもその方が良いような気がするのですが、
上の組み方で動作しない理由がわからないので、
勉強のため、どなたかご教授いただけると幸いです。

評価

0

こんにちわ。

なるほど、こうなっていましたか。
確かに再描画ではないようですね。

BorderLayoutが2回設定されているのが問題です。
親クラスでsetLayoutして形を整えているのに
使用するmainがそれを初期化してしまっています。

なのでmainのほうをコメントアウトすればOKです。

評価

0

すったかさん、ありがとうございます!

そう言われると、BoderLayoutを2回設定する必要はないですね。
BorderLayoutを使うときはsetLayoutを使わなければいけない、と、
思い込んでしまっていたので、こういうミスにつながった気がします。

これからは、1つ1つの文の意味を
しっかり吟味して勉強していきたいと思います。
ありがとうございました。

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。