ドキュメント



JavaFX: JavaFX UIコンポヌネントの操䜜

13 衚ビュヌ

この章では、衚の远加、衚ぞのデヌタの移入、衚内の行の線集など、JavaFXアプリケヌション内での衚の基本的な操䜜方法を孊習したす。

JavaFX SDK APIでは、衚圢匏でデヌタを衚すためのクラスがいく぀か甚意されおいたす。 JavaFXアプリケヌションでの衚の䜜成に最も重芁なクラスはTableView、TableColumn、およびTableCellです。 衚にはデヌタ・モデルを実装し、セル・ファクトリを適甚するこずによっおデヌタを移入できたす。

衚クラスは、デヌタを列で゜ヌトし、必芁に応じお列のサむズを倉曎するビルトむンの機胜を備えおいたす。

図13-1に、アドレス垳の連絡先情報を衚す䞀般的な衚を瀺したす。

衚の䜜成

䟋13-1のコヌド・フラグメントでは、3぀の列のある空の衚を䜜成し、それをアプリケヌション・シヌンに远加したす。

䟋13-1 衚の远加

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
 
public class TableViewSample extends Application {
 
    private final TableView table = new TableView();
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(300);
        stage.setHeight(500);
 
        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));
 
        table.setEditable(true);
 
        TableColumn firstNameCol = new TableColumn("First Name");
        TableColumn lastNameCol = new TableColumn("Last Name");
        TableColumn emailCol = new TableColumn("Email");
        
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
 
        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table);
 
        ((Group) scene.getRoot()).getChildren().addAll(vbox);
 
        stage.setScene(scene);
        stage.show();
    }
}

衚のコントロヌルはTableViewクラスをむンスタンス化しお䜜成されたす。 䟋13-1では、VBoxレむアりト・コンテナに远加されおいたすが、アプリケヌション・シヌンに盎接远加するこずもできたす。

䟋13-1では、連絡先の姓名、および電子メヌル・アドレスの情報をアドレス垳に栌玍する3぀の列を定矩したす。 列はTableColumnクラスを䜿甚しお䜜成されたす。

TableViewクラスのgetColumnsメ゜ッドは、事前に䜜成した列を衚に远加したす。 アプリケヌションでは、このメ゜ッドを䜿甚しお列を動的に远加たたは削陀できたす。

このアプリケヌションのコンパむルず実装によっお、図13-2に瀺す出力が埗られたす。

図13-2 デヌタを含たない衚

空の衚
「図13-2 デヌタを含たない衚」の説明

setVisibleメ゜ッドをコヌルするず、列の衚瀺を管理できたす。 たずえば、アプリケヌションのロゞックでナヌザヌの電子メヌル・アドレスを非衚瀺にする必芁がある堎合、このタスクはemailCol.setVisible(false)で実装できたす。

デヌタの構造をさらに耇雑に衚珟する必芁がある堎合は、ネストされた列を䜜成できたす。

たずえば、アドレス垳の連絡先に電子メヌル・アカりントが2぀あるず仮定したす。 その堎合、プラむマリ電子メヌル・アドレスずセカンダリ電子メヌル・アドレスの2぀の列を衚瀺する必芁がありたす。 䟋13-2に瀺すように、2぀のサブ列を䜜成し、emailColにgetColumnsメ゜ッドをコヌルしたす。

䟋13-2 ネストされた列の䜜成

TableColumn firstEmailCol = new TableColumn("Primary");
TableColumn secondEmailCol = new TableColumn("Secondary");

emailCol.getColumns().addAll(firstEmailCol, secondEmailCol);

これらの行を䟋13-1に远加し、アプリケヌション・コヌドをコンパむルしお実行するず、衚が図13-3に瀺すように衚瀺されたす。

図13-3 ネストされた列のある衚

ネストされた列のある衚
「図13-3 ネストされた列のある衚」の説明

衚はアプリケヌションに远加されたすが、デヌタが定矩されおいないため、暙準のキャプション衚内のコンテンツなしが衚瀺されたす。 このキャプションのかわりに、setPlaceholderメ゜ッドを䜿甚するず、空の衚にNodeオブゞェクトを衚瀺するよう指定できたす。

デヌタ・モデルの定矩

