2015-01-20 3 views
0

Я разрабатываю простое Java-приложение, которое использует JTable. Я пытаюсь реализовать то, что я видел here. Таблица в приведенной ссылке имеет то же, что и в моей таблице. Я сделал именно то, что показано на ссылке. Однако, когда я запускаю свое приложение, я не могу редактировать третий и последний столбцы. Поведение, которое я хочу, заключается в том, что приложение должно добавить пустую строку, когда пользователь нажимает Enter после заполнения последнего столбца в таблице.Интерактивный JTable

Вот мой первый класс, класс объектов:

public class Product { 
String productDescription; 
String productCode; 
double productPrice; 
//dummy properties 
int productQuantity; 
double productTotalAmount; 

public Product() { 
    this.productDescription = ""; 
    this.productCode = ""; 
    this.productPrice = 0; 
    this.productTotalAmount = 0; 
    this.productQuantity = 0; 
} 

public int getProductQuantity() { 
    return productQuantity; 
} 

public void setProductQuantity(int productQuantity) { 
    this.productQuantity = productQuantity; 
} 

public double getProductTotalAmount() { 
    return productTotalAmount; 
} 

public void setProductTotalAmount(double productTotalAmount) { 
    this.productTotalAmount = productTotalAmount; 
} 

public String getProductDescription() { 
    return productDescription; 
} 

public void setProductDescription(String productDescription) { 
    this.productDescription = productDescription; 
} 

public String getProductCode() { 
    return productCode; 
} 

public void setProductCode(String productCode) { 
    this.productCode = productCode; 
} 

public double getProductPrice() { 
    return productPrice; 
} 

public void setProductPrice(double productPrice) { 
    this.productPrice = productPrice; 
}} 

Вот мой второй класс, табличная модель:

public class InteractiveTableModel extends AbstractTableModel{ 

// indexes 
public static final int PRODUCT_DESCRIPTION_INDEX = 0; 
public static final int PRODUCT_CODE_INDEX = 1; 
public static final int PRODUCT_PRICE_INDEX = 2; 
public static final int PRODUCT_QUANTITY_INDEX=3; 
public static final int PRODUCT_TOTAL_AMOUNT_INDEX=4; 
public static final int HIDDEN_INDEX = 5; 

protected String [] columnNames; 
protected Vector dataVector; 

    //this constructor is responsible for initializing the columnmanes and the data of the table. 
public InteractiveTableModel(String[] columnNames) { 
    this.columnNames = columnNames; 
    dataVector = new Vector(); 
} 


@Override 
//this method returns the name of the column corresponding to the passed integer. 
public String getColumnName(int column) { 
    return columnNames[column]; 
} 

    //this method is used to determine whether a cell is editable 
//this is for manuvouring to the next editable cell 
@Override 

public boolean isCellEditable(int row, int column) { 
    if (column == HIDDEN_INDEX) return false; 
    else return true; 
} 

@Override 
     public Class getColumnClass(int column) {// returns a class representing the datatype of the data stored in that column 
    switch (column) { 
     case PRODUCT_DESCRIPTION_INDEX: 
     case PRODUCT_CODE_INDEX: 
      return String.class; 
     case PRODUCT_QUANTITY_INDEX: 
      return Integer.class; 
     case PRODUCT_PRICE_INDEX: 
     case PRODUCT_TOTAL_AMOUNT_INDEX: 
      return double.class; 
     default: 
      return Object.class; 
    } 
} 

@Override 
public int getRowCount() { 
     return dataVector.size(); 
} 

@Override 
public int getColumnCount() { 
return columnNames.length; 
} 

@Override 
public Object getValueAt(int row, int column) { 
    Product record = (Product)dataVector.get(row);//this will return a row in a vector 
    //this is cast to AudioRecord so that we can extract the data that we want correspoinding to column number 
    switch (column) { 
     case PRODUCT_DESCRIPTION_INDEX: 
      return record.getProductDescription(); 
     case PRODUCT_CODE_INDEX: 
      return record.getProductCode(); 
     case PRODUCT_PRICE_INDEX: 
      return record.getProductPrice(); 
     case PRODUCT_TOTAL_AMOUNT_INDEX: 
      return record.getProductTotalAmount(); 
     case PRODUCT_QUANTITY_INDEX: 
      return record.getProductQuantity(); 
     default: 
      return new Object(); 
    } 
} 

