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

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

ただいまの
回答率

88.35%

JFrameでのJPanelの切り替えについて

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 7,784

Hosaka246

score 17

前提・実現したいこと

(例)Java(UIはJFrame)でゲームを作っているのですが、JPanelの切り替えをJFrameで行おうとしています。
しかし、JPanelの切り替えがうまくいきません。

なお、切り替えにはこのサイトのような切り替え方法を使っています。

発生している問題

切り替え自体はどうやら成功しているようだが、パネルのボタンの表示がされない

該当のソースコード

※作成中のゲームのため、一部関数を改変し、コメントはすべて除去した

package panels;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class MainFrame extends JFrame{
    public String[] PanelNames = {"First","Second","Third"};
    FirstPanel fp = new FirstPanel(PanelNames[0]);
    SecondPanel sp = new SecondPanel(PanelNames[1]);
    ThirdPanel tp = new ThirdPanel(PanelNames[2]);
    public JPanel[] jps = {fp,sp,tp};

    int i;

    private static final int VERTICAL = 768;
    private static final int HORIZONTAL = 1024;

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

        this.add(fp);fp.setVisible(true);
        this.add(sp);sp.setVisible(false);
        this.add(tp);tp.setVisible(false);

        setBounds(100, 100, 300, 250);

        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowClosing());

        setSize(HORIZONTAL,VERTICAL);

        setResizable(false);

        Container contentPane = getContentPane();
        contentPane.add(jps[i], BorderLayout.CENTER);

        setVisible(true);
    }

    class WindowClosing extends WindowAdapter{
        public void windowClosing(WindowEvent e) {
            int ans = JOptionPane.showConfirmDialog
                    (MainFrame.this, "本当に終了しますか?");
            if(ans == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        }
    }

    public void changeKey(JPanel jp, String str){
        System.out.println(jp.getName());
        String name = jp.getName();
        if (name==PanelNames[0]){
            fp = (FirstPanel)jp;
            fp.setVisible(false);
            System.out.println("〇");
        } else if (name==PanelNames[1]){
            sp = (SecondPanel)jp;
            sp.setVisible(false);
            System.out.println("●");
        } else if (name==PanelNames[2]){
            tp = (ThirdPanel)jp;
            tp.setVisible(false);
            System.out.println("◎");
        } else {
            System.out.println("huh?");
        }


        if (str==PanelNames[0]){
            fp.setVisible(true);
            //iで切り替え!
            i = 0;
            System.out.println("△");
        } else if (str==PanelNames[1]){
            sp.setVisible(true);
            i = 1;
            System.out.println("▼");
        } else if (str==PanelNames[2]){
            tp.setVisible(true);
            i = 2;
            System.out.println("▲");
        } else {
            System.out.println("huh?");
        }
    }
}

package panels;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JPanel;

package panels;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class FirstPanel extends JPanel implements ActionListener{
    String str;

    public FirstPanel(String s){
        str = s;
        this.setName("First");
        //setLocationRelativeTo(null);
        setLayout(null);

        JLabel titleLabel = new JLabel("FirstPanel");

        titleLabel.setBounds(270, 100, 512, 100);

        titleLabel.setFont(new Font("MS ゴシック", Font.BOLD, 64));
        titleLabel.setHorizontalTextPosition(JLabel.CENTER);

        JButton buttonOne = new JButton("One");
        buttonOne.setBounds(256, 350, 512, 50);
        buttonOne.addActionListener(this);
        buttonOne.setActionCommand("One");

        JButton buttonTwo = new JButton("Two");
        buttonTwo.setBounds(256, 400, 512, 50);
        buttonTwo.addActionListener(this);
        buttonTwo.setActionCommand("Two");

        JButton buttonThree = new JButton("Three");
        buttonThree.setBounds(256, 4050, 512, 50);
        buttonThree.addActionListener(this);
        buttonThree.setActionCommand("Three");

        JButton buttonFour = new JButton("Four");
        buttonFour.setBounds(256, 500, 512, 50);
        buttonFour.addActionListener(this);
        buttonFour.setActionCommand("Four");

        JButton buttonFive = new JButton("Five");
        buttonFive.setBounds(256, 550, 512, 50);
        buttonFive.addActionListener(this);
        buttonFive.setActionCommand("Five");

        add(titleLabel);
        add(buttonOne);
        add(buttonTwo);
        add(buttonThree);
        add(buttonFour);
        add(buttonFive);

    }


    @Override
    public void actionPerformed(ActionEvent e) {
        String cmd = e.getActionCommand();
        System.out.println(cmd);

        switch(cmd){

        case "One":
            break;
        case "Two":
            break;
        case "Three":
            break;
        case "Four":
            break;
        case "Five":
            System.exit(0);
            break;

            default:
                //何もない場合はreturnで切る
                return;
        }

    }
}
※SecondPanel、ThirdPanelはこれと同じなので省略

試したこと

  • SecondPanelのみをMainにして起動→動作する
  • MainFrameのFirstPanelをfalseにしてSecondPanelをtrueにする→動作しない(ThirdPanelでも動作しない)
  • 切り替え時にコンソール上に文字を表記→切り替え時の文字は表記される
  • FirstPanelからFirstPanelに転送→表示される

補足情報(言語/FW/ツール等のバージョンなど)