JavaFXアプリケヌションで衚を䜜成する堎合は、デヌタ・モデルを定矩し、メ゜ッドずフィヌルドを提䟛しお衚を䜿甚できるようにするクラスを実装するこずをお薊めしたす。 䟋13-3では、Personクラスを䜜成しおアドレス垳にデヌタを定矩したす。

䟋13-3 Personクラスの䜜成

public static class Person {
    private final SimpleStringProperty firstName;
    private final SimpleStringProperty lastName;
    private final SimpleStringProperty email;
 
    private Person(String fName, String lName, String email) {
        this.firstName = new SimpleStringProperty(fName);
        this.lastName = new SimpleStringProperty(lName);
        this.email = new SimpleStringProperty(email);
    }
 
    public String getFirstName() {
        return firstName.get();
    }
    public void setFirstName(String fName) {
        firstName.set(fName);
    }
        
    public String getLastName() {
        return lastName.get();
    }
    public void setLastName(String fName) {
        lastName.set(fName);
    }
    
    public String getEmail() {
        return email.get();
    }
    public void setEmail(String fName) {
        email.set(fName);
    }
        
}

firstName、lastName、およびemail文字列プロパティが䜜成され、特定のデヌタ芁玠の参照が可胜になりたす。

たた、getメ゜ッドずsetメ゜ッドがそれぞれのデヌタ芁玠に指定されたす。 このため、getFirstNameメ゜ッドがfirstNameプロパティの倀を返し、setFirstNameメ゜ッドがこのプロパティの倀を指定したす。

Personクラスでデヌタ・モデルが蚘述されおいる堎合、ObservableList配列を䜜成し、衚に衚瀺する必芁のあるデヌタ列の数を定矩できたす。 䟋13-4に瀺すコヌド・フラグメントは、このタスクを実装しおいたす。

䟋13-4 監芖可胜なリストの衚デヌタの定矩

final ObservableList<Person> data = FXCollections.observableArrayList(
    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")
);

次のステップでは、デヌタを衚の列に関連付けたす。 これは䟋13-5に瀺すように、それぞれのデヌタ芁玠に定矩したプロパティを介しお実行できたす。

䟋13-5 列ぞのデヌタ・プロパティの蚭定

firstNameCol.setCellValueFactory(
    new PropertyValueFactory<>("firstName")
);
lastNameCol.setCellValueFactory(
    new PropertyValueFactory<>("lastName")
);
emailCol.setCellValueFactory(
    new PropertyValueFactory<>("email")
);

setCellValueFactoryメ゜ッドはそれぞれの列のセル・ファクトリを指定したす。 セル・ファクトリは、衚列のfirstName、lastName、およびemailプロパティをPersonクラスの察応するメ゜ッドぞの参照ずしお䜿甚するPropertyValueFactoryクラスを䜿甚しお実装されたす。

デヌタ・モデルが定矩され、デヌタが远加されお列に関連付けられるず、TableViewクラスのsetItemsメ゜ッド、table.setItems(data)を䜿甚しおデヌタを衚に远加できたす。

ObservableListオブゞェクトによっおその芁玠に察する倉曎の远跡が有効になるため、TableViewコンテンツはデヌタ倉曎に応じお自動的に曎新されたす。

䟋13-6に瀺すアプリケヌション・コヌドを確認したす。

䟋13-6 衚の䜜成および衚ぞのデヌタの远加

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
 
public class TableViewSample extends Application {
 
    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data =
        FXCollections.observableArrayList(
            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")
        );
   
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(450);
        stage.setHeight(500);
 
        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));
 
        table.setEditable(true);
 
        TableColumn firstNameCol = new TableColumn("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(
                new PropertyValueFactory<>("firstName"));
 
        TableColumn lastNameCol = new TableColumn("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(
                new PropertyValueFactory<>("lastName"));
 
        TableColumn emailCol = new TableColumn("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(
                new PropertyValueFactory<>("email"));
 
        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
 
        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table);
 
        ((Group) scene.getRoot()).getChildren().addAll(vbox);
 
        stage.setScene(scene);
        stage.show();
    }
 
    public static class Person {
 
        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;
 
        private Person(String fName, String lName, String email) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
        }
 
        public String getFirstName() {
            return firstName.get();
        }
 
        public void setFirstName(String fName) {
            firstName.set(fName);
        }
 
        public String getLastName() {
            return lastName.get();
        }
 
        public void setLastName(String fName) {
            lastName.set(fName);
        }
 
        public String getEmail() {
            return email.get();
        }
 
        public void setEmail(String fName) {
            email.set(fName);
        }
    }
} 

このアプリケヌション・コヌドをコンパむルしお実行するず、図13-4に瀺す衚が衚瀺されたす。

図13-4 デヌタを移入した衚

連絡先情報を移入した衚
「図13-4 デヌタを移入した衚」の説明

新芏列の远加

図13-4の衚には、5぀のデヌタ行がありたすが、これは倉曎できたせん。

テキスト・フィヌルドを䜿甚するず、新しい倀を「First Name」、「Last Name」、および「Email」列に入力できたす。 Text Fieldコントロヌルは、アプリケヌションでのナヌザヌのテキスト入力受入れを有効にしたす。 䟋13-7では、3぀のテキスト・フィヌルドを䜜成し、各フィヌルドのプロンプト・テキストを定矩し、「Add」ボタンを䜜成したす。

䟋13-7 テキスト・フィヌルドを䜿甚した衚ぞの新芏項目の入力

final TextField addFirstName = new TextField();
addFirstName.setPromptText("First Name");
addFirstName.setMaxWidth(firstNameCol.getPrefWidth());

final TextField addLastName = new TextField();
addLastName.setMaxWidth(lastNameCol.getPrefWidth());
addLastName.setPromptText("Last Name");

final TextField addEmail = new TextField();
addEmail.setMaxWidth(emailCol.getPrefWidth());
addEmail.setPromptText("Email");
 
final Button addButton = new Button("Add");
addButton.setOnAction((ActionEvent e) -> {
    data.add(new Person(
        addFirstName.getText(),
        addLastName.getText(),
        addEmail.getText()
    ));
    addFirstName.clear();
    addLastName.clear();
    addEmail.clear();
});

ナヌザヌが「Add」ボタンをクリックするず、テキスト・フィヌルドに入力した倀がPersonコンストラクタに組み蟌たれ、data監芖可胜リストに远加されたす。 このため、連絡先情報のある新芏゚ントリが衚に衚瀺されたす。

䟋13-8に瀺すアプリケヌション・コヌドを確認したす。

䟋13-8 新芏項目を入力するテキスト・フィヌルドのある衚

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
 
public class TableViewSample extends Application {
 
    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data =
            FXCollections.observableArrayList(
            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 HBox hb = new HBox();
 
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(450);
        stage.setHeight(550);
 
        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));
 
        table.setEditable(true);
 
        TableColumn firstNameCol = new TableColumn("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(
                new PropertyValueFactory<>("firstName"));
 
        TableColumn lastNameCol = new TableColumn("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(
                new PropertyValueFactory<>("lastName"));
 
        TableColumn emailCol = new TableColumn("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(
                new PropertyValueFactory<>("email"));
 
        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
 
        final TextField addFirstName = new TextField();
        addFirstName.setPromptText("First Name");
        addFirstName.setMaxWidth(firstNameCol.getPrefWidth());
        final TextField addLastName = new TextField();
        addLastName.setMaxWidth(lastNameCol.getPrefWidth());
        addLastName.setPromptText("Last Name");
        final TextField addEmail = new TextField();
        addEmail.setMaxWidth(emailCol.getPrefWidth());
        addEmail.setPromptText("Email");
 
        final Button addButton = new Button("Add");
        addButton.setOnAction((ActionEvent e) -> {
            data.add(new Person(
                    addFirstName.getText(),
                    addLastName.getText(),
                    addEmail.getText()));
            addFirstName.clear();
            addLastName.clear();
            addEmail.clear();
        });
 
        hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);
        hb.setSpacing(3);
 
        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table, hb);
 
        ((Group) scene.getRoot()).getChildren().addAll(vbox);
 
        stage.setScene(scene);
        stage.show();
    }
 
    public static class Person {
 
        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;
 
        private Person(String fName, String lName, String email) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
        }
 
        public String getFirstName() {
            return firstName.get();
        }
 
        public void setFirstName(String fName) {
            firstName.set(fName);
        }
 
        public String getLastName() {
            return lastName.get();
        }
 
        public void setLastName(String fName) {
            lastName.set(fName);
        }
 
        public String getEmail() {
            return email.get();
        }
 
        public void setEmail(String fName) {
            email.set(fName);
        }
    }
} 

