#java #swing #jtable #overriding #jcheckbox
#java #swing #jtable #переопределение #jcheckbox
Вопрос:
Мне нужна JTable для отражения содержимого динамического массива, поэтому мне пришлось переопределить ее функцию getValueAt. Проблема в том, что теперь JCheckboxes внутри таблицы не могут быть переключены.
Я искал ответ, так как я думал, что это довольно обычная ситуация, но я не нашел рабочего решения, так что это моя последняя надежда.
Возвращаясь к вопросу, вот тестовый JFrame, который я закодировал:
package gui;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class CheckboxTest extends JFrame {
private JPanel contentPane;
private JTable table;
private Object[][] tableRows;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
CheckboxTest frame = new CheckboxTest();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public CheckboxTest() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane, BorderLayout.CENTER);
tableRows = new Object[5][2];
for (int i = 0; i < tableRows.length; i ) {
tableRows[i][0] = new Boolean(i % 2 == 0);
tableRows[i][1] = "Test";
}
table = new JTable(new DefaultTableModel(tableRows, new String[] {"", "Name"}){
@Override public Class<?> getColumnClass(int col) {
return (Class<?>) new Object[] { Boolean.class, String.class }[col];
}
@Override public boolean isCellEditable(int row, int col) {
return true;
}
@Override public Object getValueAt(int row, int col) {
return tableRows[row][col];
}
});
scrollPane.setViewportView(table);
}
}
Комментарии:
1. значение должно быть true / false, для получения дополнительной информации прочитайте руководство Oracle — Как использовать таблицы, 0/1 в visual basic vba / e …
2. Я читал это несколько раз, но, боюсь, это все еще кажется мне запутанным. Я реализовал класс Boolean, как вы предложили, но, похоже, ничего не изменилось. Не могли бы вы, пожалуйста, объяснить более подробно?
3. логический класс собирается помочь DefaultTableModel узнать желаемый тип значения, но вам нужно установить там значение в форме true / false, тогда JCheckBox уже виден в представлении JTables, возможно, для поиска IsEditable, затем вы можете изменить ВЫБРАННЫЙ / ОТМЕНЕННЫЙ ВЫБОР, и в DefaultTableModel будет сохранено значение true / false
4. На самом деле я никогда не использовал значения 0/1 в качестве логических значений в коде. Я подозреваю, что вы неправильно прочитали текст.
5. верно, я вижу
tableRows[i][0] = new Boolean(i % 2 == 0);
в вашем коде
Ответ №1:
Вы должны убедиться, что логический столбец доступен для редактирования. Ваш подкласс DefaultTableModel по умолчанию должен перезаписать метод boolean isCellEditable(int RowIndex, int columIndex), который должен возвращать true для ColumnIndex 0)
Комментарии:
1. Операционная система не использует табличную модель, в этом большая часть проблемы
2. Добавлено в код. Похоже, что это ничего не меняет.
3. @MadProgrammer Я не понимаю, что ты имеешь в виду.
4. «Ваш подкласс DefaultTableModel должен быть перезаписан» — Операционная система не использует табличную модель, они напрямую расширены из JTable…
5. Операционная система расширяет DefaultTableModel, но в этом проблема, они расширяют ее неправильно.
Ответ №2:
Нашел решение сам. Мне просто пришлось переопределить функцию setValueAt в DefaultTableModel с помощью
@Override
public void setValueAt(Object value, int row, int col) {
tableRows[row][col] = value;
}
Комментарии:
1. -1 это неправильное решение. DefaultTableModel использует вектор векторов для хранения данных. Вам не нужно переопределять ни метод getValueAt(), ни метод setValueAt(). Все, что вам нужно сделать, это переопределить
getColumnClass()
метод для возврата класса столбца, чтобы таблица могла использовать надлежащий рендерер / редактор.2. Я бы не стал переопределять функции без причины. Мне нужно, чтобы моя таблица отображала динамический массив, который модифицируется в форме. Единственным элементом, который можно редактировать в таблице, является JCheckBox для включения / отключения строки. Если у вас есть лучший способ сделать это, я весь внимание @camickr .
3. Вы никогда не должны обновлять массив. Массив может быть использован ОДИН раз для загрузки данных в
DefaultTableModel
. Если вам нужно изменить данные, вы изменяете данные в TableModel, а не в массиве, поскольку вы не хотите хранить данные в двух местах. В модели DefaultTableModel есть такие методы, как setValueAt(…), addRow(…) и т.д. Затем TableModel вызовет соответствующие методы fireXXX (…), чтобы уведомить таблицу об изменении данных, чтобы таблица могла перерисовать себя. Это одинаково для всех компонентов Swing, вы всегда вносите изменения непосредственно в МОДЕЛЬ компонента.4.
How is this wrong?
— массив может использоваться для загрузки данных в DefaultTableModel, а затем вы должны присвоить массиву значение null и никогда больше не ссылаться на массив. Все обновления данных должны выполняться с помощью методов TableModel. DefaultTableModel уже определяет векторы для хранения данных. Определяя отдельную структуру для хранения данных в массивах, вы получаете запутанную реализацию табличной модели. Также ваша реализация НЕ вызывает метод fireXXX() при изменении данных. Уведомлять таблицу об изменениях данных — обязанность модели, а не кода приложения.5. Если вы хотите создать пользовательскую табличную модель со своим собственным хранилищем данных, тогда вам следует расширить AbstractTableModel, и в этом случае вам нужно будет реализовать все методы, продемонстрированные в руководстве Swing по созданию табличной модели