2017-01-04 6 views
0

テーブルビュー全体でスクロールを同期しようとしています。 (両方&タテ)TornadoFX JavaFX Syncテーブルビュー全体でスクロール

enter image description here

SyncScrollExビューは基本的に一つの断片2つのtableViewは、同じデータセットを用いて、並んで配置され、それゆえ同じテーブルサイズレイアウトました。

予想される動作:1つのテーブルビューをスクロールすると、もう1つのテーブルビューのスクロールバーも同じ量だけスクロールする必要があります。

import javafx.beans.property.SimpleIntegerProperty 
import javafx.beans.property.SimpleStringProperty 
import javafx.collections.FXCollections 
import javafx.scene.control.ScrollBar 
import tornadofx.* 

class SyncScrollEx : View() { 
    override val root = hbox { 
     setPrefSize(300.0, 150.0) 
     this += find<MyTableFrag>() 
     this += find<MyTableFrag>() 
    } 
} 
class MyTableFrag : Fragment() { 
    var addEventOnlyOnceFlag = false 
    val persons = FXCollections.observableArrayList<GameWarrior>(
      GameWarrior(1,"Tyrion Lannister", "M"), 
      GameWarrior(2,"Ned Stark", "M"), 
      GameWarrior(3,"Sansa Stark", "F"), 
      GameWarrior(4,"Daenerys Targaryen", "F"), 
      GameWarrior(5,"Bran Stark", "M"), 
      GameWarrior(6,"Jon Snow", "M"), 
      GameWarrior(7,"Arya Stark", "F") 
    ) 
    override val root = vbox { 
     tableview(persons) { 
      column("ID", GameWarrior::idProperty) 
      column("Name", GameWarrior::nameProperty) 
      column("Gender", GameWarrior::genderProperty) 
      subscribe<SyncScrollEvent> { event -> 
       //Sync the ScrollX & ScrollY of both the tables 
       event.node.value = event.newVal.toDouble() 
      } 
      //Hack, need to initialize this when the table/scroll is rendered 
      setOnMouseEntered { 
       //Hack for not triggering the lookupAll event on every mouse enter 
       if (!addEventOnlyOnceFlag) { 
        addEventOnlyOnceFlag = true 
        //INFO: Look up for the scroll bars in tableView and add a listener 
        this.lookupAll(".scroll-bar").map { node -> 
         if (node is ScrollBar) { 
          node.valueProperty().addListener { 
           value, oldValue, newValue -> 
           println(node.orientation.toString() + " " + newValue) 
           fire(SyncScrollEvent(node, newValue)) 
          } 
         } 
        } 
       } 
      } 
     } 
    } 
} 
class GameWarrior(id: Int, name: String, gender: String) { 

    val idProperty = SimpleIntegerProperty(id) 
    var id by idProperty 

    val nameProperty = SimpleStringProperty(name) 
    var name by nameProperty 

    val genderProperty = SimpleStringProperty(gender) 
    var gender by genderProperty 
} 
class SyncScrollEvent(val node: ScrollBar, val newVal: Number) : FXEvent() 

のコメントは、私が直面しています問題を強調:

以下は私の現在の進行状況です。
また、EventListener内でFire()が発生するようなシナリオでは、両方のテーブルビューに対して「購読」が呼び出される方法を理解できません。

答えて

3

最初にスクロールバーにアクセスする必要があります。 TableViewにスキンが割り当てられると、スクロールバーが使用可能になります。皮膚が使用可能になると、我々はスクロールバーを見て、私たちはイベント

を発射できるように、私たちのマップに割り当て、変更をリッスン

val scrollbars = HashMap<Orientation, ScrollBar>() 

:我々は彼らを追跡するためにオリエンテーションをキーマップを作成します

skinProperty().onChange { 
    this.lookupAll(".scroll-bar").map { it as ScrollBar }.forEach { bar -> 
     scrollbars[bar.orientation] = bar 
     bar.valueProperty().onChange { 
      fire(SyncScrollEvent(bar, this)) 
     } 
    } 
} 

スクロールバーに値を問い合わせることができるため、イベントの位置は必要ありませんが、ソースのTableViewを追加するとイベントをフィルタリングする方が簡単です。

class SyncScrollEvent(val scrollbar: ScrollBar, val table: TableView<*>) : FXEvent() 

のスクロールイベントをリッスンし、イベントは、対応するオリエンテーションのために、他のテーブルビューに由来するならば、我々は唯一の私たちのスクロールバーの値を変更することを確認してみましょう::

subscribe<SyncScrollEvent> { event -> 
    if (event.table != this) 
     scrollbars[event.scrollbar.orientation]?.value = event.scrollbar.value 
} 

SyncScrollEventは次のようになります完全性のために、ここに修正されたアプリ全体があります:

import javafx.beans.property.SimpleIntegerProperty 
import javafx.beans.property.SimpleStringProperty 
import javafx.collections.FXCollections 
import javafx.geometry.Orientation 
import javafx.scene.control.ScrollBar 
import javafx.scene.control.TableView 
import tornadofx.* 
import java.util.* 

class SyncScrollEx : View() { 
    override val root = hbox { 
     setPrefSize(300.0, 150.0) 
     add(MyTableFrag::class) 
     add(MyTableFrag::class) 
    } 
} 

class MyTableFrag : Fragment() { 
    val persons = FXCollections.observableArrayList<GameWarrior>(
      GameWarrior(1, "Tyrion Lannister", "M"), 
      GameWarrior(2, "Ned Stark", "M"), 
      GameWarrior(3, "Sansa Stark", "F"), 
      GameWarrior(4, "Daenerys Targaryen", "F"), 
      GameWarrior(5, "Bran Stark", "M"), 
      GameWarrior(6, "Jon Snow", "M"), 
      GameWarrior(7, "Arya Stark", "F") 
    ) 

    val scrollbars = HashMap<Orientation, ScrollBar>() 

    override val root = vbox { 
     tableview(persons) { 
      column("ID", GameWarrior::idProperty) 
      column("Name", GameWarrior::nameProperty) 
      column("Gender", GameWarrior::genderProperty) 
      subscribe<SyncScrollEvent> { event -> 
       if (event.table != this) 
        scrollbars[event.scrollbar.orientation]?.value = event.scrollbar.value 
      } 
      skinProperty().onChange { 
       this.lookupAll(".scroll-bar").map { it as ScrollBar }.forEach { bar -> 
        scrollbars[bar.orientation] = bar 
        bar.valueProperty().onChange { 
         fire(SyncScrollEvent(bar, this)) 
        } 
       } 
      } 
     } 
    } 
} 

class GameWarrior(id: Int, name: String, gender: String) { 

    val idProperty = SimpleIntegerProperty(id) 
    var id by idProperty 

    val nameProperty = SimpleStringProperty(name) 
    var name by nameProperty 

    val genderProperty = SimpleStringProperty(gender) 
    var gender by genderProperty 
} 

class SyncScrollEvent(val scrollbar: ScrollBar, val table: TableView<*>) : FXEvent() 
+0

完璧なソリューション。私は肌のプロパティonchangeイベントの手がかりを持っていませんでした.. JavaFXは私に広大な海のように感じますが、何ヶ月も学ぶかもしれませんが、ありがたいことに私は竜巻で速く旅しています:) – mercy123

+0

私に戻ってくれてありがとう:)これは確かにコーナーケースですが、解決策はうまくいきました。 –

関連する問題