Tornadofx Javafx - Как перезагрузить представление / компонент

Так что это основной вопрос.
Я пытаюсь освежить взгляды других взглядов.

Допустим, у меня есть представление EmployeeTableView, которое показывает табличное представление сотрудников, выполняя вызов REST API.
В другом представлении у меня есть фильтр EmployeeFilterView, в котором у меня есть пол, диапазон заработной платы, тип сотрудника и т. Д.
У меня также есть объект userContext, в котором я храню пользовательские настройки. Итак, по умолчанию, допустим, я сохранил значение гендерного фильтра как «Мужской», диапазон заработной платы - как ВСЕ и т. Д. Этот объект отправляется как параметр в EmployeeTableView.

Когда загружен EmployeeTableView, я выполняю вызов restAPI со значениями userContext, чтобы получить сведения о сотруднике. Так что это нормально работает. Теперь я изменяю фильтр пола на «Женский» и присваиваю это значение в моем userContext.
Теперь, если бы я мог просто перезагрузить EmployeeTableView с помощью объекта userContext, вызов restapi получил бы обновленные значения.

Но как я могу это сделать?
Также предложите лучший подход, если он у вас есть.


person niteesh    schedule 29.04.2017    source источник


Ответы (2)


EventBus - одно из подходящих решений. Другой вариант - использовать ViewModel или Controller в качестве объекта UserContext и позволить ему включать фактический наблюдаемый список сотрудников, а затем привязать этот список к TableView в EmployeeTableView. Всякий раз, когда список в контексте обновляется, TableView также обновляется.

Представление фильтра вызовет функцию в UserContext для выполнения фактического вызова REST и обновления списка сотрудников на основе этого.

Вы можете создать отдельный объект EmployeeQuery, который можно вставить как в EmployeeFilterView, так и в UserContext, чтобы он мог извлекать выбранные значения фильтра для выполнения запроса. Этот объект запроса содержит список всех параметров поиска, которые вы хотите передать серверу.

Вы также можете рассмотреть возможность создания отдельной области, чтобы эти компоненты были разделены, если это имеет смысл для вашей архитектуры.

Как именно вы определяете эти компоненты, по большей части дело вкуса. Вот одно из предложений. Я использовал RangeSlider от ControlsFX для пользовательского интерфейса псевдопоиска.

Чтобы было легче представить, как это связано, вот скриншот:

(Все имена и зарплаты вымысел :)

Приложение для сотрудников

/**
 * The employee domain model, implementing JsonModel so it can be fetched 
 * via the REST API
 */
class Employee : JsonModel {
    val nameProperty = SimpleStringProperty()
    var name by nameProperty

    val salaryProperty = SimpleIntegerProperty()
    var salary by salaryProperty

    val genderProperty = SimpleObjectProperty<Gender>()
    var gender by genderProperty

    override fun updateModel(json: JsonObject) {
        with (json) {
            name = getString("name")
            salary = getInt("salary")
            gender = Gender.valueOf(getString("gender"))
        }
    }
}

enum class Gender { Male, Female }

/**
 * Container for the list of employees as well as a search function called by the filter
 * view whenever it should update the employee list.
 */
class EmployeeContext : Controller() {
    val api: Rest by inject()
    val query: EmployeeQuery by inject()
    val employees = SimpleListProperty<Employee>()

    fun search() {
        runAsync {
            FXCollections.observableArrayList(Employee().apply {
                name = "Edvin Syse"
                gender = Gender.Male
                salary = 200_000
            })
            //api.post("employees/query", query).list().toModel<Employee>()
        } ui {
            employees.value = it
        }
    }
}

/**
 * Query object used to define the query sent to the server
 */
class EmployeeQuery : ViewModel(), JsonModel {
    val genderProperty = SimpleObjectProperty<Gender>(Gender.Female)
    var gender by genderProperty

    val salaryMinProperty = SimpleIntegerProperty(50_000)
    var salaryMin by salaryMinProperty

    val salaryMaxProperty = SimpleIntegerProperty(250_000)
    var salaryMax by salaryMaxProperty

    val salaryDescription = stringBinding(salaryMinProperty, salaryMaxProperty) {
        "$$salaryMin - $$salaryMax"
    }

    override fun toJSON(json: JsonBuilder) {
        with(json) {
            add("gender", gender.toString())
            add("salaryMin", salaryMin)
            add("salaryMax", salaryMax)
        }
    }
}

/**
 * The search/filter UI
 */
class EmployeeFilterView : View() {
    val query: EmployeeQuery by inject()
    val context: EmployeeContext by inject()

    override val root = form {
        fieldset("Employee Filter") {
            field("Gender") {
                combobox(query.genderProperty, Gender.values().toList())
            }
            field("Salary Range") {
                vbox {
                    alignment = Pos.CENTER
                    add(RangeSlider().apply {
                        max = 500_000.0
                        lowValueProperty().bindBidirectional(query.salaryMinProperty)
                        highValueProperty().bindBidirectional(query.salaryMaxProperty)
                    })
                    label(query.salaryDescription)
                }
            }
            button("Search").action {
                context.search()
            }
        }
    }
}

/**
 * The UI that shows the search results
 */
class EmployeeTableView : View() {
    val context: EmployeeContext by inject()

    override val root = borderpane {
        center {
            tableview(context.employees) {
                column("Name", Employee::nameProperty)
                column("Gender", Employee::genderProperty)
                column("Salary", Employee::salaryProperty)
            }
        }
    }
}

/**
 * A sample view that ties the filter UI and result UI together
 */
class MainView : View("Employee App") {
    override val root = hbox {
        add(EmployeeFilterView::class)
        add(EmployeeTableView::class)
    }
}
person Edvin Syse    schedule 01.05.2017
comment
вау, это был изящный способ сделать это. Спасибо !! мне очень помогли. - person niteesh; 10.05.2017
comment
Здорово! ViewModel и особенно ItemViewModel - фантастический инструмент для связывания разрозненных компонентов пользовательского интерфейса вместе. Я часто им пользуюсь. - person Edvin Syse; 11.05.2017

В итоге я использовал Tornadofx -> EventBus

Обычно, когда я меняю какой-либо из фильтров, я запускаю событие, которое перестраивает узел с обновленными значениями.

Не уверен, что подход правильный, поэтому все еще оставляю его открытым для обсуждения.

person niteesh    schedule 01.05.2017
comment
Хороший звонок. Я отправлю ответ с другим предложением сегодня вечером :) - person Edvin Syse; 01.05.2017