JFrameにコンポーネントが追加されず真っ白い状態となる
- 評価
- クリップ 0
- VIEW 1,241
四目並べを行うプログラムを作ったのですがうまく起動してくれません。具体的には正しくコンポーネントが追加されていないようで真っ白になってしまします。コンポーネントを追加する順序にミスがあるのでしょうか...?自力では解決しなかったためご指摘のほどお願いします。また、ほかの点で改善点があれば容赦なくお願いします。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
public class GameScreen extends JPanel implements ActionListener{
private int cn; //升目の数 cn * cn
private JPanel backpane;
private JLabel telllimit;
private JLabel tellcolor;
private GameSystem s;
private Color player_c;
static JLabel timelimit;
static boolean play_turn; //現在のターンを保持
static boolean[] enter = new boolean[400]; //すべての入力を保持
static ArrayList<ArrayList<JButton>> y_coordinate = new ArrayList<ArrayList<JButton>>();
public static void main(String args[]){
JFrame jf = new JFrame();
GameScreen gs = new GameScreen(15);
jf.add(gs);
jf.setVisible(true);
}
public GameScreen(int n){
/*
* 画面生成
*/
//親パネル
super();
this.setPreferredSize(new Dimension(930,700));
this.setLayout(null);
this.setBackground(Color.GREEN);
//ターン表示のためのパネル
tellcolor = new JLabel();
tellcolor.setBackground(getPlayer_c());
tellcolor.setBounds(0, 0, 200, 200);
this.add(tellcolor);
//残り時間表示のためのパネル
telllimit = new JLabel();
telllimit.setBorder(new BevelBorder(BevelBorder.RAISED, Color.white, Color.black));
telllimit.setBounds(200, 0, 200, 430);
telllimit.setForeground(Color.WHITE);
this.add(telllimit);
//升目パネル
JPanel screen = new JPanel();
screen.setBounds(207,200,456, 516);
screen.setLayout(new GridLayout(20,20,0,0));
cn = n;
for(int i = 0;i<cn;i++){
ArrayList<JButton> x_coordinate = new ArrayList<JButton>();
for(int t = 0;t<cn;t++){
JButton cell = CreateCell(i,t);
cell.addActionListener(this);
screen.add(cell);
x_coordinate.add(cell);
}
y_coordinate.add(x_coordinate);
}
this.add(screen);
//ゲーム開始
s = new GameSystem(15);
}
public JButton CreateCell(int x,int y){
JButton btn = new JButton();
btn.setSize(10, 10);
btn.setActionCommand(x+"-"+y);
return btn;
}
public void setTelllimittext(int second){
String s= "残り時間 "+ second+"秒";
telllimit.setText(s);
}
@Override
public void actionPerformed(ActionEvent e) {
String coordinate = e.getActionCommand();
for(int k=0;k<cn;k++){
for(int j = 0;j<cn;j++){
String number = k+"-"+j;
if(coordinate.equals(number)){
int order = k*20 + j+1; //入力の番号を作成
if(play_turn == true){
player_c = Color.RED;
s.addA(order);
}else{
player_c = Color.BLUE;
s.addB(order);
}
changeTurn();
if(k == 19){ //入力が底の時
processEnter(order,k,j,player_c);
}else{ //入力が上部の時
if(enter[order+20] == false){
System.out.println("無効な入力です");
}else{
processEnter(order,k,j,player_c);
}
}
s.createCombinations();
}
}
}
return;
}
public Color getPlayer_c(){
if(play_turn == true){
player_c = Color.RED;
}else{
player_c = Color.BLUE;
}
return player_c;
}
public void changeTurn(){
if(play_turn == true){
player_c = Color.RED;
tellcolor.setBackground(Color.red);
play_turn = false;
}else{
player_c = Color.BLUE;
tellcolor.setBackground(Color.BLUE);
play_turn = true;
}
tellcolor.setBackground(getPlayer_c());
}
/* 色塗り処理 */
public void processEnter(int order,int k,int j,Color player_c){
/* 過去に入力があればtrueなければfalse */
if( enter[order] == true){
System.out.println("既に入力されています");
return;
}else{
y_coordinate.get(k).get(j).setBackground(player_c);
enter[order] = true;
}
}
}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.swing.Timer;
public class GameSystem implements ActionListener{
private Timer timer;
private int sec;
private Combinations<Integer> c ;
private GameScreen gs ;
private Screen sc;
private ArrayList<Integer> number_a = new ArrayList<Integer>(); //player1の入力
private ArrayList<Integer> number_b = new ArrayList<Integer>(); //player2の入力
private boolean finish = false;
public GameSystem(int limit){
sec = 0;
timer = new Timer(limit*1000,this);
timer.start();
}
public void createCombinations(){
if(GameScreen.play_turn == !true){
if(number_a.size() > 3){
c = new Combinations<Integer>(number_a,4);
//con = c.count(number_a.size(),4);
judgeWinner();
}else{
return;
}
}else{
if(number_b.size() > 3){
c = new Combinations<Integer>(number_b,4);
//con = c.count(number_b.size(),4);
judgeWinner();
}else{
return;
}
}
}
/* 勝者判定 */
public void judgeWinner(){
Iterator<List<Integer>> i = c.iterator();
while(i.hasNext()){
List<Integer> t = i.next();
Collections.sort(t); //小さい順に並び替え
Collections.reverse(t); //大きい順へ
if(t.get(0)-t.get(3)==3 && t.get(0)-t.get(1)==1 ||
t.get(0)-t.get(1)==20 && t.get(1)-t.get(2)==20 && t.get(2)-t.get(3)==20 ||
t.get(0)-t.get(1)==21 && t.get(1)-t.get(2)==21 && t.get(2)-t.get(3)==21 ||
t.get(0)-t.get(1)==19 && t.get(1)-t.get(2)==19 && t.get(2)-t.get(3)==19 ){
finish = true;
System.out.println("ゲーム終了");
}
}
}
public void addA(int n){
number_a.add(n);
}
public void addB(int n){
number_b.add(n);
}
@Override
public void actionPerformed(ActionEvent e) {
if(finish == true){
timer.stop();
}
if (sec == 15){
sec = 0;
gs.changeTurn();
}else{
gs.setTelllimittext(sec);
sec++;
}
}
}
/*http://kuidaored.hatenablog.com/entry/20101120/1290268944様より引用
*組み合わせをすべて列挙するプログラム
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class Combinations<T> implements Iterator{
private List<List<T>> combinations;
private List<T> list;
private int[] index;
private boolean[] visited;
private int r;
private boolean overHalf;
private Iterator<List<T>> iterator;
public Combinations(List<T> l,int r){
if(l.size() < 1 || r < 1 || l.size() < r){
throw new IllegalArgumentException();
}
this.combinations = new ArrayList<List<T>>();
this.list = l;
this.r = r;
if(this.r == l.size()){
this.combinations.add(list);
}
else{
if(this.r > list.size() / 2){
this.r = list.size() - this.r;
this.overHalf = true;
}
this.index = new int[this.r];
this.visited = new boolean[list.size()];
this.compute(0);
}
this.iterator = this.combinations.iterator();
}
public Combinations(T[] array, int r){
this(Arrays.asList(array),r);
}
private void compute(int n){
if(n == this.r){
List<T> combination = new ArrayList<T>();
if(overHalf){
for(int i = 0;i < this.list.size();i++){
boolean skip = false;
for(int j = 0;j < this.index.length;j++){
if(i == this.index[j]){
skip = true;
}
}
if(skip){
continue;
}
combination.add(list.get(i));
}
}
else{
for(int i = 0;i < this.index.length;i++){
combination.add(list.get(index[i]));
}
}
this.combinations.add(combination);
}
else{
for(int i = 0;i < this.list.size();i++){
if(n == 0 || !this.visited[i] && index[n - 1] < i){
this.visited[i] = true;
this.index[n] = i;
this.compute(n + 1);
this.visited[i] = false;
}
}
}
}
public List<List<T>> getCombinations(){
return this.combinations;
}
public static int count(int n, int r) throws IllegalArgumentException{
if(n < 1 || r < 1 || n < r){
throw new IllegalArgumentException();
}
int res = 1;
for(int i = n;i > r;i--){
res *= i;
}
for(int i = n - r;i > 1;i--){
res /= i;
}
return res;
}
public List<T> next(){
return this.iterator.next();
}
public boolean hasNext(){
return this.iterator.hasNext();
}
public Iterator<List<T>> iterator(){
return this.iterator;
}
public void remove(){
}
}
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
正しくコンポーネントが追加されていないようで真っ白になってしまします。
細かくはチェックできてないですが、大まかな印象では原因は「swingで画面をレイアウトするための標準的な方法を採っていないから」であるように思えます。
まず最初にごく単純なswingの画面サンプルをご覧ください。
import javax.swing.*;
import java.awt.*;
public class MyFrame extends JFrame {
public static void main(String[] args) {
new MyFrame().setVisible(true);
}
MyFrame() {
super("title");
JPanel content = (JPanel)getContentPane();
JButton top = new JButton("上");
JButton center = new JButton("中央");
center.setPreferredSize(new Dimension(200, 50)); // (1)
JButton bottom = new JButton("下");
content.add(top, BorderLayout.NORTH); // (2)
content.add(center, BorderLayout.CENTER);
content.add(bottom, BorderLayout.SOUTH);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack(); // (1)
}
}
申し訳ないですが質問のコードとはクラス構成が異なっており、メインクラスはJFrameの派生でありメイン画面の定義処理はmainメソッドではなくMyFrameクラスのコンストラクターでやっている点が若干比較しずらいですが、自分がポイントであると思う処理の違いは(1),(2)ですのでとりあえずはそこに注目してください。
(1) コンポーネントのレイアウト(位置と大きさ)
特にswing前提でのゲームのコードで、普通のレイアウト機構を用いずに標準的とはいえない方法で(つまり自前で各々のコンポーネントのレイアウトを明示する方針で)書いたコードをよく見かける気がします。ご質問のコードもその傾向にあると思います。少なくとも自分にはそのようなコードを見たとき、正しくレイアウトできているかどうか分かりづらく感じます。普通のレイアウト機構とは「レイアウト制約を宣言的に指定し、実際のリサイズや配置はレイアウトマネージャーに任せる」「初期レイアウトはJFrame#packにより行う」といった点を指します。
そんなわけで、「平易なレイアウト方式に改める」のが一番よい対処という気がしますが、それはそれでなかなか大事かも知れません。そこで・・・
とりあえず何もコンテントが出ないという状況はJFrame#setVisible
の直前でJFrame#pack
を呼び出せば解消できます。コンテントが表示されるようになるので、後は個々のコンポーネントのレイアウトの乱れを修正していくことで期待するレイアウトにもっていけそうです。(実際にいくつか乱れがあるようですが、自分はそれらの原因を指摘できるほどには詳細にコードをみていません。)
(2) メイン画面へのコンポーネントの追加
こちらは現象と直接的な因果関係はありませんが気になるのでコメントします。
JFrameのウインドウ枠の内側の領域は大まかに言えばconetentPaneに設定されたコンポーネントになります。ここにはデフォルトでJPanel(そのレイアウトマネージャーはBorderLayout)が設定されている点を知っておいた方がよいと思います。BorderLayoutを用いたJPanelへ子供を追加するには普通
Container#add(Component comp, Object constraints)
を用います。constraintsには上記サンプルの(1)のようにBorderLayout.CENTERなどの位置を指定します。ご質問のコードでは
Container#add(Component comp)
を用いています。こうすると実際にはconstraintsとしてBorderLayout.CENTERが仮定されるので追加自体は行えるのですがあまり行儀がよいコードとは言えない気がします。
(1),(2)共通に言えることなのですが、swingに限らず、GUIプログラミング(特にレイアウト)はそもそもの機構が複雑なので、なるべく平易な方法(作法)を知りそれに沿ったコードを書くことが大事な気がします。そうでないとコードを見ても「うまく動くかどうか」がすぐにはわかりづらく(※)、悪くすると動かしてみても原因がつかめないといったことになりがちと思います。何が平易な作法なのかというのは一言で言うのは難しいですが、とりあえず本件でいえば「レイアウトマネージャーにレイアウトをまかせること」というのが自分の意見です。
※: ちなみに今回のコードを調べるまでは自分は「JFrame#add(Component)を用いたときBorderLayoutがCENTERを仮定する」という事実を知りませんでした。ひょっとしたらこれは常識であって自分が知らなかっただけかも知れませんが・・・
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.20%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
2017/09/26 22:45
複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。
masaya_ohashi
2017/09/27 09:52
「うまく起動してくれません」と言われても、我々にはコードを1から10まで眺める時間はありません。「ビルドがエラーを起こしている」「そもそもウィンドウが出ない」「ウィンドウは出るが、なにも見えない」「ゲームが始まらない」など、なにがどう起動しないのか具体的な情報が必要です。また、エラー情報が分かればそれも記載してください。
masaya_ohashi
2017/09/27 10:09
少なくともCombinationsというクラス、Screenというクラスの情報も必要です。もしそんなクラスが無いというなら、起動しないのはまずそれが原因です。
tarutarupop
2017/09/28 00:14
コード以前に質問が稚拙に過ぎたため大幅に変えました。指摘ありがとうございました。加えてScreenクラスは今は関係ありませんでしたので削除し、combinationsクラスのソースコードを追加しておきました