我正在尝试在tableviews上同步滚动。 (水平和垂直)
SyncScrollEx View有两个tableView,它基本上是一个并排放置的Fragment,具有相同的数据集,因此具有相同的表大小布局。
预期行为:当我滚动一个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()
评论突出了我所面临的问题 另外,我无法理解如何在EventListener中发生Fire()的场景中为两个tableviews调用“subscribe”
答案 0 :(得分: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()
让我们听一下滚动事件,并确保我们只在事件来自其他桌面视图时更改我们的滚动条值,以获得相应的方向:
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()