Concepts / Customizing Table Editing and Display

Customizing Table Editing and Display

A table's data lives in a table model, and methods such as setValueAt, removeRow, and addRow change that data; the view updates automatically.

  • Programming

Where a Table's Data Really Lives

Before any theory, consider a small question. A table on screen shows rows and columns of values, and a user can click a cell and type into it. When that happens, what decides whether the typed text is accepted, displayed as a check box, or shown as plain text? The answer comes from a piece of Java that sits behind the table, not from the table's appearance.

Take a moment to make a guess. If a learner typed text into a cell in column 1, what would you expect the table to do? Keep your guess in mind. The rest of this article follows the mechanism that produces the answer, one state change at a time.

The Table Model Holds the Data

A JTable does not own the data it displays. The data lives in a table model, and the DefaultTableModel class is the standard model that provides methods for changing it. The JTable is the visible view of that model. Three DefaultTableModel methods do most of the work: setValueAt, removeRow, and addRow.

Key point

The important point is where you make the change. You call these methods on the model, not on the visible table. The source states that when you modify the model, the view is automatically updated to reflect the changes. You never write separate code to redraw the table after an edit.

Changing One Cell with setValueAt

The setValueAt method takes an item together with a row number and a column number, and it replaces the item in that one cell. Only the targeted cell changes. The other cells in the same row and the other rows are left as they were.

Setting a cell to null is a special case. The source says that if the item in a given cell is set to null, that cell will be empty. Empty is not the same as deleted. The row still exists, and only the value in that one cell is cleared.

Adding and Removing Whole Rows

The addRow method takes an array of items and appends a new row at the end of the table, filling the cells with the items in that array. The removeRow method takes a row number and deletes that entire row. Because removeRow deletes the whole row, the rows below it move up to fill the gap.

Row 0AnaRow 0AnaRow 1BenRow 1ChloeRow 2Chloeunchangedmoves up
After removeRow(1) deletes the row at index 1, Chloe moves from index 2 up to index 1 and the table no longer shows Ben at all.

The diagram above is a generated example that uses three names. Ben was at index 1 and Chloe at index 2. After removeRow(1), Ben is gone and Chloe is at index 1. Any code that refers to row numbers after a removal must account for this shift, because the same index now points to different data.

Empty Cells Versus Removed Rows

How getColumnClass Chooses Behavior

The table does not guess what kind of data a column holds by looking at the cells. Instead, it calls getColumnClass for each column and uses the returned class to decide how to display and edit that column's items. The decision therefore depends entirely on what the method returns for that column number. The table asks the question, and the return value is the answer it acts on.

Column 0NameColumn 1Boolean.classCheck boxesdisplay and editColumn 2Integer.classRejects illegal inputnumeric entryBoolean columnnumeric column
Each column index is passed to getColumnClass, and the class it returns determines how that column is displayed and edited. Column 1 returns Boolean and column 2 returns Integer in this generated example.

The source documents two behaviors that follow from the returned class. First, if a column is specified to hold Boolean values, its cells are displayed and edited as check boxes. Second, for numeric types, the table will not accept illegal input when the user types a value. The source gives these two as examples and does not list every possible class and its appearance, so treat these two as the documented cases.

A Table Model That Declares Column Classes

java
Notes on the code
  • getColumnClass is overridden so the table can ask which class each column holds
  • Column 1 returns Boolean.class, so its cells are shown as check boxes
  • Column 2 returns Integer.class, so numeric entry is checked
  • setValueAt replaces only the cell at row 0, column 0
  • setValueAt with null leaves row 0, column 2 empty while the row remains
  • addRow appends Chloe at the end of the model
  • removeRow(0) deletes the whole first row, so the remaining rows shift up
  • The JTable is created from the model and reflects these changes automatically

How a Change Travels from Model to Screen

