TornadoFx實現側邊欄選單效果

2022-05-29 18:03:12

原文地址: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

這裡的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)
                        }
                    }
                }
            }
        }
    }
}

效果如下圖所示:

參考