     //setting data in a cell 
@Override 
public void setValueAt(Object value, int row, int column) { 
    Product record = (Product)dataVector.get(row); 
    switch (column) { 
     case PRODUCT_DESCRIPTION_INDEX: 
      record.setProductDescription((String)value); 
      break; 
     case PRODUCT_CODE_INDEX: 
      record.setProductCode((String)value); 
      break; 
     case PRODUCT_PRICE_INDEX: 
      record.setProductPrice((Double)value); 
      break; 
     case PRODUCT_QUANTITY_INDEX: 
      record.setProductQuantity((Integer)value); 
      break; 
      case PRODUCT_TOTAL_AMOUNT_INDEX: 
      record.setProductTotalAmount((Double)value); 
       break; 
     default: 
      System.out.println("invalid index"); 
    } 
    fireTableCellUpdated(row, column);//this is for updating the cell 
} 


public boolean hasEmptyRow() { 
    if (dataVector.isEmpty()) return false; 
    Product productRecord = (Product)dataVector.get(dataVector.size() - 1); 
    if (productRecord.getProductDescription().trim().equals("") && 
     productRecord.getProductCode().trim().equals("") && 
     (productRecord.getProductPrice()!=1 && 
     productRecord.getProductQuantity()!=1 && 
      productRecord.getProductTotalAmount()!=1)) 
    { 
     return true; 
    } 
    else return false; 
} 

public void addEmptyRow() { 
    dataVector.add(new Product()); 
    fireTableRowsInserted(
     dataVector.size() - 1, 
     dataVector.size() - 1); 
}} 

Последний класс выглядит следующим образом:

public final class InteractiveForm extends JPanel { 

public static final String[] columnNames = { 
    "Quantity", "Product Code", "Product Description", "Product Price","Product Quantity","" 
}; 

protected JTable table; 
protected JScrollPane scroller; 
protected InteractiveTableModel tableModel; 

public InteractiveForm() { 
    initComponent(); 
} 

public void initComponent() { 
    tableModel = new InteractiveTableModel(columnNames); 
    tableModel.addTableModelListener(new InteractiveForm.InteractiveTableModelListener()); 
    table = new JTable(); 
    table.setModel(tableModel); 
    table.setSurrendersFocusOnKeystroke(true); 
    if (!tableModel.hasEmptyRow()) { 
     tableModel.addEmptyRow(); 
    } 

    scroller = new javax.swing.JScrollPane(table); 
    table.setPreferredScrollableViewportSize(new java.awt.Dimension(500, 300)); 
    TableColumn hidden = table.getColumnModel().getColumn(InteractiveTableModel.HIDDEN_INDEX); 
    hidden.setMinWidth(2); 
    hidden.setPreferredWidth(2); 
    hidden.setMaxWidth(2); 
    hidden.setCellRenderer(new InteractiveRenderer(InteractiveTableModel.HIDDEN_INDEX)); 

    setLayout(new BorderLayout()); 
    add(scroller, BorderLayout.CENTER); 
} 


public void highlightLastRow(int row) { 
    int lastrow = tableModel.getRowCount();//return the number of rows - last row 
    if (row == lastrow - 1) { 
     table.setRowSelectionInterval(lastrow - 1, lastrow - 1); 
    } else { 
     table.setRowSelectionInterval(row + 1, row + 1); 
    } 

    table.setColumnSelectionInterval(0, 0);//setting it to the first column 
} 

class InteractiveRenderer extends DefaultTableCellRenderer { 
    protected int interactiveColumn; 

