4

だから私は学校のプロジェクトとしてボイド シミュレーション プログラムを書いています。私のプログラムは、他のグループと群がらないこれらのボイドの複数の異なるグループをサポートしています。それらはすべて、新しい部族が作成されたときにプログラムのメイン GUI に BoxPanel を追加することによって行う異なる設定を持ち、それらの BoxPanel には設定があります。グループ設定で新しいフレームを開くボタン。

これは、プログラムを起動して、コード内に事前定義された部族をすべて追加すると、完全に機能します。ここで、GUI の新しい部分を作成して、これらの Boid の新しいグループを作成し、シミュレーションの実行中にそれらを追加できるようにしました。ここで問題が発生します。

何らかの奇妙な理由で、適切な設定でシミュレーションにグループを正常に追加しますが、BoxPanels をメイン GUI に追加しません。シミュレーションの横にある設定バー全体が完全に消えます。私はこれをテストし、計算スレッドの先頭に部族を追加すると同じことを行うので、これは複数のスレッドとスイングの問題のようです。これを引き起こしているもの、またはこれを修正する方法はありますか? 私はこれに完全に困惑しています。

tl;dr: トライブを追加するための以下のコードは、スレッドを開始していないときは正常に機能しますが、スレッドの開始後に使用しようとすると、optionPanel が空に見えます。

メイン GUI に BoxPanels を追加するコードは次のとおりです。

      def addTribe(tribe: Tribe) = {
        tribeFrames += new TribeSettingFrame(tribe)
        tribeBoxPanels += new TribeBoxPanel(tribe)
        this.refcontents
      }

      private def refcontents = {
        top.optionPanel.contents.clear()
        top.optionPanel.contents += new BoxPanel(Orientation.Vertical) {
          tribeBoxPanels.foreach(contents += _.tribeBoxPanel)
        }
        top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
          contents += top.addTribeButton
        }
        top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
          contents += top.vectorDebugButton
        }
      }


  new Thread(BoidSimulation).start()

ああ、内容のサイズを印刷して本当に必要な内容を追加するかどうかをテストしましたが、すべてがうまく一致しますが、描画されません。

編集:いくつか掘り下げた後、実際にはスレッドからスイングを更新することのようです。多くの場所で SwingWorker の使用が提案されていますが、私が収集した情報から、それは継続的なシミュレーションであり、フレームごとに新しい SwingWorker を作成し続ける必要があるため、私のプログラムには適合しないと思います。

EDIT2:次のようにスレッドからメソッドを呼び出してみました:

SwingUtilities.invokeLater(new Runnable() {
  override def run() {
    GUI2D.addTribe(tribe)
  }
});

違いはありませんでした。これは、TribeBoxPanel と TribeSettingFrame の使い方に問題があると思い始めています。これらは、必要な BoxPanel または Frame を返すメソッドを 1 つだけ含むオブジェクトです。この実装は悪いですか?もしそうなら、動的な BoxPanels と Frames を作成するより良い方法は何ですか?

4

2 に答える 2

0

Swing はスレッドセーフではありません。

私の後に繰り返して。

Swing はスレッドセーフではありません。

合唱が聞こえますか?Swing はスレッドセーフではありません公式ドキュメントがあります。

非常に簡単な回避策もあります。

SwingUtilities.invokeLater(new Runnable() {
    @Override public void run() {
        // your stuff
    }
});

Scala では、これは次のようにサポートされています。

Swing.invokeLater(/* your stuff */)
于 2015-03-06T12:32:29.023 に答える
0

最初に、UI スレッドにすべての UI 操作を処理させる必要があります。簡単な方法は、Scala-Code に従う必要があります。

Swing.onEDT { GUI2D.addTribe(tribe) }

しかし、すでに指摘したように、これでは問題は解決しません。Swing.Labelaのテキストコンテンツのみを変更しただけで、単に消えてしまうという非常によく似た問題がありました。

テキストが長すぎて、ラベルが最初に予約したエリア内に表示できない場合にのみ消えたことが判明しました。したがって、問題を回避する1つの方法は、作成時にoptionPanelの初期サイズを大きくすることです。

Swing.onEDT { top.optionPanel.preferredSize = new Dimension(width,height) }

コンポーネントが最初に描画される前 (Frame.open() が呼び出される前) にこれを設定する必要があるかどうかはよくわかりません。

于 2015-04-03T18:05:19.763 に答える