Transactions 支持事务的JavaFXTableView

Transactions 支持事务的JavaFXTableView,transactions,javafx-2,jpa-2.0,tableview,observablelist,Transactions,Javafx 2,Jpa 2.0,Tableview,Observablelist,我确信有一个数据库支持的tableview是一种常见的编程范例(在我们的例子中,JPA2使用EclipseLink)。但事实证明,正确使用用户界面非常困难。我对现代UI设计没有太多经验,我确信这会让我错过一个显而易见的解决方案 我们的表应该允许用户插入、删除、进行更改,然后保存或放弃更改集。插入和更改需要验证。目前,我们通过提交更改来实现这一点,并在出现故障时回滚和重播数据库中的更改集(失败的更改除外),并保持UI不变,以便用户可以修复错误,而无需重新键入所有内容 我们的TableView由从J

我确信有一个数据库支持的tableview是一种常见的编程范例(在我们的例子中,JPA2使用EclipseLink)。但事实证明,正确使用用户界面非常困难。我对现代UI设计没有太多经验,我确信这会让我错过一个显而易见的解决方案

我们的表应该允许用户插入、删除、进行更改,然后保存或放弃更改集。插入和更改需要验证。目前,我们通过提交更改来实现这一点,并在出现故障时回滚和重播数据库中的更改集(失败的更改除外),并保持UI不变,以便用户可以修复错误,而无需重新键入所有内容

我们的TableView由从JPA来源获得的可观察数据列表支持。插入和删除非常简单。我们可以使用列表上的更改侦听器获取有关添加到列表或删除的内容的信息。然而,我还没有找到一种可靠的方法来检测对现有项目的更改

当前的设计是由其他人完成的,必须重新构建,这取决于TableRow焦点更改侦听器,但它非常不可靠。监视表更改、验证每个更改以及在更改无效时回滚数据库更改以及将可见更改重新应用到表中的常用方法是什么


一个现有的示例应用程序将非常出色,但我还没有找到任何支持事务的可用应用程序。除此之外,模型图将非常有用

从理论上讲,您可以通过使用。其思想是,对于TableView,您可以指定一个回调,该回调为列表中的每个对象提供一个观察值数组。当现有项对指定属性进行了更改时,列表将观察到这些可观察项,并且向列表中注册的任何ListChangeListeners发出通知(通过wasUpdate()返回true的更改)

然而,这似乎只适用于Java8;javafx2.2可能有一个bug

下面是一个基于常用TableView示例的示例

import java.util.Arrays;
import java.util.List;

import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class TableUpdatePropertyExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        final TableView<Person> table = new TableView<>();
        table.setEditable(true);
        final TableColumn<Person, String> firstNameCol = createTableColumn("First Name");
        final TableColumn<Person, String> lastNameCol = createTableColumn("Last Name");
        final TableColumn<Person, String> emailCol = createTableColumn("Email");
        table.getColumns().addAll(Arrays.asList(firstNameCol, lastNameCol, emailCol));
        final List<Person> data = Arrays.asList(
                new Person("Jacob", "Smith", "jacob.smith@example.com"),
                new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
                new Person("Ethan", "Williams", "ethan.williams@example.com"),
                new Person("Emma", "Jones", "emma.jones@example.com"),
                new Person("Michael", "Brown", "michael.brown@example.com")
        );
        table.setItems(FXCollections.observableList(data, new Callback<Person, Observable[]>() {
            @Override
            public Observable[] call(Person person) {
                return new Observable[] {person.firstNameProperty(), person.lastNameProperty(), person.emailProperty()};
            }
        }));

        table.getItems().addListener(new ListChangeListener<Person>() {
            @Override
            public void onChanged(
                    javafx.collections.ListChangeListener.Change<? extends Person> change) {
                while (change.next()) {
                    if (change.wasUpdated()) {
                        Person updatedPerson = table.getItems().get(change.getFrom());
                        System.out.println(updatedPerson+" was updated");
                    }
                }
            }
        });
        final BorderPane root = new BorderPane();
        root.setCenter(table);
        final Scene scene = new Scene(root, 600, 400);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    private TableColumn<Person, String> createTableColumn(String title) {
        TableColumn<Person, String> col = new TableColumn<>(title);
        col.setCellValueFactory(new PropertyValueFactory<Person, String>(makePropertyName(title)));
        col.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
        return col ;
    }

    private String makePropertyName(String text) {
        boolean first = true ;
        StringBuilder prop = new StringBuilder();
        for (String word : text.split("\\s")) {
            if (first) {
                prop.append(word.toLowerCase());
            } else {
                prop.append(Character.toUpperCase(word.charAt(0)));
                if (word.length() > 1) {
                    prop.append(word.substring(1));
                }
            }
            first=false ;
        }
        return prop.toString();
    }

    public static class Person {
        private final StringProperty firstName ;
        private final StringProperty lastName ;
        private final StringProperty email ;
        public Person(String firstName, String lastName, String email) {
            this.firstName = new SimpleStringProperty(this, "firstName", firstName);
            this.lastName = new SimpleStringProperty(this, "lastName", lastName);
            this.email = new SimpleStringProperty(this, "email", email);
        }
        public String getFirstName() {
            return firstName.get();
        }
        public void setFirstName(String firstName) {
            this.firstName.set(firstName);
        }
        public StringProperty firstNameProperty() {
            return firstName ;
        }
        public String getLastName() {
            return lastName.get();
        }
        public void setLastName(String lastName) {
            this.lastName.set(lastName);
        }
        public StringProperty lastNameProperty() {
            return lastName ;
        }
        public String getEmail() {
            return email.get();
        }
        public void setEmail(String email) {
            this.email.set(email);
        }
        public StringProperty emailProperty() {
            return email ;
        }
        @Override
        public String toString() {
            return getFirstName() + " " + getLastName();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
代替上面的Person类中的一个班轮

更新: 为了在JavaFX2.2中实现这一点,您基本上可以推出自己版本的“提取器”。这是一点工作,但还不算太糟。例如,类似于以下的方法似乎有效:

final List<Person> data = Arrays.asList(
            new Person("Jacob", "Smith", "jacob.smith@example.com"),
            new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
            new Person("Ethan", "Williams", "ethan.williams@example.com"),
            new Person("Emma", "Jones", "emma.jones@example.com"),
            new Person("Michael", "Brown", "michael.brown@example.com")
    );

    final ChangeListener<String> firstNameListener = new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> obs,
                String oldFirstName, String newFirstName) {
            Person person = (Person)((StringProperty)obs).getBean();
            System.out.println("First name for "+person+" changed from "+oldFirstName+" to "+newFirstName);
        }
    };

    final ChangeListener<String> lastNameListener = new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> obs,
                String oldLastName, String newLastName) {
            Person person = (Person)((StringProperty)obs).getBean();
            System.out.println("Last name for "+person+" changed from "+oldLastName+" to "+oldLastName);
        }
    };

    final ChangeListener<String> emailListener = new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> obs,
                String oldEmail, String newEmail) {
            Person person = (Person)((StringProperty)obs).getBean();
            System.out.println("Email for "+person+" changed from "+oldEmail+" to "+oldEmail);
        }
    };

    table.getItems().addListener(new ListChangeListener<Person>() {
        @Override
        public void onChanged(
                javafx.collections.ListChangeListener.Change<? extends Person> change) {
            while (change.next()) {
                for (Person person : change.getAddedSubList()) {
                    person.firstNameProperty().addListener(
                            firstNameListener);
                    person.lastNameProperty().addListener(lastNameListener);
                    person.emailProperty().addListener(emailListener);
                }
                for (Person person : change.getRemoved()) {
                    person.firstNameProperty().removeListener(
                            firstNameListener);
                    person.lastNameProperty().removeListener(
                            lastNameListener);
                    person.emailProperty().removeListener(emailListener);
                }
            }
        }
    });

    table.getItems().addAll(data);
