原文地址:TornadoFx實現側邊欄選單效果 - Stars-One的雜貨小窩
之前年前研究的東西,給藍奏批次下載器重構了頁面,實現了側邊欄選單的效果,稍微總結下把
首先,要說明的是,總體佈局為一個Hbox,側邊欄在左邊,是一個vbox,右側則是各選單對應的佈局,使用StackPane佈局
原理是,點選左側vbox中的選單項,更改右側的佈局(顯示對應選單項的佈局)
//定義個側邊選單的資料類
data class LeftMenuItem(val title: String)
class TestView : View("Hello TornadoFX") {
val model by inject<MainViewModel>()
override val root = vbox() {
prefWidth = 400.0
prefHeight = 200.0
hbox {
vbox {
val list = listOf(LeftMenuItem("首頁"), LeftMenuItem("下載列表"), LeftMenuItem("資源搜尋"))
list.forEachIndexed { index, leftMenuItem ->
button(leftMenuItem.title) {
action {
//點選按鈕更改選中的下標數值
model.selectIndex.set(index)
}
}
}
}
stackpane {
//顯示當前選中拿到下標數值
label(model.selectIndex.asString()){
prefWidth(120.0)
}
}
}
}
}
class MainViewModel : ViewModel() {
//當前選中的選單項下標
val selectIndex = SimpleIntegerProperty(0)
}
效果如下圖所示:
當然,這裡右側佈局只是個簡單的text,我們在修改下,讓右側佈局根據當前所選的下標值更改顯示即可
val list = listOf(LeftMenuItem("首頁"), LeftMenuItem("下載列表"), LeftMenuItem("資源搜尋"))
hbox {
vbox {
list.forEachIndexed { index, leftMenuItem ->
button(leftMenuItem.title) {
action {
model.selectIndex.set(index)
}
}
}
}
stackpane {
list.forEachIndexed { index, leftMenuItem ->
//這裡以label演示,可以更改為佈局或者是View型別
label(model.selectIndex.asString()) {
prefWidth(120.0)
visibleWhen {
model.selectIndex.eq(index)
}
}
}
}
}
效果如下所示:
這裡的View,指的是TornadoFx中的View
我們不同頁面都是寫在View中,所以按照上面的程式碼,還需要調整下
首先,LeftMenuItem類中新增個物件,用來儲存對應的View
data class LeftMenuItem(val title: String,val view:View)
右側佈局要這樣寫:
//右側佈局
stackpane {
//text(homeModel.selectIndex.asString())
list.forEachIndexed { index, leftMenuItem ->
val leftView = leftMenuItem.view
leftView.root.visibleWhen {
homeModel.selectIndex.eq(index)
}
this += leftMenuItem.view
}
}
上面省略了構造LeftMenuItem的初始化list的相關程式碼,相信各位知道該如何新建LeftMenuItem物件(View物件可以直接呼叫無參構造方法)
接下來就是側邊欄的美化工作,這樣直接貼出樣式的程式碼吧,關於css的使用,可以看下上一篇TornadoFx中的css美化
package site.starsone.xtool.app
import javafx.scene.layout.BorderStrokeStyle
import javafx.scene.paint.CycleMethod
import javafx.scene.paint.LinearGradient
import javafx.scene.paint.Stop
import javafx.scene.text.FontWeight
import tornadofx.*
class Styles : Stylesheet() {
companion object {
val leftMenu by cssclass()
val leftMenuSelect by cssclass()
}
init {
leftMenu {
prefWidth = 200.px
startMargin = 10.px
fontSize = 14.px
padding = box(15.px)
backgroundColor += c("white")
and(hover) {
textFill = c("#1890ff")
}
}
leftMenuSelect{
prefWidth = 200.px
startMargin = 10.px
fontSize = 14.px
padding = box(15.px)
backgroundColor +=c("#e6f7ff")
textFill = c("#1890ff")
borderColor += box(null,c("#1890ff"),null,null)
borderWidth += box(0.px,2.px,0.px,0.px)
borderStyle += BorderStrokeStyle.SOLID
}
}
}
View中使用樣式:
class TestView : View("Hello TornadoFX") {
val model by inject<MainViewModel>()
override val root = vbox() {
prefWidth = 400.0
prefHeight = 200.0
//單獨執行View的話,記得匯入樣式的操作
importStylesheet(Styles::class)
val list = listOf(LeftMenuItem("首頁"), LeftMenuItem("下載列表"), LeftMenuItem("資源搜尋"))
hbox {
vbox {
list.forEachIndexed { index, leftMenuItem ->
button(leftMenuItem.title) {
//給button新增樣式
addClass(Styles.leftMenu)
//根據當前是否已選(下標是否一致)來切換button樣式
toggleClass(Styles.leftMenuSelect, model.selectIndex.eq(index))
action {
model.selectIndex.set(index)
}
}
}
}
stackpane {
list.forEachIndexed { index, leftMenuItem ->
//這裡以label演示,可以更改為佈局或者是View型別
label("這是"+leftMenuItem.title) {
prefWidth(120.0)
visibleWhen {
model.selectIndex.eq(index)
}
}
}
}
}
}
}
效果如下圖所示: