回答編集履歴

1

見直しキャンペーン中

2023/07/26 15:55

投稿

TN8001
TN8001

スコア9326

test CHANGED
@@ -1,413 +1,208 @@
1
1
  [JavaFX - JavaFXのTableColumnに中身を追加したい|teratail](https://teratail.com/questions/331339)
2
-
3
2
  過去質問で解決したはずの部分まで壊れているのはなんででしょうか?
4
-
5
3
  試行錯誤は大変結構ですが、手あたり次第に勘で書き換えてもうまくいきません。
6
-
7
4
  `TableView`はもともと難しいので、1行1行どういう意味かザックリでも理解しながらやってください。
8
5
 
9
-
10
-
11
6
  まず[TableColumn<S,T>](https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/control/TableColumn.html)の型引数が逆です。
12
-
13
7
  そのため`ScheduleDataCell`も逆になってしまい、ヌルポがでます。
14
8
 
15
-
16
-
17
9
  `setCellValueFactory`があったはずですが、丸々抜けています。
18
-
19
10
  通常は表示するプロパティを指定するわけですが、セルにまとめて表示したいわけですね?
20
-
21
11
  単に改行したいだけなら各プロパティを`concat`するのが簡単です。
22
12
 
23
-
24
-
25
13
  あくまで`ScheduleDataCell`を利用したいなら、アイテム自身(`ScheduleData`)をセルに渡す必要がありますが、[ObservableValue<T>](https://docs.oracle.com/javase/jp/8/javafx/api/javafx/beans/value/ObservableValue.html)でなければなりません。
26
-
27
14
  [TableColumn#setCellValueFactory](https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/control/TableColumn.html#setCellValueFactory-javafx.util.Callback-)
28
15
 
29
-
30
-
31
16
  単純に[ReadOnlyObjectWrapper<T>](https://docs.oracle.com/javase/jp/8/javafx/api/javafx/beans/property/ReadOnlyObjectWrapper.html)で包んでみたところ、編集が即時反映されませんでした(まあ当然か)
32
17
 
33
-
34
-
35
18
  ちょっと正しいか自信はないのですが、`ScheduleData`を`ObjectBinding`にして内部のプロパティとバインドしたところ想定した動作になりました。
36
19
 
37
-
38
-
39
- ```fxml
20
+ ```xml
40
-
41
21
  <?xml version="1.0" encoding="UTF-8"?>
42
22
 
43
-
44
-
45
23
  <?import javafx.scene.control.TableColumn?>
46
-
47
24
  <?import javafx.scene.control.TableView?>
48
-
49
25
  <?import javafx.scene.layout.BorderPane?>
50
-
51
26
  <BorderPane xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
52
-
53
27
  fx:controller="sample.ScheduleTableController">
54
-
55
28
  <center>
56
-
57
29
  <TableView fx:id="table" editable="true">
58
-
59
30
  <columns>
60
-
61
31
  <TableColumn fx:id="scheduleColumn" prefWidth="100" text="schedule"/>
62
-
63
32
  <TableColumn fx:id="concatColumn" prefWidth="100" text="concat"/>
64
-
65
33
  <TableColumn fx:id="titleColumn" prefWidth="100" text="title"/>
66
-
67
34
  <TableColumn fx:id="timeColumn" prefWidth="100" text="time"/>
68
-
69
35
  <TableColumn fx:id="detailColumn" prefWidth="100" text="detail"/>
70
-
71
36
  </columns>
72
-
73
37
  </TableView>
74
-
75
38
  </center>
76
-
77
39
  </BorderPane>
78
-
79
- ```
40
+ ```
80
-
81
-
82
41
 
83
42
  ```Java
84
-
85
43
  package sample;
86
44
 
87
-
88
-
89
45
  import java.net.URL;
90
-
91
46
  import java.time.LocalTime;
92
-
93
47
  import java.util.ResourceBundle;
94
48
 
95
-
96
-
97
49
  import javafx.beans.property.ReadOnlyObjectWrapper;
98
-
99
50
  import javafx.collections.FXCollections;
100
-
101
51
  import javafx.collections.ObservableList;
102
-
103
52
  import javafx.fxml.FXML;
104
-
105
53
  import javafx.fxml.Initializable;
106
-
107
54
  import javafx.scene.control.TableCell;
108
-
109
55
  import javafx.scene.control.TableColumn;
110
-
111
56
  import javafx.scene.control.TableView;
112
-
113
57
  import javafx.scene.control.cell.PropertyValueFactory;
114
-
115
58
  import javafx.scene.control.cell.TextFieldTableCell;
116
-
117
59
  import javafx.scene.layout.VBox;
118
-
119
60
  import javafx.scene.text.Text;
120
61
 
121
62
 
122
-
123
-
124
-
125
63
  public class ScheduleTableController implements Initializable {
126
-
127
- @FXML
64
+ @FXML
128
-
129
65
  private TableView<ScheduleData> table;
130
-
131
- @FXML
66
+ @FXML
132
-
133
67
  private TableColumn<ScheduleData, ScheduleData> scheduleColumn; // アイテム自身をセルに出すため<ScheduleData, ScheduleData>になる
134
-
135
- @FXML
68
+ @FXML
136
-
137
69
  private TableColumn<ScheduleData, String> concatColumn; // 通常はアイテムの型(TableView<T>のT), プロパティの型(StringPropertyならString)
138
-
139
- @FXML
70
+ @FXML
140
-
141
71
  private TableColumn<ScheduleData, String> titleColumn;
142
-
143
- @FXML
72
+ @FXML
144
-
145
73
  private TableColumn<ScheduleData, String> timeColumn;
146
-
147
- @FXML
74
+ @FXML
148
-
149
75
  private TableColumn<ScheduleData, String> detailColumn;
150
76
 
151
-
152
-
153
77
  @Override public void initialize(URL location, ResourceBundle resources) {
154
-
155
78
  // ScheduleDataがObjectBindingでなくとも、Wrapperでコード上は通る
156
-
157
79
  // が、編集した時の挙動が異なる
158
-
159
80
  // 即時反映されずセルのクリックでupdateItemが走る模様
160
-
161
81
  // scheduleColumn.setCellValueFactory(x -> new ReadOnlyObjectWrapper<>(x.getValue()));
162
82
 
163
-
164
-
165
83
  // これでいいのか自信はないが、とりあえず想定通りに動いている
166
-
167
84
  scheduleColumn.setCellValueFactory(x -> x.getValue());
168
-
169
85
  scheduleColumn.setCellFactory(x -> new ScheduleDataCell());
170
86
 
171
87
 
172
-
173
-
174
-
175
88
  // 単にまとめたいだけならつなげればいい
176
-
177
89
  concatColumn.setCellValueFactory(x ->
178
-
179
90
  x.getValue().titleProperty()
180
-
181
91
  .concat("\n")
182
-
183
92
  .concat(x.getValue().timeProperty())
184
-
185
93
  .concat("\n")
186
-
187
94
  .concat(x.getValue().detailProperty()));
188
95
 
189
96
 
190
-
191
-
192
-
193
97
  // titleColumn.setCellValueFactory(new PropertyValueFactory<>("title")); // ↓同じ意味
194
-
195
98
  titleColumn.setCellValueFactory(x -> x.getValue().titleProperty());
196
-
197
99
  titleColumn.setCellFactory(TextFieldTableCell.forTableColumn());
198
100
 
199
-
200
-
201
101
  timeColumn.setCellValueFactory(x -> x.getValue().timeProperty());
202
-
203
102
  timeColumn.setCellFactory(TextFieldTableCell.forTableColumn());
204
103
 
205
-
206
-
207
104
  detailColumn.setCellValueFactory(x -> x.getValue().detailProperty());
208
-
209
105
  detailColumn.setCellFactory(TextFieldTableCell.forTableColumn());
210
106
 
211
-
212
-
213
107
  ObservableList<ScheduleData> schedules = FXCollections.observableArrayList(
214
-
215
108
  new ScheduleData("部活", LocalTime.of(12, 30), LocalTime.of(16, 0), "試合"),
216
-
217
109
  new ScheduleData("部活", LocalTime.of(12, 30), LocalTime.of(16, 0), "試合"));
218
-
219
110
  table.setItems(schedules);
220
-
221
- }
111
+ }
222
-
223
- }
112
+ }
224
-
225
-
226
113
 
227
114
  class ScheduleDataCell extends TableCell<ScheduleData, ScheduleData> {
228
-
229
115
  private VBox cellContainer = new VBox();
230
-
231
116
  private Text scheduleTitle = new Text();
232
-
233
117
  private Text time = new Text();
234
-
235
118
  private Text txtDetail = new Text();
236
119
 
237
-
238
-
239
120
  public ScheduleDataCell() {
240
-
241
121
  cellContainer.getChildren().addAll(scheduleTitle, time, txtDetail);
242
-
243
- }
122
+ }
244
-
245
-
246
123
 
247
124
  @Override protected void updateItem(ScheduleData item, boolean empty) {
248
-
249
125
  super.updateItem(item, empty);
250
126
 
251
-
252
-
253
127
  if (!empty) {
254
-
255
128
  scheduleTitle.setText(item.titleProperty().get());
256
-
257
129
  time.setText(item.timeProperty().get());
258
-
259
130
  txtDetail.setText(item.detailProperty().get());
260
131
 
261
-
262
-
263
132
  // これでもよさそうな気もするが、いつunbindすればいいかよくわからない
264
-
265
133
  // scheduleTitle.textProperty().bind(item.titleProperty());
266
-
267
134
  // time.textProperty().bind(item.timeProperty());
268
-
269
135
  // txtDetail.textProperty().bind(item.detailProperty());
270
136
 
271
-
272
-
273
137
  setGraphic(cellContainer);
274
-
275
138
  }
276
-
277
- }
139
+ }
278
-
279
- }
140
+ }
280
-
281
- ```
141
+ ```
282
-
283
-
284
142
 
285
143
  ```Java
286
-
287
144
  package sample;
288
145
 
289
-
290
-
291
146
  import java.time.LocalTime;
292
147
 
293
-
294
-
295
148
  import javafx.beans.binding.ObjectBinding;
296
-
297
149
  import javafx.beans.property.SimpleStringProperty;
298
-
299
150
  import javafx.beans.property.StringProperty;
300
151
 
301
152
 
302
-
303
-
304
-
305
153
  public class ScheduleData extends ObjectBinding<ScheduleData> {
306
-
307
154
  private StringProperty title = new SimpleStringProperty();
308
-
309
155
  private StringProperty time = new SimpleStringProperty();
310
-
311
156
  private StringProperty detail = new SimpleStringProperty();
312
157
 
313
-
314
-
315
158
  public ScheduleData(String title, LocalTime startTime, LocalTime finishTime, String detail) {
316
-
317
159
  this.title.set(title);
318
-
319
160
  time.set(startTime + "~" + finishTime);
320
-
321
161
  this.detail.set(detail);
322
162
 
323
-
324
-
325
163
  bind(this.title, time, this.detail);
326
-
327
- }
164
+ }
328
-
329
-
330
165
 
331
166
  public StringProperty titleProperty() { return title; }
332
167
 
333
-
334
-
335
168
  public StringProperty timeProperty() { return time; }
336
169
 
337
-
338
-
339
170
  public StringProperty detailProperty() { return detail; }
340
171
 
341
-
342
-
343
172
  @Override protected ScheduleData computeValue() { return this; }
344
-
345
- }
173
+ }
346
-
347
- ```
174
+ ```
348
-
349
-
350
175
 
351
176
  ```Java
352
-
353
177
  package sample;
354
178
 
355
-
356
-
357
179
  import javafx.application.Application;
358
-
359
180
  import javafx.fxml.FXMLLoader;
360
-
361
181
  import javafx.scene.Parent;
362
-
363
182
  import javafx.scene.Scene;
364
-
365
183
  import javafx.stage.Stage;
366
184
 
367
185
 
368
-
369
-
370
-
371
186
  public class Main extends Application {
372
-
373
187
  public static void main(String[] args) { launch(args); }
374
188
 
375
-
376
-
377
189
  @Override public void start(Stage primaryStage) throws Exception {
378
-
379
190
  Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
380
-
381
191
  primaryStage.setScene(new Scene(root, 600, 300));
382
-
383
192
  primaryStage.show();
384
-
385
- }
193
+ }
386
-
387
- }
194
+ }
388
-
389
- ```
195
+ ```
390
-
391
-
392
196
 
393
197
  ---
394
198
 
395
-
396
-
397
199
  そもそも`TableView`は表形式で編集するのに便利なコンポーネントだと思うのですが、まとめて表示の意味は何なのでしょう?
398
200
 
399
-
400
-
401
201
  ---
402
202
 
403
-
404
-
405
203
  [Java - TableViewにデータを追加したい|teratail](https://teratail.com/questions/332466)
406
-
407
204
  と全く同じ質問ですよね?
408
205
 
409
206
  [推奨していない質問|teratail(テラテイル)](https://teratail.com/help/avoid-asking)
410
207
 
411
-
412
-
413
208
  省略された部分が多く試す気が起きずにスルーしてしまいましたが、省略すべきはなくても動く部分(自動生成されたコメントや`initStyle()`等)であって、`initComponent()`や`fxml`等なくては動かない部分はできる限り記載してください。