我正在构建一个scala桌面应用程序,要求是:
我不能使用ScalaFX,Swing(Java)或Swing(Scala)。
在主要的主要方面,从现在开始MyAwesomeApp
我做了:
class MyAwesomeApp extends Application {
override def start(primaryStage: Stage) {
// Stuff here
}
}
object MyAwesomeApp extends App {
Application.launch(classOf[MyAwesomeApp], args: _*)
}
现在选择三个通用视图:MainMenu
,SettingsMenu
,NewGameMenu
,GamePanel
。
可以想象,在开始时,应用程序将以MainMenu
启动,其中有两个按钮可以带到NewGameMenu
和SettingsMenu
。然后在NewGameMenu
中将有一个按钮,将我带到GamePanel
。
为此,我将有一个控制器:MainMenuController,SettingsMenuController,NewGameMenuController,GamePanelController。但是此控制器与平台无关:换句话说,没有JavaFX控制器。为什么?因为JavaFX控制器可以“查看”视图的所有组件,例如TextBoxes,Button等,并且可以仅使用@FXML
标签“加载”它们。这不是我的情况,因为我必须是“独立于视图”的,所以我考虑了一个包装器和一个观察者模式。
我想到了FXControllers
(JavaFX控制器)和Observers
(真实的MVC控制器)。每个FXController将具有一个实现其特征(= interface)的Observer。这是一些代码:
这是加载fxml的帮助对象
object ViewLoader {
def loadView(controller: GenericFXController[_], layoutPath: String): Pane = {
val loader = new FXMLLoader(getClass.getResource("/layouts/" + layoutPath))
loader.setController(controller)
loader.load()
}
}
一个通用的FXController将会有这个(我使用了通用类型“ A”,因为我知道每个FXController都会有一个观察者,但是我不知道哪个):
abstract class GenericFXController[A] (private val path: String) {
protected var observer: A = _
protected val layout: Pane = ViewLoader.loadView(this, path)
def setObserver(observer: A): Unit = {
this.observer = observer
}
def getLayout: Pane = layout
def getPaneType: SceneType.Value = paneType
}
最后是为MainMenu定义的FXController:
class MainMenuPaneFXController extends GenericFXController[MainMenuObserver](path = "MainMenu.fxml") {
@FXML protected var startNewGameBtn: Button = _
@FXML protected var settingsBtn: Button = _
this.startNewGameBtn.setOnMouseClicked(_ => {
this.observer.onStartNewGameBtnPressed()
})
this.settingsBtn.setOnMouseClicked(_ => {
this.observer.onSettingsPressed()
})
}
trait MainMenuObserver {
def onStartNewGameBtnPressed()
def onSettingsPressed()
}
现在简化了控制器:
class MainMenuObserverImpl extends MainMenuObserver {
override def onStartNewGameBtnPressed(): Unit = println("Start pressed")
override def onSettingsPressed(): Unit = println("Settings pressed")
}
我有一个视图包装器,将JavaFX隐藏在trat和class后面。
trait GenericView {
def showView(): Unit
def closeView(): Unit
def isShowing: Boolean
def setScene(sceneType: SceneType)
}
SceneType是简单的“枚举”,具有类似“ MainMenu”,“ SettingsMenu”等的声音。
在主要方法中,我启动视图
val view: GenericView = new ViewFX(primaryStage)
我可以向GenerView特性添加方法,但必须保持“平台无关”,因此我无法返回JavaFX Scene或Swing Button。该视图无法确定控制器类:应该具有一个“ .setObserver(),并且FXControllers
在某种程度上是该视图的一部分。
是否应该在ViewFX中创建每个场景,并在创建时为每个人设置控制器?如何将视图传递给控制器(以及用于更改场景的GenericView)?
我的应用以前很简单:一个屏幕,一个控制器。在这种情况下,我该如何优雅地进行而不会“作弊”?