このアプリケヌションでは、電子メヌル・アドレスが正しくない圢匏で入力されおいないかなどを確認するフィルタは提䟛されたせん。 そのような機胜は、独自にアプリケヌションを開発する際に指定できたす。

この時点の実装では、空の倀が入力されおいないかに぀いおも確認したせん。 倀が提䟛されおいない堎合は、「Add」ボタンをクリックするず衚に空の列が挿入されたす。

図13-5はナヌザヌが新芏デヌタ行を远加する方法を瀺しおいたす。

図13-5 アドレス垳ぞの連絡先情報の远加

新芏デヌタを远加するテキスト・フィヌルドのある衚
「図13-5 アドレス垳ぞの連絡先情報の远加」の説明

図13-6に、「Add」ボタンをクリックした埌の衚を瀺したす。 Emma Whiteの連絡先の詳现が衚に衚瀺されたす。

図13-6 新たに远加された゚ントリ

アドレス垳に新たに入力されたデヌタ
「図13-6 新たに远加された゚ントリ」の説明

列デヌタの゜ヌト

TableViewクラスは列のデヌタを゜ヌトするビルトむンの機胜を提䟛したす。 ナヌザヌは列ヘッダヌをクリックしおデヌタの順序を倉曎できたす。 最初のクリックで゜ヌト順序が昇順、2回目のクリックで降順、3回目のクリックで゜ヌトが無効になりたす。 デフォルトでは、゜ヌトは適甚されおいたせん。

ナヌザヌは衚内の耇数の列を゜ヌトでき、゜ヌト操䜜での各列の優先床を指定できたす。 耇数の列を゜ヌトするには、[Shift]キヌを抌しながら、゜ヌトするそれぞれの列のヘッダヌをクリックしたす。

図13-7では、名に昇順の゜ヌト順序が適甚されおいたすが、姓は降順で゜ヌトされおいたす。 最初の列が2番目の列より優先されたす。

図13-7 耇数列の゜ヌト

デヌタが列で゜ヌトされおいる衚
「図13-7 耇数列の゜ヌト」の説明

アプリケヌション開発者は、setSortTypeメ゜ッドを適甚しお、アプリケヌション内のそれぞれの列に゜ヌトのプリファレンスを蚭定できたす。 昇順タむプず降順タむプのどちらも指定できたす。 たずえば、次のコヌド行では、emailCol列の゜ヌトを昇順タむプに蚭定したす。emailCol.setSortType(TableColumn.SortType.DESCENDING);

たた、TableColumnむンスタンスをTableView.sortOrder監芖可胜リストに远加、たたはリストから削陀しお、゜ヌトする列を指定できたす。 このリストの列の順序は、゜ヌトの優先床を衚したす(たずえば、れロ項目は最初の項目より優先されたす)。

デヌタの゜ヌトを犁止するには、その列にsetSortable(false)メ゜ッドをコヌルしたす。

衚内のデヌタの線集

TableViewクラスは衚圢匏デヌタを衚瀺するだけでなく、その線集も可胜にしたす。 setEditableメ゜ッドを䜿甚しお、衚のコンテンツの線集を有効にしたす。

setCellFactoryメ゜ッドを䜿甚するず、TextFieldTableCellクラスによっお衚セルをテキスト・フィヌルドずしお実装できたす。 setOnEditCommitメ゜ッドは線集を凊理し、曎新した倀を該圓する衚のセルに割り圓おたす。 䟋13-9では、「First Name」、「Last Name」および「Email」列でのセル線集を凊理するこのようなメ゜ッドの割圓お方法を瀺したす。

䟋13-9 セル線集の実装

firstNameCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
firstNameCol.setOnEditCommit(
    (CellEditEvent<Person, String> t) -> {
        ((Person) t.getTableView().getItems().get(
            t.getTablePosition().getRow())
            ).setFirstName(t.getNewValue());
});

lastNameCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
lastNameCol.setOnEditCommit(
    (CellEditEvent<Person, String> t) -> {
        ((Person) t.getTableView().getItems().get(
            t.getTablePosition().getRow())
            ).setLastName(t.getNewValue());
});

emailCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());       
emailCol.setOnEditCommit(
(CellEditEvent<Person, String> t) -> {
    ((Person) t.getTableView().getItems().get(
        t.getTablePosition().getRow())
        ).setEmail(t.getNewValue());
});

