В этом примере я буду использовать модель представления и область обзора для отслеживания элемента для каждого инструментария. Нам нужно убедиться, что инструменты уникальны, поэтому мы можем удалить их из списка, когда редактор закрыт. Я создал объект домена Instrument
с идентификатором и именем:
class Instrument {
val idProperty = SimpleObjectProperty<UUID>(UUID.randomUUID())
var id by idProperty
val nameProperty = SimpleStringProperty()
var name by nameProperty
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as Instrument
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id.hashCode()
}
}
Мы хотим, чтобы модель представления мы можем впрыснуть в редакторе инструмента. Мы убедимся, что модель представления содержит новый инструмент по умолчанию. Он содержит фасад для свойства name, поэтому мы можем привязать его к полю ввода редактора.
class InstrumentModel: ItemViewModel<Instrument>() {
init {
item = Instrument()
item.name = "New instrument"
}
val name = bind { item?.nameProperty }
}
Fragment
имеет обратные вызовы для onDock
и onUndock
, которые могут быть использованы для отслеживания модели для этого фрагмента. Мы можем использовать события, чтобы сигнализировать об этом. Объявите следующие события:
class InstrumentAdded(val instrument: Instrument) : FXEvent()
class InstrumentRemoved(val instrument: Instrument) : FXEvent()
Переопределить в док обратных вызовов в InstrumentFragment
стрелять эти события:
override fun onDock() {
fire(InstrumentAdded(model.item))
}
override fun onUndock() {
fire(InstrumentRemoved(model.item))
}
В настоящее время мы будем держать список инструментов в главном окне, InstrumentsView
. Это может быть так же хорошо в Controller
.
val instruments = FXCollections.observableArrayList<Instrument>()
В классе инициализации главного вида, мы будем подписаться на события, которые мы создали и изменить наш список:
subscribe<InstrumentAdded> {
instruments.add(it.instrument)
}
subscribe<InstrumentRemoved> {
instruments.remove(it.instrument)
}
Акция «Новый инструмент» откроет новый InstrumentEditor в new Scope
, чтобы мы могли ввести в него модель представления и получить экземпляр, уникальный для этого редактора.
menuitem("Add instrument", "Shortcut+A") {
find<InstrumentFragment>(Scope()).openWindow()
}
К сожалению, мы не можем использовать openInternalWindow
, как он в настоящее время поддерживает только одно внутреннее окно в то время. Поэтому вместо этого я использовал openWindow
.
Если вы хотите закрыть редактор из действия, вы можете позвонить closeModal()
из любого места внутри фрагмента.
Я включил полное приложение примера с TableView, которое показывает открытые инструменты в настоящее время. Он будет выглядеть следующим образом. Обратите внимание, что вам нужно нажать «Сохранить» до того, как изменения будут удалены из модели и будут видны в таблице.
Надеюсь, это то, что вы ищете, или что вы, по крайней мере, можете изменить его, чтобы он соответствовал вашему варианту использования на основе этого образца.
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.property.SimpleStringProperty
import javafx.collections.FXCollections
import tornadofx.*
import java.util.*
class Instrument {
val idProperty = SimpleObjectProperty<UUID>(UUID.randomUUID())
var id by idProperty
val nameProperty = SimpleStringProperty()
var name by nameProperty
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as Instrument
if (id != other.id) return false
return true
}
override fun hashCode(): Int {
return id.hashCode()
}
}
class InstrumentModel : ItemViewModel<Instrument>() {
init {
item = Instrument()
item.name = "New instrument"
}
val name = bind { item?.nameProperty }
}
class InstrumentAdded(val instrument: Instrument) : FXEvent()
class InstrumentRemoved(val instrument: Instrument) : FXEvent()
class InstrumentFragment : Fragment("Instrument Editor") {
val model: InstrumentModel by inject()
override val root = form {
prefWidth = 300.0
fieldset("Edit instrument") {
field("Name") {
textfield(model.name)
}
}
button("Save") {
setOnAction {
model.commit()
}
}
}
override fun onDock() {
fire(InstrumentAdded(model.item))
}
override fun onUndock() {
fire(InstrumentRemoved(model.item))
}
}
class InstrumentsView : View() {
val instruments = FXCollections.observableArrayList<Instrument>()
override val root = borderpane {
setPrefSize(400.0, 300.0)
top {
menubar {
menu("Tools") {
menuitem("Add instrument", "Shortcut+A") {
find<InstrumentFragment>(Scope()).openWindow()
}
}
}
}
center {
tableview(instruments) {
column("Name", Instrument::nameProperty)
columnResizePolicy = SmartResize.POLICY
}
}
}
init {
subscribe<InstrumentAdded> {
instruments.add(it.instrument)
}
subscribe<InstrumentRemoved> {
instruments.remove(it.instrument)
}
}
}
Вы хотите получить доступ к фактическим фрагментам или просто хотите получить список моделей, которые они содержат, и этот список должен обновляться при открытии/закрытии редактора фрагментов? Должен ли каждый InstrumentFragment управлять собственным/отдельным инструментом? PS: Никогда не создавайте экземпляр фрагмента напрямую, используйте find, inject или 'this + = InstrumentFragment'. –
Мне нужен доступ к списку моделей (ofcource, я также могу получить ссылку на модель, если у меня будет список фрагментов - мне самое главное - чистое и элегантное решение), и я хочу обновить этот список после открытия/закрытия редактор фрагментов. Каждый IntrumentFragment знает только о своей модели (или имеет ссылку на родителя - почему бы и нет?). –