final List data=Arrays.asList(
新人(“雅各布”、“史密斯”、“雅各布”。smith@example.com"),
新人(“伊莎贝拉”、“约翰逊”、“伊莎贝拉”。johnson@example.com"),
新人(“伊桑”、“威廉姆斯”、“伊桑”。williams@example.com"),
新人(“艾玛”、“琼斯”、“艾玛”。jones@example.com"),
新人(“迈克尔”、“布朗”、“迈克尔”。brown@example.com")
);
final ChangeListener firstNameListener=新的ChangeListener(){
@凌驾

public void changed(observevalue您应该检查Granite Data Services,它是一个在JavaFX中集成了JPA功能的框架:

它可以处理延迟加载、实体冲突、JavaFX端的EJB缓存、bean验证、多个客户端上的数据同步

您应该查看github上的示例,我认为这是一个很好的开始:


这有点复杂,但JPA管理确实很复杂。我在Flex项目中使用Granite已有多年,可能会与JavaFX一起使用,它已经可以投入生产了。

(顺便说一句,希望这会有所帮助,我可能已经错过了你问题的重点…)感谢您花时间修改示例以演示您所描述的内容。我曾尝试过类似的方法,但在我看来,JavaFX2.2中从未调用过onChanged方法。我不确定该方法的目的是什么。我在调试器中运行了此代码,但我看不到它达到了这一目的。Oracle文档非常有用帮助有限,因为它没有详细介绍这个函数。我们计划转移到JavaFX 8,但可能太晚了,无法在这个问题上提供帮助。我希望我在6个月前开始这个项目时就知道这个框架。它会让生活变得更简单。
final List<Person> data = Arrays.asList(
            new Person("Jacob", "Smith", "jacob.smith@example.com"),
            new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
            new Person("Ethan", "Williams", "ethan.williams@example.com"),
            new Person("Emma", "Jones", "emma.jones@example.com"),
            new Person("Michael", "Brown", "michael.brown@example.com")
    );

    final ChangeListener<String> firstNameListener = new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> obs,
                String oldFirstName, String newFirstName) {
            Person person = (Person)((StringProperty)obs).getBean();
            System.out.println("First name for "+person+" changed from "+oldFirstName+" to "+newFirstName);
        }
    };

    final ChangeListener<String> lastNameListener = new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> obs,
                String oldLastName, String newLastName) {
            Person person = (Person)((StringProperty)obs).getBean();
            System.out.println("Last name for "+person+" changed from "+oldLastName+" to "+oldLastName);
        }
    };

    final ChangeListener<String> emailListener = new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> obs,
                String oldEmail, String newEmail) {
            Person person = (Person)((StringProperty)obs).getBean();
            System.out.println("Email for "+person+" changed from "+oldEmail+" to "+oldEmail);
        }
    };

    table.getItems().addListener(new ListChangeListener<Person>() {
        @Override
        public void onChanged(
                javafx.collections.ListChangeListener.Change<? extends Person> change) {
            while (change.next()) {
                for (Person person : change.getAddedSubList()) {
                    person.firstNameProperty().addListener(
                            firstNameListener);
                    person.lastNameProperty().addListener(lastNameListener);
                    person.emailProperty().addListener(emailListener);
                }
                for (Person person : change.getRemoved()) {
                    person.firstNameProperty().removeListener(
                            firstNameListener);
                    person.lastNameProperty().removeListener(
                            lastNameListener);
                    person.emailProperty().removeListener(emailListener);
                }
            }
        }
    });

    table.getItems().addAll(data);