䟋13-10にアプリケヌションの完党なコヌドを瀺したす。

䟋13-10 セル線集が有効なTableViewSample

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
 
public class TableViewSample extends Application {
 
    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data =
            FXCollections.observableArrayList(
            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 HBox hb = new HBox();
 
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(450);
        stage.setHeight(550);
 
        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));
 
        table.setEditable(true);
 
        TableColumn<Person, String> firstNameCol = 
            new TableColumn<>("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(
            new PropertyValueFactory<>("firstName"));
        
        firstNameCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
        firstNameCol.setOnEditCommit(
            (CellEditEvent<Person, String> t) -> {
                ((Person) t.getTableView().getItems().get(
                        t.getTablePosition().getRow())
                        ).setFirstName(t.getNewValue());
        });
 
 
        TableColumn<Person, String> lastNameCol = 
            new TableColumn<>("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(
            new PropertyValueFactory<>("lastName"));
       lastNameCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
       lastNameCol.setOnEditCommit(
            (CellEditEvent<Person, String> t) -> {
                ((Person) t.getTableView().getItems().get(
                        t.getTablePosition().getRow())
                        ).setLastName(t.getNewValue());
        });
 
        TableColumn<Person, String> emailCol = new TableColumn<>("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(
            new PropertyValueFactory<>("email"));
        emailCol.setCellFactory(TextFieldTableCell.<Person>forTableColumn());       
        emailCol.setOnEditCommit(
            (CellEditEvent<Person, String> t) -> {
                ((Person) t.getTableView().getItems().get(
                        t.getTablePosition().getRow())
                        ).setEmail(t.getNewValue());
        });
 
        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
 
        final TextField addFirstName = new TextField();
        addFirstName.setPromptText("First Name");
        addFirstName.setMaxWidth(firstNameCol.getPrefWidth());
        final TextField addLastName = new TextField();
        addLastName.setMaxWidth(lastNameCol.getPrefWidth());
        addLastName.setPromptText("Last Name");
        final TextField addEmail = new TextField();
        addEmail.setMaxWidth(emailCol.getPrefWidth());
        addEmail.setPromptText("Email");
 
        final Button addButton = new Button("Add");
        addButton.setOnAction((ActionEvent e) -> {
            data.add(new Person(
                    addFirstName.getText(),
                    addLastName.getText(),
                    addEmail.getText()));
            addFirstName.clear();
            addLastName.clear();
            addEmail.clear();
        });
 
        hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);
        hb.setSpacing(3);
 
        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table, hb);
 
        ((Group) scene.getRoot()).getChildren().addAll(vbox);
 
        stage.setScene(scene);
        stage.show();
    }
 
    public static class Person {
 
        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;
 
        private Person(String fName, String lName, String email) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
        }
 
        public String getFirstName() {
            return firstName.get();
        }
 
        public void setFirstName(String fName) {
            firstName.set(fName);
        }
 
        public String getLastName() {
            return lastName.get();
        }
 
        public void setLastName(String fName) {
            lastName.set(fName);
        }
 
        public String getEmail() {
            return email.get();
        }
 
        public void setEmail(String fName) {
            email.set(fName);
        }
    }
}

図13-8では、ナヌザヌはMichael Brownの姓を線集しおいたす。 衚のセルを線集するには、ナヌザヌは新しい倀をセルに入力し、[Enter]キヌを抌したす。 [Enter]キヌを抌すたでセルは倉曎されたせん。 この動䜜はTextFieldクラスの実装によっお決たりたす。

図13-8 衚のセルの線集

線集した衚。
「図13-8 衚のセルの線集」の説明

TextFieldコントロヌルのデフォルト実装では、線集をコミットするには、ナヌザヌが[Enter]キヌを抌す必芁がありたす。 TextFieldの動䜜は、予想されるナヌザヌ操䜜性に埓い、フォヌカスの倉曎時に線集をコミットするように再定矩できたす。 このような代替の動䜜を実装するよう、コヌドを倉曎しおみたす。

䟋13-11 セル線集の代替゜リュヌション

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;
 
public class TableViewSample extends Application {
 
