0

最初に私はこれをしました:

public SpaceCanvas(){
    new Thread(new Runnable () {//this is the thread that triggers updates, no kidding
        int fcount = 0;

        @Override
        public void run() {
                System.out.println("Update thread started!");
                while(!Thread.interrupted()){
                    fcount++;
                    while(players.iterator().hasNext()){
                        players.iterator().next().update(fcount);
                    }
                    while(entities.iterator().hasNext()){
                        entities.iterator().next().update(fcount);
                    }
                    System.out.println("About to paint");
                    repaint();
                    System.out.println("Done with paints");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
        }
    }).start();
    players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}

私が SpaceCanvas と呼ぶもののイニシャライザで。ただし、スレッドは実際には非同期で実行されないため、キャンバス、つまりその中にあるアプレットを作成することはできません。次に、「.start()」を「.run()」に置き換えたところ、スレッドは 1 回だけ実行されましたが、SpaceCanvas は完全に初期化されました。

私は何を間違えましたか、どうすれば修正できますか?

4

2 に答える 2

3

この種のコードが期待どおりに機能するかどうかはわかりません。

while(players.iterator().hasNext()){
    players.iterator().next().update(fcount);

players.iterator()コレクションの新しい反復子を取得しますplayers。コレクションにアイテムが 0 の場合はそうなりますfalseが、アイテムがある場合は無限ループになり、毎回新しい反復子が作成されます。iterator()内部での呼び出しは、players別の新しい反復子オブジェクトも生成します。

次のようなことをすべきだと思います:

Iterator iterator = players.iterator();
while (iterator.hasNext()) {
    iterator.next().update(fcount);
}

これはあなたのentitiesループでも同じです。より良いパターン (Java 5 以降) は、forループを使用することです。

for (Player player : players) {
    player.update(fcount);
}

また、複数のスレッドがこれらのコレクションにアクセスしている場合は、何らかの形でアクセスする必要がありますsynchronized。並行コレクションを使用するか、すべてのアクセス (読み取りと書き込み) がsynchronizedブロック内にあることを確認する必要があります。

synchronized (players) {
    for (Player player : players) {
        player.update(fcount);
    }
}
...
// down in the outer thread
synchronized (players) {
    players.add(new LocalPlayer(0, 9001, 0, 0, 0, 0, this, null));
}

明らかに、同じ方法であるentities必要があります。synchronized

于 2012-05-04T22:20:05.913 に答える
1
  1. このミレニアムでは、AWT ( ) ではなく Swing ( ) を使用してJApplet/JPanelくださいApplet/Canvas
  2. Swing を使用する場合は、500 ミリ秒ごとTimerに呼び出すSwing を確立します。repaint()
  3. (Swing/ 使用時) EDT (Event Dispatch Thread) でTimer呼び出さないでください。Thread.sleep(n)

..JPanel で描画できますか?

確実なこと。そのためには、paintComponent(Graphics)メソッドをオーバーライドします。a を拡張JComponentして同じことを行うこともできますが、a の処理にはいくつかの癖があり、拡張JComponentするJPanel方が適切です。

一方、まったく別のアプローチがあります。

  • BufferedImage必要なカスタム グラフィックに必要なサイズの を作成します。
  • に画像を追加しImageIconます。
  • アイコンを に追加しますJLabel
  • ラベルを GUI に追加します。
  • Timerアクションについて。
    • image.getGraphics()描画面を取得するために呼び出します。
    • paint()またはで行った可能性のあることを再現するpaintComponent()
      1. (必要に応じて) 以前の描画をすべて消去します。
      2. 現在のカスタム レンダリングを描画します。
    • dispose()画像のGraphicsインスタンスの。
    • 電話label.repaint()
于 2012-05-04T22:35:58.500 に答える