问题
I am trying to add functionality in my app to allow a user to change the background theme (Light/Dark) of the app in a view called Settings. If I am changing the theme by using two different style sheets from Stylesheet classes, then how can I change which stylesheet the app uses during execution? Is there a simpler way to do this?
My code for these settings can be found below. Any improvements on the code are helpful as well:
class Settings(){
var BackGroundTheme: BackGroundThemeState = BackGroundThemeState.Light
}
enum class BackGroundThemeState{Light, Dark}
class SettingsController: Controller(){
private var settings = Settings()
fun changeTheme(state: BackGroundThemeState){
when(state){
Light -> settings.BackGroundTheme = Light
Dark -> settings.BackGroundTheme = Dark
}
when(settings.BackGroundTheme){
// Light -> do nothing for now
Dark -> importStylesheet(app.DarkThemeStyleSheet)
}
reloadStylesheetsOnFocus()
}
}
class SettingsView: View("Settings"){
val settings: SettingsController by inject()
private val toggleGroup = ToggleGroup()
override val root = vbox(){
alignment = Pos.BOTTOM_CENTER
setPrefSize(300.0, 200.0)
hbox(){
alignment = Pos.BASELINE_LEFT
vbox {
paddingTop = 10.0
paddingLeft = 30.0
paddingBottom = 90.0
label("Theme")
radiobutton("Light", toggleGroup){
isSelected = true
action {
settings.changeTheme(Light)
}
}
radiobutton("Dark", toggleGroup) {
action {
settings.changeTheme(Dark)
}
}
}
}
hbox {
alignment = Pos.BOTTOM_RIGHT
paddingRight = 15.0
paddingBottom = 10.0
button("OK"){
setPrefSize(70.0, 30.0)
action{
find(SettingsView::class).close()
}
}
}
}
}
回答1:
This can be done much more smoothly if you rely on observable properties. Make a property that holds the current theme and remove the old and add the new theme when this property changes.
You can rely on built in functionality of the toggle group to bind to the active theme property.
Here is a complete application showing this:
class MyThemeApp : App(SettingsView::class) {
val themeController: ThemeController by inject()
override fun start(stage: Stage) {
super.start(stage)
// Make sure we initialize the theme selection system on start
themeController.start()
}
}
class ThemeController : Controller() {
// List of available themes
val themes = SimpleListProperty<KClass<out Stylesheet>>(listOf(LightTheme::class, DarkTheme::class).observable())
// Property holding the active theme
val activeThemeProperty = SimpleObjectProperty<KClass<out Stylesheet>>()
var activeTheme by activeThemeProperty
fun start() {
// Remove old theme, add new theme on change
activeThemeProperty.addListener { _, oldTheme, newTheme ->
oldTheme?.let { removeStylesheet(it) }
newTheme?.let { importStylesheet(it) }
}
// Activate the first theme, triggering the listener above
activeTheme = themes.first()
}
}
class SettingsView : View("Settings") {
val settings: ThemeController by inject()
override val root = form {
fieldset("Theme") {
field {
vbox {
togglegroup {
// One radio button for each theme, with their value set as the theme
settings.themes.forEach { theme ->
radiobutton(theme.simpleName, getToggleGroup(), theme)
}
// The toggle group value is bound to the activeThemeProperty
bind(settings.activeThemeProperty)
}
}
}
buttonbar {
button("OK").action(this@SettingsView::close)
}
}
}
}
// Two themes for completeness
class DarkTheme : Stylesheet() {
init {
root {
backgroundColor += Color.DARKGREEN
}
}
}
class LightTheme : Stylesheet() {
init {
root {
backgroundColor += Color.LIGHTCYAN
}
}
}
来源:https://stackoverflow.com/questions/50520076/change-style-sheets-during-app-execution-tornadofx