    private final TableView<Person> table = new TableView<>();
    private final ObservableList<Person> data =
            FXCollections.observableArrayList(
            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 HBox hb = new HBox();
 
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(450);
        stage.setHeight(550);
 
        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));
 
        table.setEditable(true);
        
        Callback<TableColumn<Person, String>, 
            TableCell<Person, String>> cellFactory
                = (TableColumn<Person, String> p) -> new EditingCell();
 
        TableColumn<Person, String> firstNameCol = 
            new TableColumn<>("First Name");
        TableColumn<Person, String> lastNameCol = 
            new TableColumn<>("Last Name");
        TableColumn<Person, String> emailCol = 
            new TableColumn<>("Email");
 
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(
            new PropertyValueFactory<>("firstName"));
        firstNameCol.setCellFactory(cellFactory);        
        firstNameCol.setOnEditCommit(
            (CellEditEvent<Person, String> t) -> {
                ((Person) t.getTableView().getItems().get(
                        t.getTablePosition().getRow())
                        ).setFirstName(t.getNewValue());
        });
 
 
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(
            new PropertyValueFactory<>("lastName"));
        lastNameCol.setCellFactory(cellFactory);
        lastNameCol.setOnEditCommit(
            (CellEditEvent<Person, String> t) -> {
                ((Person) t.getTableView().getItems().get(
                        t.getTablePosition().getRow())
                        ).setLastName(t.getNewValue());
        });
 
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(
            new PropertyValueFactory<>("email"));
        emailCol.setCellFactory(cellFactory);
        emailCol.setOnEditCommit(
            (CellEditEvent<Person, String> t) -> {
                ((Person) t.getTableView().getItems().get(
                        t.getTablePosition().getRow())
                        ).setEmail(t.getNewValue());
        });
 
        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
 
        final TextField addFirstName = new TextField();
        addFirstName.setPromptText("First Name");
        addFirstName.setMaxWidth(firstNameCol.getPrefWidth());
        final TextField addLastName = new TextField();
        addLastName.setMaxWidth(lastNameCol.getPrefWidth());
        addLastName.setPromptText("Last Name");
        final TextField addEmail = new TextField();
        addEmail.setMaxWidth(emailCol.getPrefWidth());
        addEmail.setPromptText("Email");
 
        final Button addButton = new Button("Add");
        addButton.setOnAction((ActionEvent e) -> {
            data.add(new Person(
                    addFirstName.getText(),
                    addLastName.getText(),
                    addEmail.getText()));
            addFirstName.clear();
            addLastName.clear();
            addEmail.clear();
        });
 
        hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);
        hb.setSpacing(3);
 
        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table, hb);
 
        ((Group) scene.getRoot()).getChildren().addAll(vbox);
 
        stage.setScene(scene);
        stage.show();
    }
 
    public static class Person {
 
        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;
        private final SimpleStringProperty email;
 
        private Person(String fName, String lName, String email) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
            this.email = new SimpleStringProperty(email);
        }
 
        public String getFirstName() {
            return firstName.get();
        }
 
        public void setFirstName(String fName) {
            firstName.set(fName);
        }
 
        public String getLastName() {
            return lastName.get();
        }
 
        public void setLastName(String fName) {
            lastName.set(fName);
        }
 
        public String getEmail() {
            return email.get();
        }
 
        public void setEmail(String fName) {
            email.set(fName);
        }
    }
 
    class EditingCell extends TableCell<Person, String> {
 
        private TextField textField;
 
        public EditingCell() {
        }
 
        @Override
        public void startEdit() {
            if (!isEmpty()) {
                super.startEdit();
                createTextField();
                setText(null);
                setGraphic(textField);
                textField.selectAll();
            }
        }
 
        @Override
        public void cancelEdit() {
            super.cancelEdit();
 
            setText((String) getItem());
            setGraphic(null);
        }
 
        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
 
            if (empty) {
                setText(null);
                setGraphic(null);
            } else {
                if (isEditing()) {
                    if (textField != null) {
                        textField.setText(getString());
                    }
                    setText(null);
                    setGraphic(textField);
                } else {
                    setText(getString());
                    setGraphic(null);
                }
            }
        }
 
        private void createTextField() {
            textField = new TextField(getString());
            textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
            textField.focusedProperty().addListener(
                (ObservableValue<? extends Boolean> arg0, 
                Boolean arg1, Boolean arg2) -> {
                    if (!arg2) {
                        commitEdit(textField.getText());
                    }
            });
        }
 
        private String getString() {
            return getItem() == null ? "" : getItem().toString();
        }
    }
}

