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

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

0

SwingWorkerの使い方がよくわかりません。

アラスカソリティアというトランプゲームを作っていて、画面(トランプ以外)クリックで列から場に移動できるトランプを自動で移動できるようにしています。

Javaの道>掲示板(間隔をあけて移動するようにしたい。)
http://www.javaroad.jp/bbs/answer.jsp?q_id=2014060510411131

そこで2年前くらいにネットで見た情報を利用して作った2つの楽譜があるようなピアノを作った時に作ったスレッドをもとに自分なりにコードを作っていました。
でも、SwingはEDTを理解しなくてはいけないことと、SwingUtilities#invokeLaterを使った形に直すように言われたので、SwingUtilities#invokeLaterについて調べてみました。

そして、以下のページでSwingWorkerについて知り、

SwingUtilities#invokeLaterとはなんじゃらほいさっさ - q-yoshidaの日記
http://d.hatena.ne.jp/q-yoshida/20100923/1285246172

以下のページでSwingWorkerの使い方を知りました。


Java技術最前線 - 「Java SE 6完全攻略」第27回 Swingでマルチスレッド - SwingWorker その1:ITpro
http://itpro.nikkeibp.co.jp/article/COLUMN/20070413/268205/?ST=develop

Java技術最前線 - 「Java SE 6完全攻略」第28回 Swingでマルチスレッド - SwingWorker その2:ITpro
http://itpro.nikkeibp.co.jp/article/COLUMN/20070420/269053/?ST=develop

SwingWorkerクラスを親クラスに持つクラスのdoInBackgroundメソッドで非同期の動作を書いて、doneメソッドで非同期の動作が終わった後にさせる動作を書いて、processメソッドでdoInBackgroundメソッドからデータを受け取って動きの様子を画面に反映させることができると言うのはわかりました。

ですが、私のコードのどこをどのメソッドでやらせればいいかがよくわかりません。
doInBackgroundメソッドでトランプが移動できるかどうかを調べて移動できるトランプとその移動先をエンクロージング型クラスのグローバル変数に記憶させ、doneでそれをもとにsleepを交えつつ移動させていく感じにすればいいのでしょうか?
それとも、SwingWokerではなくSwingUtilitiesのinvokeLaterを使う方がいいでしょうか?

あと、gameClearメソッドでのクリア判定で4つの場に重なっているトランプの枚数がどの場も13枚ならJLabelでクリアーと表示させるようにしているのですが、クリアと判定されてからクリアーと表示されるまでに10秒程度時間がかかってしまいます。
一番最初に参考したページをもとに以下のようにsetVisibleをSwingUtilitiesのinvokeLaterで囲ってみても時間がかかります。
どうするのがよいのでしょうか?

boolean gameClear(){
    System.out.print("gameClear?");
    for(int x=0;x<4;x++){
        System.out.print("  "+x+"  ");
        if(area[x].card.size()<13){
            System.out.println("gameNotClear");
            return false;
        }
    }
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            clear.setVisible(true);
        }
    });
    System.out.println("gameClear");
        return true;
    }
}

29

回答

85122

閲覧

29件の回答

評価

0

http://stackoverflow.com/questions/2829364/java-difference-
between-swingworker-and-swingutilities-invokelater

評価

0

遅いレスなので解決済みかもしれませんが

>>クリアと判定されてからクリアーと表示されるまでに10秒程度時間がかかってしまいます。

最初にこれを何とかした方がいいと思います。
Javaの道>掲示板(間隔をあけて移動するようにしたい。)
http://www.javaroad.jp/bbs/answer.jsp?q_id=2014060510411131
のCardMoveスレッドを使っている場合Cardがクリックされる度に
CardMoveスレッドが生成されると思いますが、
それらがループから抜け出せずに終了していない可能性はないでしょうか?
runメソッドの最初に
String thread = Thread.currentThread().getName();
System.out.println(thread + ":start");
を入れ、returnの前や、whileループからのbreakの前に
System.out.println(thread + ":end");
を入れてみるとどうなるでしょうか?
もし複数のCardMoveスレッドが走っている場合はrunメソッドのループの終了条件が
何か抜け落ちていないか考えてみてください。
あとCPU使用率が異常に高くなってはいないでしょうか?

評価

0

複数のスレッドが走っているかどうかを確認しやすくするためにも、画面クリックをするのを最後の1回だけにしてみました。
1クリックで複数のスレッドが走ることはありませんでした。