Follow one change through the system. Your code calls a method on the model, such as setValueAt, addRow, or removeRow. The model's data changes. The JTable, which displays that model, reflects the change. The source says the view is updated automatically, so the path from model to screen requires no extra redraw code from you.

Your codecalls a model methodDefaultTableModeldata changes hereJTableview updates automaticallysetValueAt addRowremoveRowthe methods that changedatacallschangesview follows
A call on the DefaultTableModel changes the model's data, and the JTable displays that data without any separate redraw step written by the programmer.

Customizing Editors and Renderers

The column class is not the only way to change behavior. The source notes that it is possible to change the way a table edits or displays items, and it points to two methods in the JTable class: setDefaultEditor and setDefaultRenderer. The source names these methods and says they exist. It does not show their full signatures or code, so this article does not describe their parameters or usage beyond that.

Tracing a Result That Looks Wrong

When a table behaves differently from what you expected, work through three checks in a fixed order. This order follows the path the data takes, so you can locate the point where the result diverged.

  1. 1
    Check the model: did the setValueAt, removeRow, or addRow call change the data you thought it changed?
  2. 2
    Check the column class: what does getColumnClass return for the column that misbehaves?
  3. 3
    Check JTable customization: has the table's default editor or renderer been customized with setDefaultEditor or setDefaultRenderer?

Applying this order to the opening question: if a learner typed text into column 1 and that column's class is Boolean, the displayed cell is a check box, so the typed text does not appear as ordinary text. Reaching that conclusion requires checking the column class first, then the customization second.

Mistakes Beginners Make with Tables

  • Common mistake

    Editing the visible table and expecting the model to change

    What it looks like

    Changing a value through the view while assuming the model's stored data was updated

    Why it fails

    The JTable does not own the data. The data lives in the table model, and the model is where changes belong.

    Do this instead

    Call setValueAt, addRow, or removeRow on the DefaultTableModel.

  • Common mistake

    Writing code to redraw the table after every model change

    Why it fails

    The source states that the view is automatically updated when the model is modified.

    Do this instead

    Change the model and let the JTable reflect the change.

  • Common mistake

    Treating a null cell as a deleted row

    What it looks like

    Calling setValueAt with null on a cell and expecting the row to disappear

    Why it fails

    Setting a cell to null only empties that cell. The row still exists.

    Do this instead

    Use removeRow when the whole row should be taken out of the table.

  • Common mistake

    Using an old row number after removing a row

    What it looks like

    Calling removeRow(1) and then acting on the row that was at index 2 as if it had not moved

    Why it fails

    Rows below a removed row move up, so the same index now refers to different data.

    Do this instead

    Recheck which data sits at each index after any removeRow or addRow call.

  • Common mistake

    Assuming the cell type is determined by the value in the cell rather than by getColumnClass

Practice Tracing a Table

MEDIUM

A DefaultTableModel starts with three rows: Ana, Ben, and Chloe, in that order. Predict the state of the table after these calls: setValueAt(null, 1, 0) and then removeRow(0). Write down which name, if any, appears at each row index, and say whether any cell is merely empty. Then check your answer against the model-column-customization order from the previous section.

Hints
  • setValueAt with null only empties one cell, so the row count does not change at that step
  • removeRow(0) deletes the whole first row, and the remaining rows move up
  • Ask yourself which index holds which data after each call

Key Takeaways

  • A JTable displays data held by a table model, and changes made through DefaultTableModel methods such as setValueAt, addRow, and removeRow update the view automatically.
  • setValueAt replaces one cell, setting a cell to null leaves it empty, removeRow deletes a whole row, and addRow appends a new row at the end.
  • The table calls getColumnClass for each column and uses the returned class to decide how items are displayed and edited, such as Boolean columns shown as check boxes and numeric columns rejecting illegal input.
  • When a result looks wrong, check the model first, then the column class, then whether the JTable's default editor or renderer has been customized with setDefaultEditor or setDefaultRenderer.