Обновление ImageIcon ячейки JTable
Я создаю свой первый JTable, который требует от меня, чтобы создать пользовательский AbstractTableModel
, TableCellEditor
, а также DefaultTableCellRenderer
, Учитывая, что мне не нужно было создавать их раньше, я добился значительного прогресса в том, чтобы заставить мой стол вести себя так, как хотелось бы.
Тем не менее, меня переполняют все различные методы, которые я переопределяю, и я вращаю свои колеса, пытаясь выяснить, как изменить ImageIcon конкретной ячейки. Ячейка должна содержать JLabel, так как она требует ImageIcon
а также текстовая строка. Я уже могу установить начальный ImageIcon
(хотя я, вероятно, делаю это неправильно), но я не могу установить обновленный ImageIcon
, Ничего не выходит из строя, но никаких изменений не происходит.
В общем смысле, каков наилучший способ получить и установить значок JLabel
клетка JTable
Предполагая, что все эти модели, редакторы и средства визуализации уже были созданы?
Моя модель уже определена для возврата JLabel.class
для этих клеток, если вам интересно, и я также делаю fireTableCellUpdated(row, col)
как только изменение предположительно было сделано. Если я сделаю System.out.println(getIcon())
до и после обновления я даже вижу, что источник изменился.
Вот часть кода (обновлено с исправлением URL/ImageIcon):
class MonitorTable extends JTable {
MonitorTableModel model = new MonitorTableModel(rows, columnNames);
setModel(model);
...
public void setIconAt(ImageIcon icon, int row, int col) {
model.setIconAt(icon, row, col);
} // End setIconAt(ImageIcon, int, int)
...
class MonitorTableModel extends AbstractTableModel {
...
public void setIconAt(ImageIcon icon, int row, int col) {
StatusTableCellRenderer cell =
(StatusTableCellRenderer)getColumnModel().getColumn(col).getCellRenderer().
getTableCellRendererComponent(myTableObject, null, false, false, row, col);
System.out.println(cell.getIcon()); // Shows initial icon source
cell.setIcon(icon);
fireTableCellUpdated(row, col); // Should update the table
System.out.println(cell.getIcon()); // Shows new icon source
System.out.println("Cell updated");
} // End setIconAt(ImageIcon, int, int)
} // End class MonitorTableModel
public class StatusTableCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
setIcon(imgGray);
setText((String)value);
return this;
} // End getTableCellRendererComponent(JTable, Object, boolean, boolean, int, int)
} // End class StatusTableCellRenderer
} // End class MonitorTable
3 ответа
Я исправил это, изменив setIcon(imgGray)
в if (getIcon() == null) setIcon(imgGray);
,
Вопрос мой getTableCellRendererComponent
Метод устанавливал иконку на imgGray каждый раз. Видимо мой setIconAt
метод, который вызывает getTableCellRendererComponent
, переопределялся, даже если значение "нового" значка обрабатывалось после того, как "старое" значение было (пере) установлено.
Я закончил тем, что удалил все свои setIcon
методы и переместил соответствующую логику в мой StatusTableCellRenderer
учебный класс. Таким образом, я передаю значение ячейки и позволяю средству визуализации выполнять настройку пиктограмм на основе этого значения. Это имеет больше смысла, и работает прекрасно. Я подтвердил, что начальная настройка и все последующие обновления выполняются, как и ожидалось.
Логика установки значка довольно проста - установите предопределенный значок на основе определенных предопределенных пороговых значений.
double val;
if (getIcon() == null) setIcon(imgGray); // Initialize
if ((value == null) || (value == "")) {
val = 0;
} else {
val = Double.parseDouble(value.toString());
} // End if
if (val <= THRESHOLD1) {
setIcon(icon1);
} else if (val <= THRESHOLD2) {
setIcon(icon2);
...
} // End if
setText(value.toString());
Я был очень обеспокоен предложениями, чтобы сделать новые объекты для использования, когда по умолчанию JLabel
было именно то, что мне было нужно. Это было и ненужным, и потенциальным ударом по производительности JTable
, Спасибо всем за понимание и помощь. Это сводило меня с ума!
Моя модель уже была определена для возвращения JLabel.class для этих ячеек,
Но в соответствии с кодом вашего рендерера вы ожидаете значение String в этих ячейках:
setText((String)value);
Мне не нравится ваш метод setIcon(). Я бы не стал передавать URL. Я бы прошел в иконе. Возможно, у вас проблема с тем, что значок не был считан в память во время визуализации ячейки.
Каков наилучший способ получить и установить значок для ячейки JLabel JTable,
Вы не должны хранить JLable в TableModel. Хранить компоненты Swing в модели дорого, поэтому в компонентах Swing используются средства визуализации. Вместо этого вы храните пользовательский объект, такой как "LabelInfo", который содержит два свойства, текст и значок. Затем ваш пользовательский рендер будет расширять рендерер по умолчанию и вызывать super.getTableCellRendererComponent(). После этого вы можете получить доступ к своему объекту и оставить свойства текста / значка средства визуализации. Вы не должны создавать объекты в рендере.
Теперь, когда вы хотите что-то изменить в модели, вы можете сделать:
LabelInfo info = (LabelInfo)table.getValueAt(row, column);
info.setIcon(...);
table.setValueAt(info, row, column);
Это все, что вам нужно. Не существует специального кода для перерисовки ячейки или чего-либо еще, потому что он уже встроен в метод setValueAt(...). вашей настольной модели.
Редактировать: простой пример использования пользовательского объекта в TableModel.
1) для добавления объекта в модель вы делаете что-то вроде:
LabelInfo info = new LabelInfo("some Text", yourIcon);
table.setValueAt(info, row, column);
2) код для вашего пользовательского рендерера будет:
class LabelInfoRenderer extends DefaultTableCellRenderer
{
@Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
LableInfo info = (LabelInfo)value;
setIcon( info.getIcon() );
return this;
}
}
Вызовите fireTableDataChanged из вашей модели.
Попробуйте также вызвать метод перекраски из JLabel.
Лучший способ сделать это - реализовать CellRenderer, который возвращает JPanel и создать метод draw в paintComponent. Вы можете загрузить BufferedImage вместо ImageIcon и использовать его для рисования в JPanel.
Попробуйте изменить свой Renderer на:
public class StatusTableCellRenderer extends DefaultTableCellRenderer {
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
JLabel comp = new JLabel(new ImageIcon(imgGray));
comp.setText((String)value);
return comp;
} // End getTableCellRendererComponent(JTable, Object, boolean, boolean, int, int)
}
Вы делаете некоторую путаницу, это неправильный способ работы с TableModel, вы должны вернуть URL для изображения в getValueAt(int row, int col), после этого зарегистрируйте CellRenderer, чтобы он соответствовал ячейкам с URL. учебный класс. Рендерер автоматически вызывается из JTable, вам не нужно расширять JTable, вам нужно только реализовать Renderer и модель. SetIconAt должен вызывать только setValueAt и помещать ваш URL-адрес в столбец, а средство визуализации позаботится обо всем остальном.