powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Перемещение позиции курсора таблицы при использовании JavaFX и MVVM
5 сообщений из 5, страница 1 из 1
Перемещение позиции курсора таблицы при использовании JavaFX и MVVM
    #39037326
NDAleksey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ух... Не знал как задать вопрос и сформулировать нему топика, но постараюсь объяснить.

Банальная задача - есть сущность "MeasurementType" (тип единиц измерений). Есть диалоговое окно (а вернее таба в TabPane) "Справочник типов единиц измерений". Выглядит оно, как показано на рисунке.

Первый опыт использования MVVM, поэтому не судите строго. В окне поля ввода привязываются ко MeasurementTypeViewModel, а таблица к MeasurementTypesViewModel (разница в окончании) . Из БД представлю только одну сущность - MeasurementType. Далее привожу эти классы:

MeasurementTypeViewModel:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
public class MeasurementTypeViewModel extends AbstractViewModel<MeasurementType> {

    private final IntegerProperty id = new SimpleIntegerProperty();
    private final StringProperty name = new SimpleStringProperty();
    private final StringProperty code = new SimpleStringProperty();

    private final ListProperty<MeasurementType> types = new SimpleListProperty<>();

    public MeasurementTypeViewModel() {}

    private MeasurementTypeViewModel(MeasurementTypeViewModel viewModel) {
        code.set(viewModel.getCode());
        name.set(viewModel.getName());
    }

    public MeasurementTypeViewModel(MeasurementType measurementType) {
        id.set(measurementType.getId());
        name.set(measurementType.getName());
        code.set(measurementType.getCode());
    }

    public MeasurementTypeViewModel(int id, String code, String name) {
        this(code, name);
        this.id.set(id);
    }

    public MeasurementTypeViewModel(String code, String name) {
        this.code.set(code);
        this.name.set(name);
    }

    // getters/setters для полей
}



MeasurementTypesViewModel:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
public class MeasurementTypesViewModel {
    private final ListProperty<MeasurementTypeViewModel> types;

    private final ObjectProperty<EventHandler<ActionEvent>> addBtn;
    private final ObjectProperty<EventHandler<ActionEvent>> deleteBtn;

    private final ObjectProperty<MeasurementTypeViewModel> type;

    private ObjectProperty<MeasurementTypeViewModel> selectedRow = new SimpleObjectProperty<>();

    private final DbHelper dbHelper = DbHelper.getInstance();

    public MeasurementTypesViewModel(MeasurementTypeViewModel viewModel) {
        type = new SimpleObjectProperty<>(viewModel);

        List<MeasurementTypeViewModel> typeList = new ArrayList<>();
        for (MeasurementType type : dbHelper.importAllMeasurementTypes()) {
            typeList.add(new MeasurementTypeViewModel(type));
        }

        types = new SimpleListProperty<>(new ObservableListWrapper(typeList));

        addBtn = new SimpleObjectProperty<>(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                MeasurementType typeEntity = new MeasurementType(type.get().getCode(), type.get().getName());

                if (dbHelper.exportMeasurementType(typeEntity) != false) {
                    types.get().add(new MeasurementTypeViewModel(typeEntity));
                    type.get().setCode(null);
                    type.get().setName(null);
//                    selectedRow = new SimpleObjectProperty<>(types.get().get(types.getSize()));  -- это не работает
                }
            }
        });

        deleteBtn = new SimpleObjectProperty<>(event -> {

            if (getSelectedRow() == null) {
                return;
            }

            Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
            alert.setTitle("Удаление типа единицы измерения");
            alert.setHeaderText(null);
            alert.setContentText("Вы действительно хотите удалить тип:\nНаименование:   " + getSelectedRow().getName());

            ButtonType yes = new ButtonType("Удалить");
            ButtonType no = new ButtonType("Отмена");

            alert.getButtonTypes().setAll(yes, no);

            Optional<ButtonType> result = alert.showAndWait();

            if (result.get() == yes) {
                for (MeasurementTypeViewModel type : types) {
                    if (type.equals(getSelectedRow())) {
                        if (dbHelper.removeMeasurementType(type.getId())) {
                            types.get().remove(type);
                        }
                        break;
                    }
                }
            }
        });
    }



