Я создаю настольное приложение Scala, требования:
- Java 8 (не 9, не 10, не 7)
- Использование Scala (возможно, с Java)
- MVC Patter (View и Controller должны быть независимы от "платформы", у моего учителя уже есть рабочая консоль и представление Swing, но нам ничего не говорят)
- Реализация View должна быть на JavaFX
Я не могу использовать 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, Buttons и т. Д., И может просто «загрузить» их с тегом @FXML
. Это не мой случай, так как я должен быть «Независимым от просмотра», поэтому я думаю о оболочке и шаблоне Observer.
Я придумал FXControllers
(контроллеры JavaFX) и Observers
(настоящие контроллеры MVC). Каждый FXController будет иметь Наблюдателя, который реализует его черту (= интерфейс). Это некоторый код:
Это вспомогательный объект для загрузки 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
}
И, наконец, определенный FXController для MainMenu:
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 за буквой и классом.
trait GenericView {
def showView(): Unit
def closeView(): Unit
def isShowing: Boolean
def setScene(sceneType: SceneType)
}
Где SceneType - это простое «Enum» с такими голосами, как «MainMenu», «SettingsMenu» и т. Д.
В основном методе я запускаю представление
val view: GenericView = new ViewFX(primaryStage)
... А теперь как передать "Наблюдатели" в "FXControllers"?
Я могу добавить методы к признаку GenerView, но он должен оставаться «независимым от платформы», поэтому я не могу вернуть сцену JavaFX или кнопку Swing. Представление не может istantiate классы контроллера: должно иметь ".setObserver (), и FXControllers
являются, в некотором роде, частью представления.
Должен ли я создавать каждую сцену в ViewFX и устанавливать контроллер для всех при создании? Как передать представление на контроллеры (и GenericView для смены сцен)?
Раньше мои приложения были просты: один экран, один контроллер. В таком случае, как я могу действовать ЭЛЕГАНТНО, без «обмана»?