質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.35%

JLayeredPaneでFlowLayoutを使う

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 914

score 109

問題

(1)
Main.FrameにFlowLayoutを適用したのですが、実行するとlabelsが横一列に並び期待した見た目にはなりませんでした。

下の方に書いてある「ソースコード(期待する見た目)」ではJLayeredPaneを使用していないのですが、Window.java内にあるlabelsを背面においてlabelを前面においておきたいのでJLayeredPaneを使用しました。

(2)

label.setLocation(50, 50);


としてlabelの位置を変えたつもりですが、反映されませんでした。

この2つの問題が解決せず、質問しました。
どうぞよろしくお願いします。

ソースコード

Main.java

import javax.swing.SwingUtilities;

public class Main {

    private final static int rows = 5;
    private final static int columns = 5;

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Window(rows, columns).setVisible(true);
            }
        });

    }

}

Window.java

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.border.LineBorder;

public class Window extends JFrame {

    private final int rows;
    private final int columns;

    Window(final int rows, final int columns) {
        this.rows = rows;
        this.columns = columns;
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(500, 150, columns * 80 + 20, rows * 80 + 40);
        setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));

        Movement mv = new Movement();

        Frame frame = new Frame(rows, columns);
        add(frame);

    }

    public class Frame extends JLayeredPane {

        Frame(final int rows, final int columns) {
            setSize(columns * 80 + 20, rows * 80 + 40);
            setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));

            Movement mv = new Movement();

            JLabel[][] labels = new JLabel[rows][columns];
            for(int i = 0; i < rows; i++) {
                for(int j = 0; j < columns; j++) {
                    labels[i][j] = new JLabel();
                    labels[i][j].setPreferredSize(new Dimension(80, 80));
                    labels[i][j].setText(i + ", " + j);
                    labels[i][j].setBorder(new LineBorder(Color.BLACK, 2, true));
                    labels[i][j].setOpaque(true);
                    labels[i][j].setBackground(Color.WHITE);
                    add(labels[i][j]);
                    setLayer(labels[i][j], DEFAULT_LAYER);
                }
            }

            JLabel label = new JLabel("Label");
            label.setPreferredSize(new Dimension(80, 80));
            label.setLocation(50, 50);
            label.setBorder(new LineBorder(Color.BLACK, 5, true));
            label.setOpaque(true);
            label.setBackground(Color.WHITE);
            add(label);
            setLayer(label, DRAG_LAYER);
            mv.addMovementListener(label);

        }

    }

}

Movement.java

package que;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JLabel;

public class Movement implements MouseListener, MouseMotionListener {

    private int X, Y;

    public Movement() {}

    public void addMovementListener(JLabel... labels) {
        for(JLabel label : labels) {
            label.addMouseListener(this);
            label.addMouseMotionListener(this);
        }
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        e.getComponent().setLocation(e.getX() + e.getComponent().getX() - X, e.getY() + e.getComponent().getY() - Y);
    }

    @Override
    public void mouseMoved(MouseEvent e) {}

    @Override
    public void mouseClicked(MouseEvent e) {}

    @Override
    public void mousePressed(MouseEvent e) {
        X = e.getX();
        Y = e.getY();
    }

    @Override
    public void mouseReleased(MouseEvent e) {}

    @Override
    public void mouseEntered(MouseEvent e) {}

    @Override
    public void mouseExited(MouseEvent e) {}

}

ソースコード(期待する見た目)

Main.javaとMovement.javaは同じ

Window.java

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.border.LineBorder;

public class Window extends JFrame {

    private final int rows;
    private final int columns;

    Window(final int rows, final int columns) {
        this.rows = rows;
        this.columns = columns;
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(500, 150, columns * 80 + 20, rows * 80 + 40);
        setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));

        Movement mv = new Movement();

        JLabel[][] labels = new JLabel[rows][columns];
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < columns; j++) {
                labels[i][j] = new JLabel();
                labels[i][j].setPreferredSize(new Dimension(80, 80));
                labels[i][j].setText(i + ", " + j);
                labels[i][j].setBorder(new LineBorder(Color.BLACK, 2, true));
                labels[i][j].setOpaque(true);
                labels[i][j].setBackground(Color.WHITE);
                add(labels[i][j]);
            }
        }

        JLabel label = new JLabel("Label");
        label.setPreferredSize(new Dimension(80, 80));
        label.setLocation(50, 50);
        label.setBorder(new LineBorder(Color.BLACK, 5, true));
        label.setOpaque(true);
        label.setBackground(Color.WHITE);
        add(label);
        mv.addMovementListener(label);

    }

}