CPU使用率についてですが、家で充電しながらやってた時は初めは10%程度でクリアーと出る直前に34%になりました。
今回はKがすべて場に重なってからクリアーと出るまでにそんな時間はかかりませんでした。
1・2秒くらいだったように思います。
また電車で移動中にやった時は、10〜20%あたりからクリアーと出る前は38%が続いていました。
その時はKがすべて場に重なってからクリアーと出るまで3・4秒程度だったように思います。
もう一度今度は個別の使用率を調べるためにやってみると、javaw.exeの使用率がプレイ中は基本使っていても数%くらいでしたが、クリアーと出る前に28%になったのを確認しました。
この時の出るまでの秒数は意識していなかったためあまり分からないのですが、そんな時間かからなかったように思います。

数秒を超えて10秒ほどかかった時は今よりもしばらくシャットダウンとかさせてなかったりいろいろ起動していたように思うのでそれも原因だと思いますが、やはり私のコードの書き方がどこかよくなかったのでしょうか?

評価

0

>CardMoveスレッドを使っている場合Cardがクリックされる度にCardMoveスレッドが生成されると思いますが、

むしろCard(トランプ)以外がクリックされたときに生成するようにしているつもりですし、実際に画面上のトランプ以外をクリックしたときにスレッドに書いたprintlnの出力がされるようにもなっています。
スレッド実行中でのクリックの対処(実行が終わるまで新たにスレッドを作られないようになど)は特にしていませんが、自分でプレイしていて自動移動中にどこかをクリックしたりはしていませんし、先ほどの検証ではこれでクリアーできるという時に1度だけクリックしただけです。
なので、同時実行による障害は発生しないと思っていますし、実際に検証中はThread-2以外のスレッド名の出力はありませんでした。

評価

0

public void mouseClicked(MouseEvent event){
    if(!(event.getSource() instanceof Card)){
        new CardMove().start();
    }
}
確かにCard以外ですね、!を見落としていました。
すみませんでした。

CPU使用率は問題なさそうですね。
CardMoveスレッドのwhileでsleepをはさまない無限ループにはまってCPUを占有し、それによってEDTでの処理が遅くなっている可能性があると思ったのですが、そうではないようですね。

>その時はKがすべて場に重なってからクリアーと出るまで3・4秒程度だったように思います。

最後のKが場に重なる処理もCardMove#runの中で行われているのでしょうか?
またgameClearメソッドが呼び出されて、コンソールに"gameClear"と表示されるのは、Kがすべて場に重なってすぐでしょうか?
それともクリアーと出るのと同じくらいでしょうか?

それと普通にゲームを進めている時にはCardMoveスレッドは複数起動されているのでしょうか?

評価

0

カードの自動移動はすでに書いたとおりCardMoveのrunメソッドで行っています。
列の先頭と場の一番上のトランプを比較し、マーク・数字とも場に重ねられる条件を満たしている時に列の先頭のトランプの座標を重ねられる場の座標に変更しています。
これを移動できるトランプがなくなるまで繰り返しています。
この時、座標が変わってからと裏になっていてめくってもよいトランプをめくってから(CardクラスのcardTurnメソッドが終わってから)のところにsleepを入れています。
初めのwhile(true)の部分で無限ループのようになっていますが、次のfor文に入る前に変化の数(数じゃなくてあったかどうかでよかったですね)を記憶する変数を作り、そのforが終わった時に変化がなかったら(数が0だったら)breakして無限ループから抜けるようにしています。
変化がなくなるまでなので、トランプの並びによっては最後のKが場に重なるまでwhileの中が実行されることになります。

クリアーしているかどうかの確認は、場にトランプが移動してからgameClearメソッドを呼び出して調べています。
そのメソッドは初めに書いたように4つの場に重なっているトランプの枚数を調べることによってクリアーかどうかを判断するようにしています。
そして、クリアーならtrue、そうでないならfalseを返すようにしています。
なぜ戻り値を作ったかというと、そこでクリアーの場合はそれ以降の動作をする必要がなく(というかするだけ無駄だと思って)、そのメソッドからtrueが帰ってきたらそれ以降の処理を中止する(returnする)ようにしようと思ったからです。

画面上で4つの場に4つのKがそろってからすぐコンソールにgameClearと出ているように思いますが、そこから画面上にクリアーというJLabelが表示されるまでに数秒や10秒程度かかっています。
setVisibleをSwingUtilitiesのinvokeLaterで囲う前から時間がかかっていました。

評価

0

