Обновление ImageIcon ячейки JTable - PullRequest
1 голос
/ 19 января 2011

Я создаю свой первый 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 ]

3 голосов
/ 20 января 2011

Моя модель уже определена для возвращения 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;
    }
}
0 голосов
/ 20 января 2011

Я исправил это, изменив 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. Спасибо всем за понимание и помощь. Это сводило меня с ума!

0 голосов
/ 19 января 2011

Вызовите 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.class. Рендерер автоматически вызывается из JTable, вам не нужно расширять JTable, вам нужно только реализовать Renderer и модель. SetIconAt должен вызывать только setValueAt и помещать ваш URL-адрес в столбец, а средство визуализации позаботится обо всем остальном.

...