0

SwingWorker でシミュレーションを実行するアプリケーションを作成しています。このシミュレーションでは、一部のセットは SwingWorker の doInBackground() メソッドで変更されたデータを保持します。このデータは GUI で表示する必要がありますが、SwingWorker が同じセットを変更しているため、GUI がセットへのアクセスを開始するとすぐに同時変更例外がスローされるため、これは明らかに失敗します。

SwingWorker が GUI がデータの描画を完了するのを待たずに、このデータを共有するにはどうすればよいでしょうか? データをコピーしてから publish() する必要がありますか? これでかなりデータ量が増えませんか(データ量が多い)?この問題を回避する他の方法はありますか?

簡単なコードを次に示します。

public class World {
    public Set<Foo> fooSet = new HashSet<Foo>();
}

public class Simulator extends SwingWorker<Void, Void> {
    private World       world;
    private WorldPanel  worldPanel;

    public Simulator(World world, WorldPanel worldPanel) {
        this.world = world;
        this.worldPanel = worldPanel;
    }

    @Override
    protected Void doInBackground() throws Exception {
        while (true) {
            doSomethingWithFooSet() //structurally modifies the set
            publish();
        }
    }

    @Override
    protected void process(List<Void> voidList) {
        worldPanel.repaint();
    }
}

public class WorldPanel extends JPanel {
    private final World             world;

    public WorldPanel(World world) {
        this.world = world;
    }

    @Override
    public void paintComponent(Graphics g) {
        drawWorld() //reads from fooSet in world
    }
}

誤解しないでください。なぜこれがうまくいかないのか理解しています。やりたいことを実行できるようにするには、この設計で何を変更する必要があるのか​​ 疑問に思っているだけです。つまり、シミュレーションが変更しているのと同じデータにアクセスします。process() は EDT で実行されますか? もしそうなら、WorldPanel がデータを描画するために使用するワールド オブジェクトのコピーで process() がセットを更新できるようにすることは可能でしょうか?

4

2 に答える 2

2

ワールド オブジェクトの更新と表示を同時に行うことはできないため、2 つの方法があります。更新と表示を順番に行うか、データのクローンを作成して、更新されたデータと表示されるデータが異なるようにすることです。最初のバリアントを実装するには、SwingWorker を使用しないでください。2 番目のバリアントでは、ワールド全体を単純に複製することが受け入れられない場合、バックグラウンド スレッドにワールドの新しい状態だけでなく、ワールドのイメージを変更するコマンドも計算させます。Publishコマンドを実行しprocessてから、画像を更新します。

于 2012-10-21T12:16:53.847 に答える
0

データを表示/アクセスするかどうかにかかわらず、GUIにフラグを追加します

最初は false に設定し、ワーカーが終了したら、切り替えられたフラグでアクセス部分をリロードします

于 2012-10-21T09:33:25.720 に答える