Java8 JavaFX でプログラムを作成しています。
TableViewで列の設定は編集不可にしている状態で
特定のセルのみ編集可能にする方法はありますでしょうか?
ご存知の方いらっしゃいましたら、ご教授お願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
Cellクラスにはずばりその目的のためのeditableプロパティーがありますのでそれが使えます。ただし、例えば**TextFieldTableCellなどを用いる場合はTableViewおよびTableColumnは編集可能でなければならない(※)**ため、TableColumnを編集不可にしたままでは実現できません。
さて、例えば「先頭行だけ編集可能にしたい」といった場合なら、バインディングを用いて次のように書けます。
java
1@FXML TableColumn<TableModel, String> nameColumn; 2 3... 4 5public void initialize(URL location, ResourceBundle resources) { 6 ... 7 nameColumn.setCellValueFactory(new PropertyValueFactory("name")); 8 nameColumn.setCellFactory(column -> new TextFieldTableCell() { 9 { // instance initialization block 10 editableProperty().bind(indexProperty().isEqualTo(0)); 11 } 12 }); 13 ... 14}
蛇足ながら・・・
Cellとモデルインスタンス(のプロパティ)の対応関係はTableViewの表示状態によって自動的に(勝手に)変更されてしまう点に注意してください。つまりCell生成時にeditableプロパティーへ固定値を設定してもダメで、依存関係にあるプロパティーの状態を監視し常に適切な値となるようにしなければなりません。それにはaddListenerも使えますが、バインディングの方がより確実に表現できます。
※: セルが編集可能とは?
TextFieldTableCell#startEditのAPIリファレンスには以下のようにしか書かれてません。
この関数を呼び出して、セルが編集可能な場合に、非編集状態から編集状態に遷移します。
実際はstartEditで「TableView、TableColumn、Cellが全て編集可能か」をチェックしているので、そのとおりに記述しておいてくれればいいのに・・・と自分などは思いますが、「3つのeditableプロパティーのAND条件である点ははっきり書いてないけど汲み取ってください」ということなのかも知れません・・・
追記:
あるモデルインスタンスの他のプロパティーの値によってeditableを制御する実装を考えてみました。
元の回答に書いたように、セルはいつどのモデルインスタンスに割り当てられるかが予測できませんので、考えられる状態変化を全て監視せねばなりません。
そのような煩雑な処理をアプリケーションの論理から分離したいので、「セルに対するモデルインスタンスのプロパティーの値を得るユーティリティー」を別途定義し、それを使った「"locked"プロパティーがfalseの場合にeditableがtrueとなるようなTextEditTableCell」の例をあげてみます。
java
1@FXML TableColumn<TableModel, String> nameColumn; 2 3... 4 5public void initialize(URL location, ResourceBundle resources) { 6 ... 7 colName.setCellFactory(col -> new TextFieldTableCell<>() { 8 { // instance initialization block 9 // ユーティリティーにより、lockedプロパティーと同じ値を持つ式を生成する 10 ObjectExpression<Boolean> cloneOfLocked = 11 TableModelPropertyFactory.forTableCell(this, model -> model.lockedProperty(), false); 12 // 上の式を使ってeditableプロパティーがlockedの逆になるようバインドする 13 editableProperty().bind(cloneOfLocked.isNotEqualTo(true)); 14 } 15 }); 16 ... 17}```
以下がユーティリティーです。とりあえず作ってみたというレベルなので、実装方法の考え方のヒントと考えていただければと思います。
java
1import javafx.beans.binding.ObjectExpression; 2import javafx.beans.property.ReadOnlyProperty; 3import javafx.beans.property.SimpleObjectProperty; 4import javafx.beans.value.ChangeListener; 5import javafx.collections.ListChangeListener; 6import javafx.collections.ObservableList; 7import javafx.scene.control.TableCell; 8import javafx.scene.control.TableView; 9import javafx.util.Callback; 10 11import java.util.Objects; 12 13/** 14 * TableViewのモデルのプロパティーの値を参照するためのファクトリー 15 */ 16public class TableModelPropertyFactory { 17 /** 18 * 特定のTableCellに対応するモデルインスタンスの特定のプロパティーの値を表す式を得る 19 * @param cell 結果のObjectExpressionを参照するTableCell 20 * @param mapper バインドするプロパティーを求める関数 21 * @param defaultValue バインドするプロパティーがない場合のデフォルト値 22 * @param <S> TableViewのモデルの型 23 * @param <U> バインド元のモデルプロパティーの値の型 24 * @return cellに対応したモデルインスタンスの指定プロパティーの値 25 */ 26 public static <S, U> ObjectExpression<U> forTableCell(TableCell<S, ?> cell, Callback<S, ReadOnlyProperty<U>> mapper, U defaultValue) { 27 return new PropertyExpression<S, U>(cell, mapper, defaultValue); 28 } 29 30 private static class PropertyExpression<S, U> extends SimpleObjectProperty<U> { 31 private final ChangeListener<?> cl = (observable, oldValue, newValue) -> refreshBinding(); 32 private final ListChangeListener<S> lcl = c -> refreshBinding(); 33 private final TableCell<S, ?> cell; 34 private final Callback<S, ReadOnlyProperty<U>> mapper; 35 private final U defaultValue; 36 37 private PropertyExpression(TableCell<S, ?> cell, Callback<S, ReadOnlyProperty<U>> mapper, U defaultValue) { 38 super(); 39 this.cell = Objects.requireNonNull(cell); 40 this.mapper = Objects.requireNonNull(mapper); 41 this.defaultValue = defaultValue; 42 // 初期バインド 43 refreshBinding(); 44 // TableViewのモデルの順番が入れ替わった際にバインドしなおす 45 TableView<S> tableView = cell.getTableView(); 46 if (tableView != null) 47 initForTableView(tableView); 48 cell.tableViewProperty().addListener((observable, oldTable, newTable) -> { 49 assert oldTable == null && newTable != null; 50 initForTableView(newTable); 51 }); 52 53 // cellのindexが変化したらバインドしなおす 54 cell.indexProperty().addListener((observable, oldIndex, newIndex) -> refreshBinding()); 55 } 56 57 private void initForTableView(TableView<S> tableView) { 58 ObservableList<S> items = tableView.getItems(); 59 if (items != null) 60 items.addListener(lcl); 61 // テーブルのitemsプロパティーの値(=ObservableList)が入れ替わったら 62 // リスナーを再設定する 63 tableView.itemsProperty().addListener((observable, oldList, newList) -> { 64 if (oldList != null) 65 oldList.removeListener(lcl); 66 if (newList != null) 67 newList.addListener(lcl); 68 }); 69 } 70 71 private void refreshBinding() { 72 unbind(); 73 TableView<S> tableView = cell.getTableView(); 74 if (tableView == null) 75 return; 76 ObservableList<S> items = tableView.getItems(); 77 if (items == null) 78 return; 79 int index = cell.getIndex(); 80 if (index < 0 || index >= items.size()) { 81 // 表示中のモデルインスタンスなし 82 set(defaultValue); 83 } else { 84 bind(mapper.call(items.get(index))); 85 } 86 } 87 } 88}
投稿2017/10/09 21:34
編集2017/10/10 13:07総合スコア18392
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/10/10 07:23
2017/10/10 07:26
2017/10/10 08:08
2017/10/10 08:14
2017/10/10 09:12
2017/10/10 09:24
2017/10/10 13:12
2017/10/10 14:13