gameClearメソッドがtrueを返すとCardMoveのrunメソッド
がreturnされスレッドが終了するのは理解しました。
その場合はただちに処理はEVT(イベントディスパッチスレッド)に移ってコンポーネントの描画処理(クリアーというJLabelの表示)が行われるはずですが、そうならないのは、やはり他のCardMoveスレッドがいくつか終了せずに走っていて、それらに処理が移るのが表示が遅れる原因のような気がします。

もし複数のCardMoveスレッドが同時に起動されている状態が発生しているのであれば、常に一つだけが起動されるように修正する必要があると思います。
moveの値が1以上になった状態で、それ以上のカード移動がないのにも関わらず、whileループから抜け出せていない可能性はないでしょうか?
もしそうであれば、それ以上のカード移動がないという状態になったらCardMoveのrunメソッドを終了するように修正すればうまくいきそうな気がします。

ソリティアをやったことがないので見当違いの回答だったらすみません。

評価

0

本当にスレッドが終わっているかを調べるためにCardMoveのrunメソッドのwhile部分を以下のように書き換えてみました。

while(true){
    boolean move=false; //移動があったときにtrueを代入
    //トランプが移動出来るかどうかを調べるfor文省略
    if(move==false){ //falseのまま—つまり移動されていなかったら
        System.out.println(thread + ":while return");
        return; //終了
    }
    System.out.println(thread + ":in while");
}

クリアーしやすいようにシャッフルしないでもらって1クリックで自動移動だけでクリアーできるようにしてみました。
コンソールでreturnが表示されてから画面にクリアーと出るまでに3・4秒かかりました。
その時のログがこれです。

Thread-2:start
gameClear?  0  gameNotClear
Thread-2:for2 break
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0  gameNotClear
Thread-2:for2 break
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameNotClear
Thread-2:for2 break
Thread-2:in while
gameClear?  0    1    2    3  gameClear
Thread-2:return

出力されているスレッド名はThread-2だけで、returnの後にin whileが出力されることもなく、1つのスレッドが実行されていてreturnできちんと終わっていることを確認しました。
なので、動かせるトランプがないのにスレッドが動き続けているとかいうのもないです。

シャッフルしてもらってまだクリアーにならないタイミングで1クリックして試してみましたが、それでも移動できるトランプがなくなればwhile returnが出力されてそのあとはクリックしたり自分で場にトランプを重ねたりしない限りなにも出力されませんでした。

クリアー認定されてクリアーを表示するように頼んだ後は自動移動処理中でも手動移動処理中でもその移動処理を中止するようにしているはずなのですが・・・

評価

0

>クリアーしやすいようにシャッフルしないでもらって1クリックで自動移動だけでクリアーできるようにしてみました。

確かにこの条件でスレッドが正しく終了していますね。
またその際に画面にクリアーと出るまでに3・4秒かかってしまうということも分かりました。

>シャッフルしてもらってまだクリアーにならないタイミングで1クリックして試してみましたが、それでも移動できるトランプがなくなればwhile returnが出力されてそのあとはクリックしたり自分で場にトランプを重ねたりしない限りなにも出力されませんでした。

こちらの方もそれ以上のカード移動がなければスレッドが終了するのが分かりました。
つまり私が想像していたwhileループを抜け出せないCardMoveスレッドがあるのが原因というのは間違いでした。
余計なテストをさせてしまい、すみませんでした。

こりずにお願いしますが、CardMove#runメソッドを以下のようにした場合はクリアーの表示はどうなるでしょうか?
public void run(){
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            clear.setVisible(true);
        }
    });
    System.out.println("gameClear");
}


評価

0

invokeLaterの前に、画面の描画は基本的に後回しにされる
場合が多い。この場合も何らかの原因で描画へ行き着かない
ということじゃないかね。
invokeLaterを使うことで、遅くなることはあっても速くなる
ことはあんましない。

全体が出てないので、何がまずいかは全く見えないな。


最後のコードについて。sleep入れた方がいいよ。

評価

0

JLabelをvisibleにするのにinvokeLaterって要らないんじゃ?

評価

0

invokeLaterは、作業があるなら全部終わってから、
割り込み作業が入ったらそれも先に終わらせてってもので、
決して即座に実行してってものじゃないよ。

評価

0

>invokeLaterの前に、画面の描画は基本的に後回しにされる
場合が多い。この場合も何らかの原因で描画へ行き着かない
ということじゃないかね。

そうですねEVT上の最後のrepaintの前に何か時間がかかる処理を行っているようですね。

>全体が出てないので、何がまずいかは全く見えないな。