Java8(Eclipse)

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • umyu

    2017/05/11 09:49

    多分、行いたいことはゲームのシーン遷移だと思いますがー。。質問文のコードではコンパイルエラーになります! 1,FirstPanelのコンストラクタが一致してません。2,MainFrameコンストラクタのsuper(Main.title);3,同コンストラクタdp.setVisible(false);

    キャンセル

  • Hosaka246

    2017/05/11 18:36

    失礼しました…

    キャンセル

回答 1

checkベストアンサー

+1

JPanelの切り替えにCardLayoutを使用。

MainFrame クラス

package panels;

import java.awt.Container;
import java.awt.event.WindowAdapter;

import java.awt.CardLayout;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import java.util.Arrays;

public class MainFrame extends JFrame {
    public String[] PanelNames = { "First", "Second", "Third" };
    JPanel fp = new FirstPanel(this, PanelNames[0]);
    JPanel sp = new SecondPanel(this, PanelNames[1]);
    JPanel tp = new ThirdPanel(this, PanelNames[2]);
    public JPanel[] jps = { fp, sp, tp };
    private final CardLayout layout = new CardLayout();//カードレイアウト

    private static final int VERTICAL = 768;
    private static final int HORIZONTAL = 1024;

    public MainFrame() {
        super("Test");
        setBounds(100, 100, 300, 250);
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowClosing());
        setSize(HORIZONTAL, VERTICAL);
        // CardLayoutを使用。
        Container contentPane = getContentPane();
        JPanel mainPanel = new JPanel();
        mainPanel.setLayout(layout);
        for (JPanel panel : jps){
            mainPanel.add(panel, panel.getName());
        }
        contentPane.add(mainPanel);

        setResizable(false);
        setVisible(true);
    }

    class WindowClosing extends WindowAdapter {
        public void windowClosing(WindowEvent e) {
            int ans = JOptionPane.showConfirmDialog(MainFrame.this, "本当に終了しますか?");
            if (ans == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        }
    }

    // changeKey=>changePanelにメソッド名を変更して、引数を1個に
    public void changePanel(String str) {
        int index = Arrays.asList(PanelNames).indexOf(str);
        layout.show(jps[index].getParent(), jps[index].getName());
    }
}


FirstPanelクラス

package panels;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class FirstPanel extends JPanel implements ActionListener{
    private final String str;
    private final MainFrame frame; // インスタンス変数でMainFrameの参照を保持
    public FirstPanel(MainFrame f, String s){
        str = s;
        frame = f;
        this.setName(s);//固定文字列ではなく、コンストラクタで渡された文字列に変更
        //setLocationRelativeTo(null);
        setLayout(null);

        JLabel titleLabel = new JLabel(s);//固定文字列ではなく、コンストラクタで渡された文字列に変更

        titleLabel.setBounds(270, 100, 512, 100);

        titleLabel.setFont(new Font("MS ゴシック", Font.BOLD, 64));
        titleLabel.setHorizontalTextPosition(JLabel.CENTER);

        JButton buttonOne = new JButton("One");
        buttonOne.setBounds(256, 350, 512, 50);
        buttonOne.addActionListener(this);
        buttonOne.setActionCommand("One");

        JButton buttonTwo = new JButton("Two");
        buttonTwo.setBounds(256, 400, 512, 50);
        buttonTwo.addActionListener(this);
        buttonTwo.setActionCommand("Two");

        JButton buttonThree = new JButton("Three");
        // setBounds の引数y 4050=> 450
        buttonThree.setBounds(256, 450, 512, 50);
        buttonThree.addActionListener(this);
        buttonThree.setActionCommand("Three");

        JButton buttonFour = new JButton("Four");
        buttonFour.setBounds(256, 500, 512, 50);
        buttonFour.addActionListener(this);
        buttonFour.setActionCommand("Four");

        JButton buttonFive = new JButton("Five");
        buttonFive.setBounds(256, 550, 512, 50);
        buttonFive.addActionListener(this);
        buttonFive.setActionCommand("Five");

        add(titleLabel);
        add(buttonOne);
        add(buttonTwo);
        add(buttonThree);
        add(buttonFour);
        add(buttonFive);

    }


    @Override
    public void actionPerformed(ActionEvent e) {
        String cmd = e.getActionCommand();
        System.out.println(cmd);

        switch(cmd){

        case "One":
            //MainFrame#changePanelを呼び出す。
            frame.changePanel("First");
            break;
        case "Two":
            frame.changePanel("Second");
            break;
        case "Three":
            break;
        case "Four":
            frame.changePanel("Third");
            break;
        case "Five":
            System.exit(0);
            break;

            default:
                //何もない場合はreturnで切る
                return;
        }

    }
}

MainFrame#changeKeyメソッドでFirstPanelをsetVisible(false);にすると親のcontentPaneが表示されて遷移したように見えるだけなのです。

Swingのコンポーネントのデバックをする時は、
JFrameをクリックしてフォーカスを当てた状態でCTRL+Shit+F1キーを押下すると、コンソールにSwingのコンポーネントツリーが出力されます。


画面遷移の管理について

  1. 遷移を管理するためのシーンクラスを作成(シングルトン)
  2. 画面の遷移元と遷移先をツリー構造で管理する。

JFrameを継承したクラスにいろいろな処理を書くのは個人的に好きではないのでこれがベターだと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/05/12 09:27

    ありがとうございました。これで動くようになりました。CardLayoutも一度は考えたのですが難しくてやめてしまいましたが、これでできるようになりました。これからも頑張りたいです。

    キャンセル

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

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

関連した質問

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