回答編集履歴

7

コード変更

2022/04/13 08:38

投稿

jimbe
jimbe

スコア12623

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(MyTableModel.OmittableString.class, new MyTableModel.OmittableString.Renderer());
41
+ table.setDefaultRenderer(Row.Name.class, new Row.NameRenderer());
46
- table.setDefaultEditor(MyTableModel.OmittableString.class, new DefaultCellEditor(new JTextField()));
42
+ table.setDefaultEditor(Row.Name.class, new DefaultCellEditor(new JTextField()));
47
- table.setDefaultRenderer(MyTableModel.Duration.class, new MyTableModel.Duration.Renderer());
43
+ table.setDefaultRenderer(Row.Duration.class, new Row.DurationRenderer());
48
- table.setDefaultEditor(MyTableModel.Duration.class, new MyTableModel.Duration.Editor());
44
+ table.setDefaultEditor(Row.Duration.class, new Row.DurationEditor());
49
- table.setDefaultRenderer(MyTableModel.Book.class, new MyTableModel.Book.Renderer());
45
+ table.setDefaultRenderer(Row.Book.class, new Row.BookRenderer());
50
- table.setDefaultEditor(MyTableModel.Book.class, new MyTableModel.Book.Editor());
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
- MyData(String name, int duration, String book) {
56
+ private static void setAction(JTable table, KeyStroke key, Action a) {
63
- this.name = name;
64
- this.duration = duration;
57
+ table.getActionMap().put(a, a);
58
+
59
+ InputMap im;
60
+ im = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
65
- this.book = book;
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
- static class MyTableModel extends AbstractTableModel {
79
+ public class DeleteAction extends AbstractAction {
70
- private static final String[] titles = new String[] {"Name", "Last job duration", "Book #"};
71
-
72
- static class Row {
80
+ public DeleteAction() {
73
- final String name;
74
- final Duration duration;
81
+ super("table-row-del");
82
+ }
83
+
75
- final Book book;
84
+ @Override
76
- Row(MyData mydata) {
77
- this(mydata.name, mydata.duration, mydata.book);
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
- private Row(String name, int duration, String book) {
93
+ for(int i=rows.length-1; i>=0; i--) {
80
- this.name = name;
81
- this.duration = new Duration(duration, this);
82
- this.book = new Book(book, this);
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
- Row setName(String name) {
115
+ Column(String title) {
116
+ this.title = title;
117
+ }
118
+ abstract Object getValueAt(Row row);
119
+ abstract Class<?> getColumnClass();
86
- return new Row(name, duration.value, book.value);
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
- Row setDuration(int duration) {
89
- return new Row(name, duration, book.value);
90
- }
91
- Row setBook(String book) {
92
- return new Row(name, duration.value, book);
93
- }
94
- MyData getMyData() {
95
- return new MyData(name, duration.value, book.value);
96
- }
97
- }
98
-
99
- static class OmittableString {
100
- static class Renderer extends DefaultTableCellRenderer {
101
- @Override
102
- public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
103
- //直前の行と同じ内容なら省略する
104
- value = row>0 && Objects.equals(table.getValueAt(row-1, column), value) ? "" : value;
105
-
106
- return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
107
- }
108
- }
109
- }
110
-
111
- static class Duration implements Comparable<Duration> {
112
- final Integer value;
113
- final Row row;
114
- Duration(int value, Row row) {
115
- this.value = value;
116
- this.row = row;
117
- }
118
- @Override
119
- public int compareTo(Duration o) {
120
- int result = row.name.compareTo(o.row.name);
121
- return result == 0 ? value.compareTo(o.value) : result;
122
- }
123
-
124
- static class Renderer extends DefaultTableCellRenderer {
125
- Renderer() {
126
- super();
127
- setHorizontalAlignment(SwingConstants.RIGHT);
128
- }
129
- @Override
130
- public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
131
- return super.getTableCellRendererComponent(table, ((Duration)value).value, isSelected, hasFocus, row, column);
132
- }
133
- }
134
- static class Editor extends AbstractCellEditor implements TableCellEditor {
135
- private JTextField component = new JTextField();
136
- Editor() {
137
- component.setHorizontalAlignment(JTextField.RIGHT);
138
- }
139
- @Override
140
- public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
141
- Duration duration = (Duration)value;
142
- component.setText(""+duration.value);
143
- return component;
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

コード修正

2022/04/12 18:52

投稿

jimbe
jimbe

スコア12623

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

コード修正

2022/04/12 18:44

投稿

jimbe
jimbe

スコア12623

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
- TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
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
- protected MyData(String name, int duration, String book) {
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<MyData> mydataList = new ArrayList<>();
189
+ private List<Row> rowList = new ArrayList<>();
77
190
 
78
191
  void add(MyData mydata) {
79
- int rowIndex = mydataList.size();
192
+ int rowIndex = rowList.size();
80
- mydataList.add(mydata);
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 mydataList.size();
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 mydataList.get(rowIndex).name;
215
+ case 0: return rowList.get(rowIndex).name;
103
- case 1: return mydataList.get(rowIndex).duration;
216
+ case 1: return rowList.get(rowIndex).duration;
104
- case 2: return mydataList.get(rowIndex).book;
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 Integer.class;
226
+ case 1: return Duration.class;
114
- case 2: return String.class;
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

コード修正

2022/04/12 04:12

投稿

jimbe
jimbe

スコア12623

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 OmittableStringEditor());
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

コード修正

2022/04/12 04:06

投稿

jimbe
jimbe

スコア12623

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
- super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
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
- String prev = (String)table.getValueAt(row - 1, column);
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

クラス名変更

2022/04/12 03:43

投稿

jimbe
jimbe

スコア12623

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 OmittableStringCellEditor());
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 OmittableStringCellEditor extends DefaultCellEditor {
152
+ static class OmittableStringEditor extends DefaultCellEditor {
153
- public OmittableStringCellEditor() {
153
+ public OmittableStringEditor() {
154
154
  super(new JTextField());
155
155
  }
156
156
  }

1

コード追加

2022/04/12 03:38

投稿

jimbe
jimbe

スコア12623

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
+ ```