NewMeasurementTypeController:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
public class NewMeasurementTypeController implements Initializable {
    @FXML
    private Button addBtn;

    @FXML
    private Button deleteBtn;

    @FXML
    private Button cancelBtn;

    @FXML
    private TextField codeTextField;

    @FXML
    private TextField nameTextField;

    @FXML
    TableView<MeasurementTypeViewModel> typesTableView;

    @FXML
    TableColumn<MeasurementTypeViewModel, Integer> idTableColumn;

    @FXML
    TableColumn<MeasurementTypeViewModel, String> codeTableColumn;

    @FXML
    TableColumn<MeasurementTypeViewModel, String> nameTableColumn;

    private MeasurementTypesViewModel measurementTypesViewModel;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        MeasurementTypeViewModel typeViewModel = new MeasurementTypeViewModel();
        codeTextField.textProperty().bindBidirectional(typeViewModel.codeProperty());
        nameTextField.textProperty().bindBidirectional(typeViewModel.nameProperty());

        measurementTypesViewModel = new MeasurementTypesViewModel(typeViewModel);

        // make addBtn disable if codeTextField and nameTextField are empty
        addBtn.disableProperty().bind(typeViewModel.isActionPossibleProperty());
        addBtn.onActionProperty().bindBidirectional(measurementTypesViewModel.addBtnProperty());

        // binding ObservableCollection "Types" on the TableView
        typesTableView.itemsProperty().bindBidirectional(new SimpleObjectProperty<>(measurementTypesViewModel.getTypes()));

        deleteBtn.onActionProperty().bindBidirectional(measurementTypesViewModel.deleteBtnProperty());
        cancelBtn.onActionProperty().bindBidirectional(measurementTypesViewModel.cancelBtnProperty());

        initializeTableView();

    }

    private void initializeTableView() {
        idTableColumn.setCellValueFactory(param -> param.getValue().idProperty().asObject());
        codeTableColumn.setCellValueFactory(param -> param.getValue().codeProperty());
        nameTableColumn.setCellValueFactory(param -> param.getValue().nameProperty());

//        idTableColumn.setCellValueFactory(new PropertyValueFactory("id"));
//        codeTableColumn.setCellValueFactory(new PropertyValueFactory("code"));
//        nameTableColumn.setCellValueFactory(new PropertyValueFactory("name"));

        typesTableView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            measurementTypesViewModel.selectedRowProperty().unbind();
            measurementTypesViewModel.selectedRowProperty().bindBidirectional(new SimpleObjectProperty<>(newValue));
        });
    }
}



Небольшие пояснения. Разметку fxml не даю - она не нужна.Контроллер - представляет собой вьюшку (название нелепое - потом исправлю).
Два поля привязываются ко MeasurementTypeViewModel. Таблица привязывается к коллекции этих вьюмоделей (к объекту класса MeasurementTypesViewModel). Класс DbHelper тоже не представляю за ненадобностью (работает как положено).

Не знаю, получилось может и сумбурно. Если неясно, задавайте вопросы.

А теперь моя просьба:
- первое и первостепенное - где перемещать курсор в таблице после добавления новой записи (во View или ViewModel) и как это сделать????
- второе - покритикуйте код (что сделал не так? как надо было?)

Очень-очень слезно прошу помощи!, комрады!!!
...
Рейтинг: 0 / 0
Перемещение позиции курсора таблицы при использовании JavaFX и MVVM
    #39037360
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NDAleksey - первое и первостепенное - где перемещать курсор в таблице после добавления новой записи (во View или ViewModel) и как это сделать????
ViewModel это бизнес-сущности адаптированная для биндинга. Что такое "курсор в таблице" не очень понятно. Там есть фокус и есть выбранные ячейки. Если удобно selection забиндить на ViewModel, то почему бы и нет?

NDAleksey - второе - покритикуйте код (что сделал не так? как надо было?)

Если у тебя 2-звенка, то не очень понятно зачем было разделять Model и ViewModel.

DbHelper - странное имя класса. Это же не Helper, а Repository.
Вызов его из ViewModel настораживает ещё больше. Действия пользователя, вроде как, обрабатывать должен контроллер?
Не удачное именование MeasurementTypesViewModel, MeasurementTypeViewModel - имена визуально почти не различимы.
MeasurementTypeViewModel - действительно ли нужно столько конструкторов?

