回答編集履歴
7
コード変更
test
CHANGED
@@ -10,15 +10,11 @@
|
|
10
10
|
グループ化・ソートをオリジナル(?)に合わせる為に、 Duration・Book クラスを作って name を参照できるようにしました。
|
11
11
|
その為、全列にレンダラ・エディタが必要になりました・・・。
|
12
12
|
|
13
|
+
大きくなってきたので Row クラスを別ファイルとしました。
|
14
|
+
Insert キー / Delete キーで 行の追加・削除をしてみました。
|
15
|
+
|
13
16
|
RowGroupInTableTest2.java
|
14
17
|
```java
|
15
|
-
import java.awt.Component;
|
16
|
-
import java.awt.EventQueue;
|
17
|
-
import java.util.*;
|
18
|
-
|
19
|
-
import javax.swing.*;
|
20
|
-
import javax.swing.table.*;
|
21
|
-
|
22
18
|
public class RowGroupInTableTest2 extends JFrame {
|
23
19
|
public static void main(String[] args) {
|
24
20
|
EventQueue.invokeLater(() -> new RowGroupInTableTest2().setVisible(true));
|
@@ -42,204 +38,277 @@
|
|
42
38
|
|
43
39
|
JTable table = new JTable(model);
|
44
40
|
table.setFillsViewportHeight(true);
|
45
|
-
table.setDefaultRenderer(
|
41
|
+
table.setDefaultRenderer(Row.Name.class, new Row.NameRenderer());
|
46
|
-
table.setDefaultEditor(
|
42
|
+
table.setDefaultEditor(Row.Name.class, new DefaultCellEditor(new JTextField()));
|
47
|
-
table.setDefaultRenderer(
|
43
|
+
table.setDefaultRenderer(Row.Duration.class, new Row.DurationRenderer());
|
48
|
-
table.setDefaultEditor(
|
44
|
+
table.setDefaultEditor(Row.Duration.class, new Row.DurationEditor());
|
49
|
-
table.setDefaultRenderer(
|
45
|
+
table.setDefaultRenderer(Row.Book.class, new Row.BookRenderer());
|
50
|
-
table.setDefaultEditor(
|
46
|
+
table.setDefaultEditor(Row.Book.class, new Row.BookEditor());
|
51
|
-
|
47
|
+
|
52
48
|
table.setRowSorter(new TableRowSorter<TableModel>(model));
|
53
49
|
|
50
|
+
setAction(table, KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0), new AddAction());
|
51
|
+
setAction(table, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), new DeleteAction());
|
52
|
+
|
54
53
|
getContentPane().add(new JScrollPane(table));
|
55
54
|
}
|
56
55
|
|
57
|
-
static class MyData {
|
58
|
-
final String name;
|
59
|
-
final int duration;
|
60
|
-
final String book;
|
61
|
-
|
62
|
-
|
56
|
+
private static void setAction(JTable table, KeyStroke key, Action a) {
|
63
|
-
this.name = name;
|
64
|
-
|
57
|
+
table.getActionMap().put(a, a);
|
58
|
+
|
59
|
+
InputMap im;
|
60
|
+
im = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
65
|
-
|
61
|
+
im.put(key, a);
|
62
|
+
im = table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
|
63
|
+
im.put(key, a);
|
66
|
-
|
64
|
+
}
|
65
|
+
|
66
|
+
static class AddAction extends AbstractAction {
|
67
|
+
public AddAction() {
|
68
|
+
super("table-row-add");
|
67
|
-
}
|
69
|
+
}
|
70
|
+
|
68
|
-
|
71
|
+
@Override
|
72
|
+
public void actionPerformed(ActionEvent e) {
|
73
|
+
JTable table = (JTable)e.getSource();
|
74
|
+
MyTableModel model = (MyTableModel)table.getModel();
|
75
|
+
model.insert(table.getRowCount(), new MyData("", 0, ""));
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
69
|
-
|
79
|
+
public class DeleteAction extends AbstractAction {
|
70
|
-
private static final String[] titles = new String[] {"Name", "Last job duration", "Book #"};
|
71
|
-
|
72
|
-
|
80
|
+
public DeleteAction() {
|
73
|
-
final String name;
|
74
|
-
|
81
|
+
super("table-row-del");
|
82
|
+
}
|
83
|
+
|
75
|
-
|
84
|
+
@Override
|
76
|
-
Row(MyData mydata) {
|
77
|
-
|
85
|
+
public void actionPerformed(ActionEvent e) {
|
86
|
+
JTable table = (JTable)e.getSource();
|
87
|
+
int[] rows = table.getSelectedRows();
|
88
|
+
for(int i=0; i<rows.length; i++) {
|
89
|
+
rows[i] = table.convertRowIndexToModel(rows[i]);
|
78
90
|
}
|
91
|
+
|
92
|
+
MyTableModel model = (MyTableModel)table.getModel();
|
79
|
-
|
93
|
+
for(int i=rows.length-1; i>=0; i--) {
|
80
|
-
this.name = name;
|
81
|
-
this.duration = new Duration(duration, this);
|
82
|
-
|
94
|
+
model.remove(rows[i]);
|
83
95
|
}
|
84
|
-
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
class MyData {
|
101
|
+
final String name;
|
102
|
+
final int duration;
|
103
|
+
final String book;
|
104
|
+
|
105
|
+
MyData(String name, int duration, String book) {
|
106
|
+
this.name = name;
|
107
|
+
this.duration = duration;
|
108
|
+
this.book = book;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
class MyTableModel extends AbstractTableModel {
|
113
|
+
abstract private class Column {
|
114
|
+
final String title;
|
85
|
-
|
115
|
+
Column(String title) {
|
116
|
+
this.title = title;
|
117
|
+
}
|
118
|
+
abstract Object getValueAt(Row row);
|
119
|
+
abstract Class<?> getColumnClass();
|
86
|
-
|
120
|
+
abstract Row setRowAt(Row row, Object aValue);
|
121
|
+
}
|
122
|
+
private Column[] columns = {
|
123
|
+
new Column("Name") {
|
124
|
+
Object getValueAt(Row row) { return row.name; }
|
125
|
+
Class<?> getColumnClass() { return Row.Name.class; }
|
126
|
+
Row setRowAt(Row row, Object aValue) { return row.setName((String)aValue); }
|
127
|
+
},
|
128
|
+
new Column("Last job duration") {
|
129
|
+
Object getValueAt(Row row) { return row.duration; }
|
130
|
+
Class<?> getColumnClass() { return Row.Duration.class; }
|
131
|
+
Row setRowAt(Row row, Object aValue) { return row.setDuration((Integer)aValue); }
|
132
|
+
},
|
133
|
+
new Column("Book #") {
|
134
|
+
Object getValueAt(Row row) { return row.book; }
|
135
|
+
Class<?> getColumnClass() { return Row.Book.class; }
|
136
|
+
Row setRowAt(Row row, Object aValue) { return row.setBook((String)aValue); }
|
87
137
|
}
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
@Override
|
146
|
-
public Object getCellEditorValue() {
|
147
|
-
return Integer.parseInt(component.getText());
|
148
|
-
}
|
149
|
-
}
|
150
|
-
}
|
151
|
-
|
152
|
-
static class Book implements Comparable<Book> {
|
153
|
-
final String value;
|
154
|
-
final Row row;
|
155
|
-
Book(String value, Row row) {
|
156
|
-
this.value = value;
|
157
|
-
this.row = row;
|
158
|
-
}
|
159
|
-
@Override
|
160
|
-
public int compareTo(Book o) {
|
161
|
-
int result = row.name.compareTo(o.row.name);
|
162
|
-
return result == 0 ? value.compareTo(o.value) : result;
|
163
|
-
}
|
164
|
-
|
165
|
-
static class Renderer extends DefaultTableCellRenderer {
|
166
|
-
@Override
|
167
|
-
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
168
|
-
return super.getTableCellRendererComponent(table, ((Book)value).value, isSelected, hasFocus, row, column);
|
169
|
-
}
|
170
|
-
}
|
171
|
-
|
172
|
-
static class Editor extends AbstractCellEditor implements TableCellEditor {
|
173
|
-
private JTextField component = new JTextField();
|
174
|
-
@Override
|
175
|
-
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
|
176
|
-
Book book = (Book)value;
|
177
|
-
component.setText(book.value);
|
178
|
-
return component;
|
179
|
-
}
|
180
|
-
@Override
|
181
|
-
public Object getCellEditorValue() {
|
182
|
-
return component.getText();
|
183
|
-
}
|
184
|
-
}
|
185
|
-
}
|
186
|
-
|
187
|
-
private List<Row> rowList = new ArrayList<>();
|
188
|
-
|
189
|
-
void add(MyData mydata) {
|
190
|
-
int rowIndex = rowList.size();
|
191
|
-
rowList.add(new Row(mydata));
|
192
|
-
fireTableRowsInserted(rowIndex, rowIndex);
|
193
|
-
}
|
194
|
-
|
195
|
-
@Override
|
196
|
-
public String getColumnName(int column) {
|
197
|
-
return titles[column];
|
198
|
-
}
|
199
|
-
|
200
|
-
@Override
|
201
|
-
public int getColumnCount() {
|
202
|
-
return titles.length;
|
203
|
-
}
|
204
|
-
|
205
|
-
@Override
|
206
|
-
public int getRowCount() {
|
207
|
-
return rowList.size();
|
208
|
-
}
|
209
|
-
|
210
|
-
@Override
|
211
|
-
public Object getValueAt(int rowIndex, int columnIndex) {
|
212
|
-
switch(columnIndex) {
|
213
|
-
case 0: return rowList.get(rowIndex).name;
|
214
|
-
case 1: return rowList.get(rowIndex).duration;
|
215
|
-
case 2: return rowList.get(rowIndex).book;
|
216
|
-
}
|
217
|
-
return null;
|
218
|
-
}
|
219
|
-
|
220
|
-
@Override
|
221
|
-
public Class<?> getColumnClass(int columnIndex) {
|
222
|
-
switch(columnIndex) {
|
223
|
-
case 0: return OmittableString.class;
|
224
|
-
case 1: return Duration.class;
|
225
|
-
case 2: return Book.class;
|
226
|
-
}
|
227
|
-
return super.getColumnClass(columnIndex);
|
228
|
-
}
|
229
|
-
|
230
|
-
@Override
|
231
|
-
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
232
|
-
return true;
|
233
|
-
}
|
234
|
-
|
235
|
-
@Override
|
236
|
-
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
237
|
-
switch(columnIndex) {
|
238
|
-
case 0: rowList.set(rowIndex, rowList.get(rowIndex).setName((String)aValue)); break;
|
239
|
-
case 1: rowList.set(rowIndex, rowList.get(rowIndex).setDuration((Integer)aValue)); break;
|
240
|
-
case 2: rowList.set(rowIndex, rowList.get(rowIndex).setBook((String)aValue)); break;
|
241
|
-
}
|
242
|
-
}
|
138
|
+
};
|
139
|
+
|
140
|
+
private List<Row> rowList = new ArrayList<>();
|
141
|
+
|
142
|
+
void add(MyData data) {
|
143
|
+
insert(rowList.size(), data);
|
144
|
+
}
|
145
|
+
|
146
|
+
void insert(int rowIndex, MyData data) {
|
147
|
+
rowList.add(rowIndex, new Row(data.name, data.duration, data.book));
|
148
|
+
fireTableRowsInserted(rowIndex, rowIndex);
|
149
|
+
}
|
150
|
+
|
151
|
+
void remove(int rowIndex) {
|
152
|
+
rowList.remove(rowIndex);
|
153
|
+
fireTableRowsDeleted(rowIndex, rowIndex);
|
154
|
+
}
|
155
|
+
|
156
|
+
List<MyData> getList() {
|
157
|
+
List<MyData> list = new ArrayList<>();
|
158
|
+
for(Row row : rowList) list.add(row.getMyData());
|
159
|
+
return list;
|
160
|
+
}
|
161
|
+
|
162
|
+
@Override
|
163
|
+
public String getColumnName(int column) {
|
164
|
+
return columns[column].title;
|
165
|
+
}
|
166
|
+
|
167
|
+
@Override
|
168
|
+
public int getColumnCount() {
|
169
|
+
return columns.length;
|
170
|
+
}
|
171
|
+
|
172
|
+
@Override
|
173
|
+
public int getRowCount() {
|
174
|
+
return rowList.size();
|
175
|
+
}
|
176
|
+
|
177
|
+
@Override
|
178
|
+
public Object getValueAt(int rowIndex, int columnIndex) {
|
179
|
+
return columns[columnIndex].getValueAt(rowList.get(rowIndex));
|
180
|
+
}
|
181
|
+
|
182
|
+
@Override
|
183
|
+
public Class<?> getColumnClass(int columnIndex) {
|
184
|
+
return columns[columnIndex].getColumnClass();
|
185
|
+
}
|
186
|
+
|
187
|
+
@Override
|
188
|
+
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
189
|
+
return true;
|
190
|
+
}
|
191
|
+
|
192
|
+
@Override
|
193
|
+
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
194
|
+
rowList.set(rowIndex, columns[columnIndex].setRowAt(rowList.get(rowIndex), aValue));
|
243
195
|
}
|
244
196
|
}
|
245
197
|
```
|
198
|
+
Row.java
|
199
|
+
```java
|
200
|
+
class Row {
|
201
|
+
final String name;
|
202
|
+
final Duration duration;
|
203
|
+
final Book book;
|
204
|
+
|
205
|
+
Row(String name, int duration, String book) {
|
206
|
+
this.name = name;
|
207
|
+
this.duration = new Duration(duration);
|
208
|
+
this.book = new Book(book);
|
209
|
+
}
|
210
|
+
|
211
|
+
Row setName(String name) {
|
212
|
+
return new Row(name, duration.value, book.value);
|
213
|
+
}
|
214
|
+
Row setDuration(int duration) {
|
215
|
+
return new Row(name, duration, book.value);
|
216
|
+
}
|
217
|
+
Row setBook(String book) {
|
218
|
+
return new Row(name, duration.value, book);
|
219
|
+
}
|
220
|
+
MyData getMyData() {
|
221
|
+
return new MyData(name, duration.value, book.value);
|
222
|
+
}
|
223
|
+
|
224
|
+
class Name {
|
225
|
+
}
|
226
|
+
static class NameRenderer extends DefaultTableCellRenderer {
|
227
|
+
@Override
|
228
|
+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
229
|
+
//直前の行と同じ内容なら省略する
|
230
|
+
value = row>0 && Objects.equals(table.getValueAt(row-1, column), value) ? "" : value;
|
231
|
+
|
232
|
+
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
236
|
+
class Duration implements Comparable<Duration> {
|
237
|
+
final Integer value;
|
238
|
+
private Duration(int value) {
|
239
|
+
this.value = value;
|
240
|
+
}
|
241
|
+
private String getName() { return Row.this.name; }
|
242
|
+
@Override
|
243
|
+
public int compareTo(Duration o) {
|
244
|
+
int result = getName().compareTo(o.getName());
|
245
|
+
return result == 0 ? value.compareTo(o.value) : result;
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
static class DurationRenderer extends DefaultTableCellRenderer {
|
250
|
+
DurationRenderer() {
|
251
|
+
super();
|
252
|
+
setHorizontalAlignment(SwingConstants.RIGHT);
|
253
|
+
}
|
254
|
+
@Override
|
255
|
+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
256
|
+
return super.getTableCellRendererComponent(table, ((Duration)value).value, isSelected, hasFocus, row, column);
|
257
|
+
}
|
258
|
+
}
|
259
|
+
static class DurationEditor extends AbstractCellEditor implements TableCellEditor {
|
260
|
+
private JTextField component = new JTextField();
|
261
|
+
DurationEditor() {
|
262
|
+
component.setHorizontalAlignment(JTextField.RIGHT);
|
263
|
+
}
|
264
|
+
@Override
|
265
|
+
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
|
266
|
+
Duration duration = (Duration)value;
|
267
|
+
component.setText(""+duration.value);
|
268
|
+
return component;
|
269
|
+
}
|
270
|
+
@Override
|
271
|
+
public Object getCellEditorValue() {
|
272
|
+
try {
|
273
|
+
return Integer.parseInt(component.getText());
|
274
|
+
} catch(NumberFormatException e) {
|
275
|
+
return 0;
|
276
|
+
}
|
277
|
+
}
|
278
|
+
}
|
279
|
+
|
280
|
+
class Book implements Comparable<Book> {
|
281
|
+
final String value;
|
282
|
+
private Book(String value) {
|
283
|
+
this.value = value;
|
284
|
+
}
|
285
|
+
private String getName() { return Row.this.name; }
|
286
|
+
@Override
|
287
|
+
public int compareTo(Book o) {
|
288
|
+
int result = getName().compareTo(o.getName());
|
289
|
+
return result == 0 ? value.compareTo(o.value) : result;
|
290
|
+
}
|
291
|
+
}
|
292
|
+
|
293
|
+
static class BookRenderer extends DefaultTableCellRenderer {
|
294
|
+
@Override
|
295
|
+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
296
|
+
return super.getTableCellRendererComponent(table, ((Book)value).value, isSelected, hasFocus, row, column);
|
297
|
+
}
|
298
|
+
}
|
299
|
+
|
300
|
+
static class BookEditor extends AbstractCellEditor implements TableCellEditor {
|
301
|
+
private JTextField component = new JTextField();
|
302
|
+
@Override
|
303
|
+
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
|
304
|
+
Book book = (Book)value;
|
305
|
+
component.setText(book.value);
|
306
|
+
return component;
|
307
|
+
}
|
308
|
+
@Override
|
309
|
+
public Object getCellEditorValue() {
|
310
|
+
return component.getText();
|
311
|
+
}
|
312
|
+
}
|
313
|
+
}
|
314
|
+
```
|
6
コード修正
test
CHANGED
@@ -12,8 +12,6 @@
|
|
12
12
|
|
13
13
|
RowGroupInTableTest2.java
|
14
14
|
```java
|
15
|
-
package teratail_java.q_gc86fe9l52s1zn;
|
16
|
-
|
17
15
|
import java.awt.Component;
|
18
16
|
import java.awt.EventQueue;
|
19
17
|
import java.util.*;
|
5
コード修正
test
CHANGED
@@ -5,11 +5,15 @@
|
|
5
5
|
例えば [JTable のセルの値を更新するテーブルモデルの実装方法](https://java.keicode.com/lib/swing-jtable-6.php) のような記事をお読みになってみては如何でしょうか。
|
6
6
|
|
7
7
|
---
|
8
|
-
テーブルモデルを AbstractTableModel から作り、編集可能としてみました。(編集可能状態になるだけで、実際には編集・追加の処理が入っていませんので、編集・追加は出来ません。)
|
8
|
+
テーブルモデルを AbstractTableModel から作り、編集可能としてみました。~~(編集可能状態になるだけで、実際には編集・追加の処理が入っていませんので、編集・追加は出来ません。)~~
|
9
|
-
"Name" の列は OmittableString.class とすることでレンダラを使うようにし、編集可能とする為にエディタを設定しています。(name の実体は String なので特別なことはしていません。)
|
9
|
+
~~"Name" の列は OmittableString.class とすることでレンダラを使うようにし、編集可能とする為にエディタを設定しています。(name の実体は String なので特別なことはしていません。)~~
|
10
|
+
グループ化・ソートをオリジナル(?)に合わせる為に、 Duration・Book クラスを作って name を参照できるようにしました。
|
11
|
+
その為、全列にレンダラ・エディタが必要になりました・・・。
|
10
12
|
|
11
13
|
RowGroupInTableTest2.java
|
12
14
|
```java
|
15
|
+
package teratail_java.q_gc86fe9l52s1zn;
|
16
|
+
|
13
17
|
import java.awt.Component;
|
14
18
|
import java.awt.EventQueue;
|
15
19
|
import java.util.*;
|
@@ -40,30 +44,24 @@
|
|
40
44
|
|
41
45
|
JTable table = new JTable(model);
|
42
46
|
table.setFillsViewportHeight(true);
|
43
|
-
table.setDefaultRenderer(OmittableString.class, new OmittableStringRenderer());
|
47
|
+
table.setDefaultRenderer(MyTableModel.OmittableString.class, new MyTableModel.OmittableString.Renderer());
|
44
|
-
table.setDefaultEditor(OmittableString.class, new DefaultCellEditor(new JTextField()));
|
48
|
+
table.setDefaultEditor(MyTableModel.OmittableString.class, new DefaultCellEditor(new JTextField()));
|
45
|
-
|
49
|
+
table.setDefaultRenderer(MyTableModel.Duration.class, new MyTableModel.Duration.Renderer());
|
50
|
+
table.setDefaultEditor(MyTableModel.Duration.class, new MyTableModel.Duration.Editor());
|
51
|
+
table.setDefaultRenderer(MyTableModel.Book.class, new MyTableModel.Book.Renderer());
|
52
|
+
table.setDefaultEditor(MyTableModel.Book.class, new MyTableModel.Book.Editor());
|
53
|
+
|
46
|
-
|
54
|
+
table.setRowSorter(new TableRowSorter<TableModel>(model));
|
47
|
-
sorter.setComparator(0, new MyComparator<String>());
|
48
|
-
sorter.setComparator(1, new MyComparator<Integer>());
|
49
|
-
sorter.setComparator(2, new MyComparator<String>());
|
50
|
-
table.setRowSorter(sorter);
|
51
55
|
|
52
56
|
getContentPane().add(new JScrollPane(table));
|
53
|
-
}
|
54
|
-
|
55
|
-
static class MyComparator<T extends Comparable<T>> implements Comparator<T> {
|
56
|
-
@Override
|
57
|
-
public int compare(T o1, T o2) {
|
58
|
-
return o1.compareTo(o2);
|
59
|
-
}
|
60
57
|
}
|
61
58
|
|
62
59
|
static class MyData {
|
63
60
|
final String name;
|
64
61
|
final int duration;
|
65
62
|
final String book;
|
63
|
+
|
66
|
-
|
64
|
+
MyData(String name, int duration, String book) {
|
67
65
|
this.name = name;
|
68
66
|
this.duration = duration;
|
69
67
|
this.book = book;
|
@@ -73,11 +71,126 @@
|
|
73
71
|
static class MyTableModel extends AbstractTableModel {
|
74
72
|
private static final String[] titles = new String[] {"Name", "Last job duration", "Book #"};
|
75
73
|
|
74
|
+
static class Row {
|
75
|
+
final String name;
|
76
|
+
final Duration duration;
|
77
|
+
final Book book;
|
78
|
+
Row(MyData mydata) {
|
79
|
+
this(mydata.name, mydata.duration, mydata.book);
|
80
|
+
}
|
81
|
+
private Row(String name, int duration, String book) {
|
82
|
+
this.name = name;
|
83
|
+
this.duration = new Duration(duration, this);
|
84
|
+
this.book = new Book(book, this);
|
85
|
+
}
|
86
|
+
|
87
|
+
Row setName(String name) {
|
88
|
+
return new Row(name, duration.value, book.value);
|
89
|
+
}
|
90
|
+
Row setDuration(int duration) {
|
91
|
+
return new Row(name, duration, book.value);
|
92
|
+
}
|
93
|
+
Row setBook(String book) {
|
94
|
+
return new Row(name, duration.value, book);
|
95
|
+
}
|
96
|
+
MyData getMyData() {
|
97
|
+
return new MyData(name, duration.value, book.value);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
static class OmittableString {
|
102
|
+
static class Renderer extends DefaultTableCellRenderer {
|
103
|
+
@Override
|
104
|
+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
105
|
+
//直前の行と同じ内容なら省略する
|
106
|
+
value = row>0 && Objects.equals(table.getValueAt(row-1, column), value) ? "" : value;
|
107
|
+
|
108
|
+
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
113
|
+
static class Duration implements Comparable<Duration> {
|
114
|
+
final Integer value;
|
115
|
+
final Row row;
|
116
|
+
Duration(int value, Row row) {
|
117
|
+
this.value = value;
|
118
|
+
this.row = row;
|
119
|
+
}
|
120
|
+
@Override
|
121
|
+
public int compareTo(Duration o) {
|
122
|
+
int result = row.name.compareTo(o.row.name);
|
123
|
+
return result == 0 ? value.compareTo(o.value) : result;
|
124
|
+
}
|
125
|
+
|
126
|
+
static class Renderer extends DefaultTableCellRenderer {
|
127
|
+
Renderer() {
|
128
|
+
super();
|
129
|
+
setHorizontalAlignment(SwingConstants.RIGHT);
|
130
|
+
}
|
131
|
+
@Override
|
132
|
+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
133
|
+
return super.getTableCellRendererComponent(table, ((Duration)value).value, isSelected, hasFocus, row, column);
|
134
|
+
}
|
135
|
+
}
|
136
|
+
static class Editor extends AbstractCellEditor implements TableCellEditor {
|
137
|
+
private JTextField component = new JTextField();
|
138
|
+
Editor() {
|
139
|
+
component.setHorizontalAlignment(JTextField.RIGHT);
|
140
|
+
}
|
141
|
+
@Override
|
142
|
+
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
|
143
|
+
Duration duration = (Duration)value;
|
144
|
+
component.setText(""+duration.value);
|
145
|
+
return component;
|
146
|
+
}
|
147
|
+
@Override
|
148
|
+
public Object getCellEditorValue() {
|
149
|
+
return Integer.parseInt(component.getText());
|
150
|
+
}
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
static class Book implements Comparable<Book> {
|
155
|
+
final String value;
|
156
|
+
final Row row;
|
157
|
+
Book(String value, Row row) {
|
158
|
+
this.value = value;
|
159
|
+
this.row = row;
|
160
|
+
}
|
161
|
+
@Override
|
162
|
+
public int compareTo(Book o) {
|
163
|
+
int result = row.name.compareTo(o.row.name);
|
164
|
+
return result == 0 ? value.compareTo(o.value) : result;
|
165
|
+
}
|
166
|
+
|
167
|
+
static class Renderer extends DefaultTableCellRenderer {
|
168
|
+
@Override
|
169
|
+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
170
|
+
return super.getTableCellRendererComponent(table, ((Book)value).value, isSelected, hasFocus, row, column);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
static class Editor extends AbstractCellEditor implements TableCellEditor {
|
175
|
+
private JTextField component = new JTextField();
|
176
|
+
@Override
|
177
|
+
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
|
178
|
+
Book book = (Book)value;
|
179
|
+
component.setText(book.value);
|
180
|
+
return component;
|
181
|
+
}
|
182
|
+
@Override
|
183
|
+
public Object getCellEditorValue() {
|
184
|
+
return component.getText();
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
76
|
-
private List<
|
189
|
+
private List<Row> rowList = new ArrayList<>();
|
77
190
|
|
78
191
|
void add(MyData mydata) {
|
79
|
-
int rowIndex =
|
192
|
+
int rowIndex = rowList.size();
|
80
|
-
|
193
|
+
rowList.add(new Row(mydata));
|
81
194
|
fireTableRowsInserted(rowIndex, rowIndex);
|
82
195
|
}
|
83
196
|
|
@@ -93,15 +206,15 @@
|
|
93
206
|
|
94
207
|
@Override
|
95
208
|
public int getRowCount() {
|
96
|
-
return
|
209
|
+
return rowList.size();
|
97
210
|
}
|
98
211
|
|
99
212
|
@Override
|
100
213
|
public Object getValueAt(int rowIndex, int columnIndex) {
|
101
214
|
switch(columnIndex) {
|
102
|
-
case 0: return
|
215
|
+
case 0: return rowList.get(rowIndex).name;
|
103
|
-
case 1: return
|
216
|
+
case 1: return rowList.get(rowIndex).duration;
|
104
|
-
case 2: return
|
217
|
+
case 2: return rowList.get(rowIndex).book;
|
105
218
|
}
|
106
219
|
return null;
|
107
220
|
}
|
@@ -110,8 +223,8 @@
|
|
110
223
|
public Class<?> getColumnClass(int columnIndex) {
|
111
224
|
switch(columnIndex) {
|
112
225
|
case 0: return OmittableString.class;
|
113
|
-
case 1: return
|
226
|
+
case 1: return Duration.class;
|
114
|
-
case 2: return
|
227
|
+
case 2: return Book.class;
|
115
228
|
}
|
116
229
|
return super.getColumnClass(columnIndex);
|
117
230
|
}
|
@@ -120,22 +233,14 @@
|
|
120
233
|
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
121
234
|
return true;
|
122
235
|
}
|
236
|
+
|
237
|
+
@Override
|
238
|
+
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
239
|
+
switch(columnIndex) {
|
240
|
+
case 0: rowList.set(rowIndex, rowList.get(rowIndex).setName((String)aValue)); break;
|
241
|
+
case 1: rowList.set(rowIndex, rowList.get(rowIndex).setDuration((Integer)aValue)); break;
|
242
|
+
case 2: rowList.set(rowIndex, rowList.get(rowIndex).setBook((String)aValue)); break;
|
123
|
-
}
|
243
|
+
}
|
124
|
-
|
125
|
-
static class OmittableString {}
|
126
|
-
|
127
|
-
static class OmittableStringRenderer extends DefaultTableCellRenderer {
|
128
|
-
OmittableStringRenderer() {
|
129
|
-
super();
|
130
|
-
setHorizontalAlignment(SwingConstants.LEFT);
|
131
|
-
}
|
132
|
-
|
133
|
-
@Override
|
134
|
-
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
135
|
-
//直前の行と同じ内容なら省略する
|
136
|
-
value = row>0 && Objects.equals(table.getValueAt(row-1, column), value) ? "" : value;
|
137
|
-
|
138
|
-
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
139
244
|
}
|
140
245
|
}
|
141
246
|
}
|
4
コード修正
test
CHANGED
@@ -41,7 +41,7 @@
|
|
41
41
|
JTable table = new JTable(model);
|
42
42
|
table.setFillsViewportHeight(true);
|
43
43
|
table.setDefaultRenderer(OmittableString.class, new OmittableStringRenderer());
|
44
|
-
table.setDefaultEditor(OmittableString.class, new
|
44
|
+
table.setDefaultEditor(OmittableString.class, new DefaultCellEditor(new JTextField()));
|
45
45
|
|
46
46
|
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
|
47
47
|
sorter.setComparator(0, new MyComparator<String>());
|
@@ -138,11 +138,5 @@
|
|
138
138
|
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
139
139
|
}
|
140
140
|
}
|
141
|
-
|
142
|
-
static class OmittableStringEditor extends DefaultCellEditor {
|
143
|
-
public OmittableStringEditor() {
|
144
|
-
super(new JTextField());
|
145
|
-
}
|
146
|
-
}
|
147
141
|
}
|
148
142
|
```
|
3
コード修正
test
CHANGED
@@ -132,20 +132,10 @@
|
|
132
132
|
|
133
133
|
@Override
|
134
134
|
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
135
|
+
//直前の行と同じ内容なら省略する
|
135
|
-
|
136
|
+
value = row>0 && Objects.equals(table.getValueAt(row-1, column), value) ? "" : value;
|
136
137
|
|
137
|
-
String name = (String)value;
|
138
|
-
if(row > 0) {
|
139
|
-
//if (table.getModel().getValueAt(row-1, column).equals(value)) {
|
140
|
-
//Since it compares with the value of the previous line on the display,
|
141
|
-
//table.getModel() is not needed
|
142
|
-
|
138
|
+
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
143
|
-
if(Objects.equals(prev, name)) {
|
144
|
-
name = "";
|
145
|
-
}
|
146
|
-
}
|
147
|
-
setText(name);
|
148
|
-
return this;
|
149
139
|
}
|
150
140
|
}
|
151
141
|
|
2
クラス名変更
test
CHANGED
@@ -41,7 +41,7 @@
|
|
41
41
|
JTable table = new JTable(model);
|
42
42
|
table.setFillsViewportHeight(true);
|
43
43
|
table.setDefaultRenderer(OmittableString.class, new OmittableStringRenderer());
|
44
|
-
table.setDefaultEditor(OmittableString.class, new OmittableString
|
44
|
+
table.setDefaultEditor(OmittableString.class, new OmittableStringEditor());
|
45
45
|
|
46
46
|
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
|
47
47
|
sorter.setComparator(0, new MyComparator<String>());
|
@@ -149,8 +149,8 @@
|
|
149
149
|
}
|
150
150
|
}
|
151
151
|
|
152
|
-
static class OmittableString
|
152
|
+
static class OmittableStringEditor extends DefaultCellEditor {
|
153
|
-
public OmittableString
|
153
|
+
public OmittableStringEditor() {
|
154
154
|
super(new JTextField());
|
155
155
|
}
|
156
156
|
}
|
1
コード追加
test
CHANGED
@@ -3,3 +3,156 @@
|
|
3
3
|
そこから逆に言いますと、使う側にとっては簡単になる「直接書き込み」はコードを作る側にとっては(コード的にも、データの整合性的にも)「簡単では無く」なります。
|
4
4
|
|
5
5
|
例えば [JTable のセルの値を更新するテーブルモデルの実装方法](https://java.keicode.com/lib/swing-jtable-6.php) のような記事をお読みになってみては如何でしょうか。
|
6
|
+
|
7
|
+
---
|
8
|
+
テーブルモデルを AbstractTableModel から作り、編集可能としてみました。(編集可能状態になるだけで、実際には編集・追加の処理が入っていませんので、編集・追加は出来ません。)
|
9
|
+
"Name" の列は OmittableString.class とすることでレンダラを使うようにし、編集可能とする為にエディタを設定しています。(name の実体は String なので特別なことはしていません。)
|
10
|
+
|
11
|
+
RowGroupInTableTest2.java
|
12
|
+
```java
|
13
|
+
import java.awt.Component;
|
14
|
+
import java.awt.EventQueue;
|
15
|
+
import java.util.*;
|
16
|
+
|
17
|
+
import javax.swing.*;
|
18
|
+
import javax.swing.table.*;
|
19
|
+
|
20
|
+
public class RowGroupInTableTest2 extends JFrame {
|
21
|
+
public static void main(String[] args) {
|
22
|
+
EventQueue.invokeLater(() -> new RowGroupInTableTest2().setVisible(true));
|
23
|
+
}
|
24
|
+
|
25
|
+
RowGroupInTableTest2() {
|
26
|
+
super("RowGroupInTableTest2");
|
27
|
+
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
28
|
+
setSize(320, 240);
|
29
|
+
setLocationRelativeTo(null);
|
30
|
+
|
31
|
+
MyTableModel model = new MyTableModel();
|
32
|
+
model.add(new MyData("Tom", 17, "Book1"));
|
33
|
+
model.add(new MyData("Tom", 23, "Book2"));
|
34
|
+
model.add(new MyData("Tom", 25, "Book3"));
|
35
|
+
model.add(new MyData("Polazzo", 41, "Book1"));
|
36
|
+
model.add(new MyData("Polazzo", 45, "Book2"));
|
37
|
+
model.add(new MyData("Polazzo", 12, "Book3"));
|
38
|
+
model.add(new MyData("Anna", 1, "Book3"));
|
39
|
+
model.add(new MyData("Anna", 33, "Book5"));
|
40
|
+
|
41
|
+
JTable table = new JTable(model);
|
42
|
+
table.setFillsViewportHeight(true);
|
43
|
+
table.setDefaultRenderer(OmittableString.class, new OmittableStringRenderer());
|
44
|
+
table.setDefaultEditor(OmittableString.class, new OmittableStringCellEditor());
|
45
|
+
|
46
|
+
TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
|
47
|
+
sorter.setComparator(0, new MyComparator<String>());
|
48
|
+
sorter.setComparator(1, new MyComparator<Integer>());
|
49
|
+
sorter.setComparator(2, new MyComparator<String>());
|
50
|
+
table.setRowSorter(sorter);
|
51
|
+
|
52
|
+
getContentPane().add(new JScrollPane(table));
|
53
|
+
}
|
54
|
+
|
55
|
+
static class MyComparator<T extends Comparable<T>> implements Comparator<T> {
|
56
|
+
@Override
|
57
|
+
public int compare(T o1, T o2) {
|
58
|
+
return o1.compareTo(o2);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
static class MyData {
|
63
|
+
final String name;
|
64
|
+
final int duration;
|
65
|
+
final String book;
|
66
|
+
protected MyData(String name, int duration, String book) {
|
67
|
+
this.name = name;
|
68
|
+
this.duration = duration;
|
69
|
+
this.book = book;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
static class MyTableModel extends AbstractTableModel {
|
74
|
+
private static final String[] titles = new String[] {"Name", "Last job duration", "Book #"};
|
75
|
+
|
76
|
+
private List<MyData> mydataList = new ArrayList<>();
|
77
|
+
|
78
|
+
void add(MyData mydata) {
|
79
|
+
int rowIndex = mydataList.size();
|
80
|
+
mydataList.add(mydata);
|
81
|
+
fireTableRowsInserted(rowIndex, rowIndex);
|
82
|
+
}
|
83
|
+
|
84
|
+
@Override
|
85
|
+
public String getColumnName(int column) {
|
86
|
+
return titles[column];
|
87
|
+
}
|
88
|
+
|
89
|
+
@Override
|
90
|
+
public int getColumnCount() {
|
91
|
+
return titles.length;
|
92
|
+
}
|
93
|
+
|
94
|
+
@Override
|
95
|
+
public int getRowCount() {
|
96
|
+
return mydataList.size();
|
97
|
+
}
|
98
|
+
|
99
|
+
@Override
|
100
|
+
public Object getValueAt(int rowIndex, int columnIndex) {
|
101
|
+
switch(columnIndex) {
|
102
|
+
case 0: return mydataList.get(rowIndex).name;
|
103
|
+
case 1: return mydataList.get(rowIndex).duration;
|
104
|
+
case 2: return mydataList.get(rowIndex).book;
|
105
|
+
}
|
106
|
+
return null;
|
107
|
+
}
|
108
|
+
|
109
|
+
@Override
|
110
|
+
public Class<?> getColumnClass(int columnIndex) {
|
111
|
+
switch(columnIndex) {
|
112
|
+
case 0: return OmittableString.class;
|
113
|
+
case 1: return Integer.class;
|
114
|
+
case 2: return String.class;
|
115
|
+
}
|
116
|
+
return super.getColumnClass(columnIndex);
|
117
|
+
}
|
118
|
+
|
119
|
+
@Override
|
120
|
+
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
121
|
+
return true;
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
static class OmittableString {}
|
126
|
+
|
127
|
+
static class OmittableStringRenderer extends DefaultTableCellRenderer {
|
128
|
+
OmittableStringRenderer() {
|
129
|
+
super();
|
130
|
+
setHorizontalAlignment(SwingConstants.LEFT);
|
131
|
+
}
|
132
|
+
|
133
|
+
@Override
|
134
|
+
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
135
|
+
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
136
|
+
|
137
|
+
String name = (String)value;
|
138
|
+
if(row > 0) {
|
139
|
+
//if (table.getModel().getValueAt(row-1, column).equals(value)) {
|
140
|
+
//Since it compares with the value of the previous line on the display,
|
141
|
+
//table.getModel() is not needed
|
142
|
+
String prev = (String)table.getValueAt(row - 1, column);
|
143
|
+
if(Objects.equals(prev, name)) {
|
144
|
+
name = "";
|
145
|
+
}
|
146
|
+
}
|
147
|
+
setText(name);
|
148
|
+
return this;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
static class OmittableStringCellEditor extends DefaultCellEditor {
|
153
|
+
public OmittableStringCellEditor() {
|
154
|
+
super(new JTextField());
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}
|
158
|
+
```
|