Обновление 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-адрес в столбец, а средство визуализации позаботится обо всем остальном.

Другие вопросы по тегам