В случае многократного вызова вроде type.get() и param.getValue() очень не хватает локальной переменной.

Для полей контроллера есть удобный компактный формат:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
@FXML Button addBtn;
@FXML Button deleteBtn;
@FXML Button cancelBtn;
@FXML TextField codeTextField;
@FXML TextField nameTextField;
@FXML TableView<MeasurementTypeViewModel> typesTableView;
@FXML TableColumn<MeasurementTypeViewModel, Integer> idTableColumn;
@FXML TableColumn<MeasurementTypeViewModel, String> codeTableColumn;
@FXML TableColumn<MeasurementTypeViewModel, String> nameTableColumn;


Модификатор private для полей зачастую является просто синтаксическим шумом.
...
Рейтинг: 0 / 0
Перемещение позиции курсора таблицы при использовании JavaFX и MVVM
    #39037528
NDAleksey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz[\b], спасибо, что Вы ответили!!! Мне это и надо было)

BlazkowiczТам есть фокус и есть выбранные ячейки. Если удобно selection забиндить на ViewModel, то почему бы и нет?

Именно! Так вот я и спрашиваю как это сделать? У меня щас есть selectRow поле во ViewModel. Оно подвязывается к таблице во вьюшке. Но как переставить выделение в таблице через ViewModel? Подскажите?

BlazkowiczЕсли у тебя 2-звенка, то не очень понятно зачем было разделять Model и ViewModel.
Да, получается так. Но, я приведу Ваши слова из топика на форуме, которые натолкнули на использование MVVM в моем приложении:

авторЭто называется Model-View-ViewModel (MVVM). Model - ваша существующая модель. View - это JavaFX контролы. ViewModel это "обёртка" с биндингами

Это первое приложение и хочу хорошо разобраться. У меня есть класс доменного слоя MeasurementType, который я не привел, но упомянул, и использование его видно во вьюмодели в классе выше. У меня есть вьюшка (файл.fxml) + NewMeasurementTypeController, который не смотрите на название является частью вьюшки, где происходит первичная инициализация контролов с биндингом на них полей из классов ViewModel (MeasurementTypeViewModel, MeasurementTypesViewModel).
Вот мне и показалось, что я несколько приблизился к реализации MVVM. Если нет, то прошу [b]развернуто
, на сколько это возможно, объяснить, что не так.

BlazkowiczDbHelper - странное имя класса. Это же не Helper, а Repository.
Да, полностью согласен. Вообще дальше нужно будет использовать UnitOfWork. Но это пока)


BlazkowiczВызов его из ViewModel настораживает ещё больше.
А вот тут не понял совсем. Как так?

BlazkowiczДействия пользователя, вроде как, обрабатывать должен контроллер?
А разве действия обрабатываются не во ViewModel?

Про остальное полностью согласен, но это несколько потом. Хотя ценные замечания. Обязательно учту.
...
Рейтинг: 0 / 0
Перемещение позиции курсора таблицы при использовании JavaFX и MVVM
    #39037554
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
NDAleksey,

У TableViewSelectionModel два свйоства. selectedIndex и selectedItem. В чем сложности прибиндить их к модели?
...
Рейтинг: 0 / 0
Перемещение позиции курсора таблицы при использовании JavaFX и MVVM
    #39037627
NDAleksey
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczNDAleksey,

У TableViewSelectionModel два свйоства. selectedIndex и selectedItem. В чем сложности прибиндить их к модели?

Сложность в том, что typesTableView.getSelectionModel().selectedIndexProperty() - ReadOnlyProperty и биндить к нему я напрямую не могу.
Но смогу прибиндить в Listener-e:
Код: java
1.
2.
typesTableView.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> {
}


, как я сделал это для selectedItemProperty . Но при таком подходе событие происходит тогда, когда я выделяю строки таблицы мышью, но никак не после нажатия на кнопку добавления. А обработчик кнопки у меня зашит во ViewModel и по паттерну MVVM у меня нет доступа к таблице из ViewModel = (
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Перемещение позиции курсора таблицы при использовании JavaFX и MVVM
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]