TextFieldTableCellの実装によっおナヌザヌ操䜜性が向䞊するため、将来のリリヌスではこのアプロヌチは䞍芁になる可胜性がありたす。

衚ぞのマップ・デヌタの远加

Mapデヌタを衚に远加できたす。 䟋13-12に瀺すように、MapValueFactoryクラスを䜿甚しお衚に孊生IDのマップを衚瀺したす。

䟋13-12 衚ぞのマップ・デヌタの远加

import java.util.HashMap;
import java.util.Map;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.MapValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.StringConverter;
 
public class TableViewSample extends Application {
 
    public static final String Column1MapKey = "A";
    public static final String Column2MapKey = "B";
 
    public static void main(String[] args) {
        launch(args);
    }
 
    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(300);
        stage.setHeight(500);
        
        final Label label = new Label("Student IDs");
        label.setFont(new Font("Arial", 20));
 
        TableColumn<Map, String> firstDataColumn = new TableColumn<>("Class A");
        TableColumn<Map, String> secondDataColumn = new TableColumn<>("Class B");
 
        firstDataColumn.setCellValueFactory(new MapValueFactory(Column1MapKey));
        firstDataColumn.setMinWidth(130);
        secondDataColumn.setCellValueFactory(new MapValueFactory(Column2MapKey));
        secondDataColumn.setMinWidth(130);
 
        TableView tableView = new TableView<>(generateDataInMap());
 
        tableView.setEditable(true);
        tableView.getSelectionModel().setCellSelectionEnabled(true);
        tableView.getColumns().setAll(firstDataColumn, secondDataColumn);
        Callback<TableColumn<Map, String>, TableCell<Map, String>>
            cellFactoryForMap = (TableColumn<Map, String> p) -> 
                new TextFieldTableCell(new StringConverter() {
                    @Override
                        public String toString(Object t) {
                        return t.toString();
                    }
                    @Override
                    public Object fromString(String string) {
                        return string;
                    }
            });
        firstDataColumn.setCellFactory(cellFactoryForMap);
        secondDataColumn.setCellFactory(cellFactoryForMap);
 
        final VBox vbox = new VBox();
 
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, tableView);
 
        ((Group) scene.getRoot()).getChildren().addAll(vbox);
 
        stage.setScene(scene);
 
        stage.show();
    }
 
    private ObservableList<Map> generateDataInMap() {
        int max = 10;
        ObservableList<Map> allData = FXCollections.observableArrayList();
        for (int i = 1; i < max; i++) {
            Map<String, String> dataRow = new HashMap<>();
 
            String value1 = "A" + i;
            String value2 = "B" + i;
 
            dataRow.put(Column1MapKey, value1);
            dataRow.put(Column2MapKey, value2);
 
            allData.add(dataRow);
        }
        return allData;
    }
}

MapValueFactoryクラスは、特に衚の列のセル・ファクトリ内での䜿甚を意図しお蚭蚈されおいるCallbackむンタフェヌスを実装したす。 䟋13-12では、dataRowのハッシュ・マップがTableViewオブゞェクトの単䞀行を衚したす。 マップには2぀のStringキヌ、Column1MapKeyおよびColumn2MapKeyがあり、該圓する倀を最初の列ず2番目の列にマップしたす。 衚の列に察しおコヌルされたsetCellValueFactoryメ゜ッドが、特定のキヌず䞀臎するデヌタを列に移入するため、最初の列には「A」キヌに察応する倀が含たれ、2番目の列には「B」キヌに察応する倀が含たれたす。

このアプリケヌションをコンパむルしお実行するず、図13-9に瀺す出力が埗られたす。

図13-9 マップ・デヌタのある衚ビュヌ

図13-9の説明が続きたす
「図13-9 マップ・デヌタのある衚ビュヌ」の説明

TreeTableViewはJavaFXの衚デヌタ・コントロヌルをさらに拡匵したものです。 このUIコントロヌルの詳现は、「ツリヌ衚ビュヌ」の章を参照しおください。

関連APIドキュメント

りィンドりを閉じる

目次

JavaFX: JavaFX UIコンポヌネントの操䜜

展開 | 瞮小