    public InteractiveRenderer(int interactiveColumn) { 
     this.interactiveColumn = interactiveColumn; 
    } 

    @Override 
    public Component getTableCellRendererComponent(JTable table, 
     Object value, boolean isSelected, boolean hasFocus, int row, 
     int column) 
    { 
     Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 
     if (column == interactiveColumn && hasFocus) { 
      if ((InteractiveForm.this.tableModel.getRowCount() - 1) == row && 
       !InteractiveForm.this.tableModel.hasEmptyRow()) 
      { 
       InteractiveForm.this.tableModel.addEmptyRow();//this is where we append a new row 
      } 

      highlightLastRow(row);//making it get focus and highlighted 
     } 

     return c;//returning the component 
    } 
} 

public class InteractiveTableModelListener implements TableModelListener { 
    @Override 
    public void tableChanged(TableModelEvent evt) { 
     if (evt.getType() == TableModelEvent.UPDATE) { 
      int column = evt.getColumn(); 
      int row = evt.getFirstRow(); 
      System.out.println("row: " + row + " column: " + column); 
      table.setColumnSelectionInterval(column + 1, column + 1); 
      table.setRowSelectionInterval(row, row); 
     } 
    } 
} 

public static void main(String[] args) { 
    try { 
     UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); 
     JFrame frame = new JFrame("Interactive Form"); 
     frame.addWindowListener(new WindowAdapter() { 
      @Override 
      public void windowClosing(WindowEvent evt) { 
       System.exit(0); 
      } 
     }); 
     frame.getContentPane().add(new InteractiveForm()); 
     frame.pack(); 
     frame.setVisible(true); 
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException | HeadlessException e) { 
    } 
}} 

Единственные различия, которые я сделал из таблицы по ссылке выше, это добавить свой собственный v которые не должны заставить его не работать. Логика убегает от меня здесь.

Как я могу заставить свою таблицу вести себя так же, как this one?

+0

Ну, с этой точки зрения, это не ячейка, которая несет ответственность за изменение модели, это действительно плохая идея, для этого вам нужно будет углубиться в модели привязки клавиш и выбора ячейки/строки. – MadProgrammer

+0

@MadProgrammer Как сделать Я использую модели привязки клавиш и ячейки/строки? Примеры кода и ссылок были бы полезны – JWizard

+1

Проведите поиск «Как использовать привязки клавиш», пока моя дочь не решит заснуть, это все, что я могу сделать – MadProgrammer

ответ

2

Вы устанавливаете нулевые значения. Он работает нормально с Double.class, а не double.class.

public class Product { 
    String productDescription; 
    String productCode; 
    Double productPrice; 
    //dummy properties 
    Double productQuantity; 
    Double productTotalAmount; 
.. 
    @Override 
     public Class getColumnClass(int column) {// returns a class representing the datatype of the data stored in that column 
     switch (column) { 
      case PRODUCT_DESCRIPTION_INDEX: 
      case PRODUCT_CODE_INDEX: 
       return String.class; 
      case PRODUCT_QUANTITY_INDEX: 
      case PRODUCT_PRICE_INDEX: 
      case PRODUCT_TOTAL_AMOUNT_INDEX: 
       return Double.class; 
      default: 
       return Object.class; 
     } 
    } 
... 

UPDATE Что-то связано с бокса/распаковка. Я знаю, кто это исправить, но я до сих пор не знаю истинной причины.

+0

Там, обновление правильно – MadProgrammer

+0

@PbxMan Это сработало отлично !!! Но разве это не повлияет на мои данные в таблице, поскольку я хочу, чтобы моя таблица взяла парные разряды, целые числа и строки? Кроме того, не существует способа заставить его работать без преобразования моих типов данных в String? – JWizard

+0

@Giovanrich Кажется, вы можете. Проверьте обновление. Я до сих пор не знаю истинной причины. Я предполагаю, что это потому, что API не работает с примитивами только с объектами. Мне нужно было бы углубиться, чтобы ответить на это. – PbxMan

Смежные вопросы