そこがおもしろいんじゃないですか ^^

>最後のコードについて。sleep入れた方がいいよ。

そうですね一回ぐらい入れて置けば良かったかもしれません。

>JLabelをvisibleにするのにinvokeLaterって要らないんじゃ?
確かrepaintとrevaridateとリスナーの登録や解除以外はEVTでやる必要があると記憶していたのですが...

>invokeLaterは、作業があるなら全部終わってから、
割り込み作業が入ったらそれも先に終わらせてってもので、
決して即座に実行してってものじゃないよ。

確かに他のスレッドに処理が割り振られる可能性があるので、即座に実行されないかもしれません。
もしすぐにEDTの処理が開始された場合はEventQueueに他のrunnableが溜まっていなければすぐに実行されるはずです。

評価

0

>そこがおもしろいんじゃないですか ^^
何言ってるんだお前は。

自分が楽しかったら他の人間にとっても楽しいと思ってる
のか…?
つうか、人に助力を請う立場の台詞じゃない。

評価

0

class CardMove extends Thread{
    @Override
    public void run(){
        /*以下追記して元のはコメントアウト*/
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                clear.setVisible(true);
            }
        });
        System.out.println("gameClear");
    }
}

となるように書き換えてみました。
すると、たぶん5分以上は待ったのですが、画面にクリアーと表示されませんでした。

invokeLaterがEDTに処理を頼むためのもの的なことはこの間知りましたが、それを知ったサイトにsetVisbleをinvokeLaterで囲ったりするサンプルもあるとか見たりしたので、囲った方がいいのかなと思いまして。

CardMoveのrunメソッドを元に戻してgameClearメソッドのinvokeLaterあたりをコメントアウトしてシャッフルさせない状況で試してみたところ、その場合は最後のKが場に重なる前に3・4秒ほど時間がかかり、そのあと最後のKが場に重なるのと画面にクリアーと出るのが同時に行われているように見えます。
囲うことによってクリアーと出すよりも最後のKを移動することを優先させているということですよね。
どちらも現状クリアーと出るまでにいくらか時間がかかることは同じなので、それなら囲って一応画面上ですべてのKが場に重なっている状況でクリアーの表示を待つ方がいいと思うので、やはりここは囲ったままにしておこうかと思います。

>最後のコードについて。sleep入れた方がいいよ。

最後のコードってどのコードのことでしょうか?
whileのとこですかね?
そこならwhileの最後に行くまでにトランプの移動やめくる動作の後にはsleepが入るようになっていますが、トランプの移動などがなくてもsleepが入るようにした方がいいということですかね?

評価

0

匿名(2014-06-10 22:12:04)さんが勘違いしているようなので一言。
匿名(2014-06-10 21:41:38)さんの回答は私(質問者です)が書いたものではありません。

口調等からの私の勝手なる推測ですが、私はその人はこの質問に対していろいろと原因を探ってくれている(2014-06-09 01:40:14)や(2014-06-09 21:25:36)の書き込みの人だと思っています。
もし違ったらすいません。

評価

0

現状を整理するためにも、以下に自動移動とクリアー判定にかかわる部分のコードと説明的なものを載せます。

CardクラスというのがJLabelを親クラスとした自作クラスになっていて、トランプの数字記憶用変数numとマーク記憶用変数markとトランプをめくるcardTurnメソッドなどがあります。
列や場にあるトランプの並びを記憶させたりするためのAreaクラスがあり、ベースの枠を表示させるためにもJLabelを親クラスとして作っていて、その上に重なっているトランプの並びを記憶するためのVector<Card>のcard変数などがあります。
line配列やarea配列はそのクラスのもので、line配列で各列・area配列で各場にあるトランプを管理しています。

gameClearメソッドでのクリア判定で4つの場に重なっているトランプの枚数がどの場も13枚ならJLabelでクリアーと表示させるようにしているのですが、クリアと判定されてからクリアーと表示されるまでに現状1〜4秒程度時間がかかってしまいます。
一番最初に参考したページをもとに以下のようにsetVisibleをSwingUtilitiesのinvokeLaterで囲ってみても時間がかかります。

setVisibleをSwingUtilitiesのinvokeLaterで囲わないと最後のKが移動する前に画面の動きが止まり、囲うと最後のKが移動してから画面の動きが止まります。

以下コードです。

public void mouseClicked(MouseEvent event){
    if(!(event.getSource() instanceof Card)){
        new CardMove().start();
    }
}

