2017-01-04 72 views
0

我正在嘗試跨瀏覽器同步滾動條。 (兩個水平&垂直)TornadoFX JavaFX Sync跨瀏覽器滾動

enter image description here

的SyncScrollEx查看具有兩個的tableView這基本上是並排一個片段置於側,具有相同的數據集,並因此相同的表大小的佈局。

預期行爲:當我在一個tableview上滾動時,另一個tableview的滾動條也應滾動相同的數量。

下面是我目前的進度:

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() 

的講話突出表明,我所面臨的問題。
此外,我無法理解在這種情況下,如果Fire()發生在EventListener內部,將如何爲這兩個表視圖調用「訂閱」

回答

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,則更容易過濾事件。該SyncScrollEvent現在看起來是這樣的:

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

讓我們來聽聽滾動事件,並確保我們只能改變我們的滾動值,如果事件與其他的tableview起源,爲相應的方向:

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

爲了完整性,這裏是整個修改的應用程序:

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

謝謝你回到我:)這的確是一個角落的情況下,但我認爲解決方案運作良好。 –