期待する見た目

期待する見た目
(↑ではlabelがlabelsの背面にありますが、期待するのはlabelを前面にすることです。)

その他

Eclipse 2019-06
Java SE 8

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

labelsを背面においてlabelを前面においておきたいのでJLayeredPaneを使用

されたのに, JLayeredPane をそのように使用していないように思います.
ドキュメントの「詳細」をご確認頂くと良いかと思います.

JLayeredPane (Java Platform SE 8)

詳細
JLayeredPaneは、Containerと同じように子のリストを管理しますが、内部で複数のレイヤーを定義することができます。同じレイヤーに属する子は、通常のContainerオブジェクトとまったく同じように管理されますが、子コンポーネントどうしがオーバーラップした場合には、上位のレイヤーのコンポーネントの方が下位レイヤーのコンポーネントより上に表示されます。
各レイヤーには個別の整数値が割り当てられます。Componentのレイヤー属性を設定するには、add呼出しでIntegerオブジェクトを渡します。
たとえば、
(以下略)


以下で labels の上に label が表示されました.
Frame コンストラクタ内での setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); では, レイアウトマネージャが全てのコンポーネントの配置を司る為に, setLocation が効かず label も並べてしまい, (確認していませんが)描画領域が制限されずに全て横一列に並べた上で中央部分を表示していたものと思われます.
また, Window コンストラクタ内の setLayout が有効では(これも原因は確認していませんが)表示がされませんでしたので, コメントにしました.

Window.java

import java.awt.Color;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.border.LineBorder;

import que.Movement;

public class Window extends JFrame {

    private final int rows;
    private final int columns;

    Window(final int rows, final int columns) {
        this.rows = rows;
        this.columns = columns;
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(500, 150, columns * 80 + 20, rows * 80 + 40);
        //setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));

        Movement mv = new Movement();

        Frame frame = new Frame(rows, columns);
        add(frame);
    }

    public class Frame extends JLayeredPane {
        Frame(final int rows, final int columns) {
            setSize(columns * 80 + 20, rows * 80 + 40);
            //setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
            setLayout(null);

            Movement mv = new Movement();

            JLabel[][] labels = new JLabel[rows][columns];
            for(int i = 0; i < rows; i++) {
                for(int j = 0; j < columns; j++) {
                    labels[i][j] = new JLabel();
                    labels[i][j].setBounds(i * 80, j * 80, 80, 80);
                    labels[i][j].setText(i + ", " + j);
                    labels[i][j].setBorder(new LineBorder(Color.BLACK, 2, true));
                    labels[i][j].setOpaque(true);
                    labels[i][j].setBackground(Color.WHITE);
                    add(labels[i][j], DEFAULT_LAYER);
                }
            }

            JLabel label = new JLabel("Label");
            label.setBounds(50, 50, 80, 80);
            label.setBorder(new LineBorder(Color.BLACK, 5, true));
            label.setOpaque(true);
            label.setBackground(Color.WHITE);
            add(label, DRAG_LAYER);

            mv.addMovementListener(label);
        }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/04 14:46

    期待通りの画面になりました。ありがとうございます。
    質問が解決したのですが、この問題を調べているときにSOでたまにsetLayout(null)は推奨しないなどのコメントを見ました。ただ私はこれが何故なのかが理解できません。もし何か知っていれば教えてください。

    キャンセル

  • 2019/09/04 18:07 編集

    個人的な考えとしましては, Swing のレイアウトは(ウインドウの拡縮や各コンポーネントの位置・大きさの変動に対し)レイアウトマネージャによって自動的に調整する形にするのが目指す形であり, レイアウトマネージャを null とするということはつまり setLocation 等で固定することになり拡縮等に適切に対応出来ないためということかと思います.

    これは Windows 等では分かり難いかもしれませんが, Android のようにディスプレイサイズそのものが多種多様にある状態ですと, テストした機種では丁度良くても, ディスプレイが大きな機種ではコンテンツが小さく纏まって空白ばかり多くなってしまいますし, 小さい機種では入りきらずに読めないとかボタンが押せない等となります. そうならないようにするためにはディスプレイの大きさによって各種計算を行い適切に配置する必要があり, それを担うのがレイアウトマネージャということになります.
    (Android では Swing は使いませんが, 位置や大きさを相対的にする(具体的な値は計算される)ほうが良いことは同じです.)

    キャンセル

  • 2019/09/04 18:43

    なるほど、分かりやすい説明ありがとうございます。
    今回制作するものは画面のサイズを変更する必要が無いのでその点は問題ないかと思います。
    回答ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る