«Настоящий» шаблон MVC с Scala и JavaFX с несколькими представлениями и контроллерами - PullRequest
0 голосов
/ 27 августа 2018

Я создаю настольное приложение 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 для смены сцен)?

Раньше мои приложения были просты: один экран, один контроллер. В таком случае, как я могу действовать ЭЛЕГАНТНО, без «обмана»?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...