Лучший способ отобразить компоненты в JTable? - PullRequest
4 голосов
/ 16 февраля 2012

Я не спрашиваю, КАК отображать Компонент в JTable, так как в Интернете есть несколько уроков и примеров.Тем не менее, я хочу знать, как ЛУЧШИЙ способ это сделать.

Например, в большинстве учебников, с которыми я сталкиваюсь, есть примеры, которые создают отдельные классы (Главный класс, который расширяет JTable, на этомрасширяет TableModel, расширяет TableCellRenderer и так далее).Однако я обнаружил, что вы можете сделать это не только в одном классе, но и в одном методе, просто используя следующее:

Пример кода (SSCCE)


Main

public class Main
{
  public static void main(String[] args)
  {
    javax.swing.JFrame jf = new javax.swing.JFrame("A table with components");
    jf.setLayout(new java.awt.BorderLayout());
    jf.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
    jf.add(new TableWithCompsPanel(), java.awt.BorderLayout.CENTER);
    jf.setVisible(true);
  }
}

TableWithComps

public class TableWithCompsPanel extends java.awt.Container
{
  private Class<?> tableColumnClassArray[];
  private javax.swing.JTable jTableWithComps;
  private Object tableContentsArray[][];

  public TableWithCompsPanel()
  {
    tableContentsArray = new Object[][]
      {
        {"This is plain text",                                            new javax.swing.JButton("This is a button")    },
        {new javax.swing.JLabel("This is an improperly rendered label!"), new javax.swing.JCheckBox("This is a checkbox")}
      };
    tableColumnClassArray = new Class<?>[]{String.class, java.awt.Component.class};
    initGUI();
  }

  private void initGUI()
  {
    setLayout(new java.awt.BorderLayout());
    jTableWithComps = new javax.swing.JTable(new javax.swing.table.AbstractTableModel()
      {
        @Override public int getRowCount()
        {
          return tableContentsArray.length;
        }

        @Override public int getColumnCount()
        {
          return tableContentsArray[0].length;
        }

        @Override public Object getValueAt(int rowIndex, int columnIndex)
        {
          return tableContentsArray[rowIndex][columnIndex];
        }

        @Override public Class<?> getColumnClass(int columnIndex)
        {
          return tableColumnClassArray[columnIndex];
        }
      });
    jTableWithComps.setDefaultRenderer(java.awt.Component.class, new javax.swing.table.TableCellRenderer()
    {
      @Override public java.awt.Component getTableCellRendererComponent(javax.swing.JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
      {
        return value instanceof java.awt.Component ? (java.awt.Component)value : new javax.swing.table.DefaultTableCellRenderer();
      }
    });
    add(jTableWithComps, java.awt.BorderLayout.CENTER);
  }
}

Вопрос


Мне интересно, что , если это может бытьВ столь коротком объеме кода, почему изо всех сил стараются разделить его на три, а иногда даже больше, классов?Является ли мой код как-то менее эффективным во время выполнения? Я понимаю, как разделить основной класс и класс, в котором есть пример графического интерфейса пользователя, но не то, почему вы должны разделить пример графического интерфейса пользователя на несколько классов.

Edit: Я вижу множество людей, дающих веские причины, почему этот код нецелесообразен.Буду признателен за ваши ответы больше, если вы предоставили альтернативу!

Ответы [ 4 ]

5 голосов
/ 16 февраля 2012

TableModel моделирует данные, которые вы хотите отслеживать, самым простым способом из соображений эффективности использования памяти. TableCellRenderer определяет способ отображения этих данных в ячейке таблицы.

В вашем примере с флажком iTunes самый простой способ смоделировать информацию из флажка - это логическое значение (true / false). Хранение коллекции из 10 000 boolean объектов намного эффективнее, чем 10 000 JCheckBox объектов.

Затем TableCellRenderer может хранить один объект JCheckBox, и когда его просят использовать компонент для рисования ячейки, он может установить / снять флажок в зависимости от значения и каждый раз возвращать один и тот же компонент. , Таким образом, вы не будете создавать тысячи компонентов пользовательского интерфейса снова и снова, пока пользователь прокручивает таблицу.

3 голосов
/ 16 февраля 2012

В общем, разделение во многих взаимодействующих компонентах связано с дизайном. Этот дизайн пытается применять хорошие принципы, такие как разделение интересов. Вы можете создать одну большую вещь, которая делает все или идентифицировать меньшие части, каждая из которых отвечает. В последнем случае ваш код больше подходит для изменений, потому что каждый класс делает только одну вещь и много времени меняет, подразумевает касание одной или двух обязанностей без нарушения общей архитектуры решения.

В частности, Swing применяет шаблон MVC, который немного многословен, но пытается понять много хороших принципов проектирования. Я понимаю, что это не всегда самая простая вещь для поддержания, но я должен признать, что ответственность очень отделена.

Образцы могут быть короткими. Но они должны придерживаться философии и архитектуры Swing. Вот почему они выполняют те же роли независимо от размера кода.

Основное правило для этого (ИМХО) - найти для каждого деления причину, по которой было сделано деление.

Производительность: не беспокойтесь, если ваш код разбит на несколько классов. Это не влияет на производительность. Другая вещь (например, сложность времени) делает. Или, может быть, некорректное использование компонентов, но если все используется как задумано все будет хорошо.

Редактировать: надеюсь, что этот ответ полезен! Как видите, он вообще не ориентирован на качели ...

2 голосов
/ 16 февраля 2012

Что нужно учитывать:

  • Из вашего примера видно, что значение ячейки является Компонентом.Разве это не собирается занимать огромную память для каждой нетривиальной таблицы?
  • Правильно ли рисует компонент, когда, например, строка выбрана, находится в фокусе и т. Д.могут возникнуть проблемы с редактированием ячейки.
1 голос
/ 16 февраля 2012
  1. Renderer только для визуального оформления содержимого ячейки, например, setFont, setForeground, setBackground, isEnable, isVisible и т. д.

  2. Не создавать, устанавливать, изменять JComponents тип в Renderer во время выполнения; это работа для TableModel.

  3. Если возможно, используйте DefaultTableModel и используйте существующие средства визуализации для типов, известных JTable .

  4. Вы знаете, какой тип из Object/JComponent присутствует / присутствует в ячейке JTable.

...