class CardMove extends Thread{
    @Override
    public void run(){
        String thread = Thread.currentThread().getName();
        System.out.println(thread + ":start");
        try {
            while(true){
                boolean move=false;;
                for(int x=0;x<7;x++){
                    if(line[x].card.size()>0){
                        for(int x2=0;x2<4;x2++){
                            if(area[x2].card.size()==0){
                                if(line[x].card.get(0).num==0){
                                    getContentPane().setComponentZOrder(line[x].card.get(0), 0);
                                    line[x].card.get(0).setLocation(area[x2].getLocation());
                                    area[x2].card.add(line[x].card.get(0));
                                    line[x].card.remove(0);
                                    move|=true;
                                    if(gameClear()==true){
                                        System.out.println(thread + ":return");
                                        return;
                                    }
                                    Thread.sleep(100);
                                    System.out.println(thread + ":for2 break");
                                    break;
                                }
                            }
                            else{
                                if((line[x].card.get(0).mark==area[x2].card.get(area[x2].card.size()-1).mark) &&
                                        (line[x].card.get(0).num==area[x2].card.get(area[x2].card.size()-1).num+1)){
                                    getContentPane().setComponentZOrder(line[x].card.get(0), 0);
                                    line[x].card.get(0).setLocation(area[x2].getLocation());
                                    area[x2].card.add(line[x].card.get(0));
                                    line[x].card.remove(0);
                                    move|=true;
                                    if(gameClear()==true){
                                        System.out.println(thread + ":return");
                                        return;
                                    }
                                    Thread.sleep(100);
                                    System.out.println(thread + ":for2 break");
                                    break;
                                }
                            }
                        }
                        if(line[x].card.size()>0 && line[x].card.get(0).turn==0){
                            line[x].card.get(0).cardTurn();
                            Thread.sleep(100);
                        }
                    }
                }
                if(move==false){
                    System.out.println(thread + ":while return");
                    return;
                }
                System.out.println(thread + ":in while");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

boolean gameClear(){
    System.out.print("gameClear?");
    for(int x=0;x<4;x++){
        System.out.print("  "+x+"  ");
        if(area[x].card.size()<13){
            System.out.println("gameNotClear");
            return false;
        }
    }
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            clear.setVisible(true);
        }
    });
    System.out.println("gameClear");
    return true;
}

評価

0

2014-06-10 21:41:38
の書き込みは質問されている方ではありません。
誤解されるような書き方をして申し訳ありませんでした。
またイベントディスパッチスレッドをしつこくEVTと書いてしまいましたがEDTの間違いでした。(なぜか最後だけEDTになってますが)

質問者の方へ
面白いと感じているのは事実ですが、質問者の方は1秒でも速く解決したいと思っているでしょうから、不謹慎でした、すみません。
問題が解決するまで付き合わせてください。

現状2つの問題があると思います。
1つはスレッドセーフではないSwingコンポーネントのメソッドへのアクセスをSwingUtilities#invokeLaterあるいはSwingWorkerを使う形に修正する。
2つ目は、クリアーと判定されてからクリアーと表示されるまでに時間がかかってしまう。

1つ目の方は結構大変です。
条件分岐の中でJLabelであるCardオブジェクトにアクセスしているので部分的に切り出してSwingUtilities#invokeLaterを使うことが難しくなっています。
またif文ごとEDTに持って行くとEDTがsleepしてしまい、新しいスレッドを作った意味がなくなってしまいます。
さらに、ややこしさが増すので後にしようと思っていましたが、新しいスレッドを作る以上、Javaのメモリモデルが絡んできて、他のスレッドからは正しい値が見えていないとか、面倒な事を考慮する必要も出てきます。
(あまりにややこしい事をいっぺんに学習しろというと質問者さんが嫌気をさすと思ったので、なるべく順番に解決できるようにしたいと思ったのですが、現状うまくいっていません。)

という事で2つ目の問題の方から解決した方がいいのではないかと思います。
こちらの問題の直接の原因はCardMoveクラスにはないようです。試しに
mouseClickedメソッドの
    if(!(event.getSource() instanceof Card)){
        new CardMove().start();
    }
の部分を
    if(!(event.getSource() instanceof Card)){
        clear.setVisible(true);
        System.out.println("gameClear");
    }
とした場合はすぐにクリアーラベルが表示されますか?

評価

0

>面白いと感じているのは事実ですが、質問者の方は1秒でも速く解決したいと思っているでしょうから、不謹慎でした、すみません。

私はそれでいいと思ってますよ。
無理やり付き合わせるわけにはいきませんから、面白いと思って興味持ってくれてるほうがうれしいです。
もちろんどうにかしたいとかいう気持ちはありますが、そのために他人の回答をせかしたりするつもりは一切ありません。
趣味で作っているだけですし。

>問題が解決するまで付き合わせてください。

はい。
よろしくお願いします。

私がEDTを全然わかってないもので・・・
もっといろいろ勉強しないとだめですね。

2番目の問題の話ですが、提案の通り書き換えてみてもそのsetVisibleをinvokeLaterで囲ってみてもその前に画面のsetVisibleをfalseにしてクリアーのsetVisibleをtrueにした後で画面のsetVisibleをtrueにしてみてもかれこれ30分くらいたちますがクリアーラベルは表示されません。
どれもコンソールに"gameClear"と出力されるだけです。

評価

0

やはり全体が分からんので想像だが、JLabelが表示されない
のはサイズ指定やaddが外れてしまったなんてことはないか?
setVisibleをinvokeLaterしなければ表示されるのか?

評価

0

途中で上げたコードでは今そーづに"gameClear"と出力されてから画面に"クリアー"というラベルが表示されるまでに今は2秒かからないくらいで表示されます。
テンポもそんな悪くないのでこれはこのままでいいような気もします。

>やはり全体が分からんので

パッケージが3つでファイルとクラスが5つあったりとかするのでとりあえずあそこら辺だけと思っていましたが、やはりeclipseのプロジェクトフォルダごと以下にアップロードします。

http://fast-uploader.com/file/6958020940123/

その中のフォルダ構成.txtにフォルダ構成とクラスの簡単な説明を書きました。
ソースファイルはあまりというか一部を除いてコメント文を書いていないものでわかりにくいかもしれませんが、よろしくお願いします。

評価

0

イベントディスパッチスレッドがwaitやスリープなどでブロックされているか、どこかで無限ループにはまっているようですね。

まどろっこしいと思われるでしょうがアップされたソースはDLしていませんので、またいくつか質問に答えてください。

応答のない状態の時のCPU使用率はどうなってますか?
mouseClickedメソッドはあれで全部でしょうか、何か後に書いてあるコードを省略していますか?

これはないと思いますが、イベント処理のコードでどこかでwaitまたThread.sleepを記述していますか?(CardMove以外で)

CardMoveスレッドを走らせた場合は時間がかかっても終了するということは、トランプがある状態になるまで終了しないwhileやforループがEDTでぐるぐる回っているような気がするのですが、該当するコードがないでしょうか?

それとcardTurn()メソッドはCardのnumとmarkをラベルに表示するだけですか?

評価

0

ソース見た。
ZOrderをいじるなら、同一のコンテナに載っけた全部を気
にしような。

評価

0

>ZOrderをいじるなら、同一のコンテナに載っけた全部を気にしような。

後に追加したものが手前に表示されるのは確認しました。
そして、ZOderいじれば表示順を任意に変更できることを知り、ドラッグやクリックによる手動・半自動移動では表示順を整えて移動したトランプの表示順を最前面のほうにしています。

クリアーラベルは一番最後に追加していて最前面にあると思いますが、手動・半自動・自動移動により結果的にすべてのトランプより背面になっているとは思っています。
でも、クリアーと出る部分の上には見た目には何も乗っていないのでそこは気にしていませんでした。
それが今回の問題と何か絡んでいるということでしょうか?

評価

0

ああ、「クリア」が必要になるのは下にカードが無くなっ
たときか…そりゃそうか。
最後まで流してみたら、ちゃんと「クリア」と出て来た。
問題ないみたいだな。

どこかにビルドエラーがあって、ビルドが途中で止まって
る(ソースの修正が反映されてない)ってことはないか?
Eclipseだと結構ありがちなんだが。

評価

0

途中PCのシャットダウンもしていますので、ソースが古いままとかいうのはないかと思います。

評価

0

ソースが古いんじゃなくて、classが古い。

評価

0

クリーンをしてから実行してみました。
すると、1回目は10秒近くかかりましたが、2回目以降は1秒くらいで出てくれました。
1から2秒くらいならいいのですが、それ以上とくに10秒とかかかると遅いと感じるので、できるだけそうはならないようにしたいと思っています。

ここに質問する前は何度やっても10秒くらいかかっていたように思います。
いろいろやっているうちにあまり10秒もかかることはなくなりましたが、遅いと感じることがないわけでもないので。

評価

0

で、invokeLater取ってみたの?

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