Concepts / Modifying Table Models

Modifying Table Models

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

A Guess Before the Edit

A table on screen looks like the thing that holds your data, but it is only the part that draws the data. When a program needs to change what the user sees, it changes the data behind the table, and the table redraws itself to match. This article follows that path step by step, so that when a table shows something unexpected you know exactly where to look.

What do you think happens?

A DefaultTableModel has 4 rows. You call setValueAt(null, 2, 1). How many rows does the table have afterward?

  • 3

  • 4

  • It depends on the column class

Reveal answer
Answer:

4

Setting a cell to null only empties that one cell. The source says the cell becomes empty, and empty is different from deleted. The row still exists, so the table still has 4 rows. Only removeRow takes a whole row out.

Where the Data Lives

A JTable does not own the data it displays. The data lives in a table model, and DefaultTableModel is the standard model that provides methods for changing it. The table is the view: it reads from the model and draws what it finds there. Because of this split, the place where you make a change matters more than the code that draws the change.

You call the change 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. The model is the single place where data changes, and the view follows it.

My codeDefaultTableModelholds the dataJTabledraws the datacalls setValueAt, addRow, or removeRowview updates automatically
When my code calls setValueAt or addRow, which object holds the data, which object draws it, and how does the change travel from one to the other?
Key point

Edit the model, never the drawn table. The table displays whatever the model currently holds, so a correct edit to the model is the only edit you need.

Three Methods That Change the Model

Three methods on DefaultTableModel do most of the work. Each one changes the stored data in a specific way, and each has a different effect on the number of rows. The subsections below take them one at a time.

Tracing a Small Table Edit

The following small program builds a model with two columns, adds two rows, changes one cell, and then removes the first row. The code is an original teaching example written to use the three methods described in the source. Read it once, then follow it with the worked example below.

Code walkthrough
DefaultTableModel model = new DefaultTableModel(new Object[]{"Name", "Score"}, 0);
model.addRow(new Object[]{"Ana", 90});
model.addRow(new Object[]{"Ben", 75});
model.setValueAt(82, 1, 1);
model.removeRow(0);
  1. 1
    Line 1 creates the model that holds the data. The table that displays it would be attached to this model.
  2. 2
    Line 2 appends a row at the end of the table. Ana is now at row index 0.
  3. 3
    Line 3 appends Ben at row index 1.
  4. 4
    Line 4 changes only one cell, the score in row 1. No row is added or removed.
  5. 5
    Line 5 deletes the whole row at index 0. Ben, who was at index 1, moves up to index 0 because the rows below a removed row shift up.
  • Creates a model with two columns and zero rows to start
  • addRow appends Ana at index 0
  • addRow appends Ben at index 1
  • setValueAt replaces the score in row 1, column 1 only
  • removeRow deletes row 0, which is Ana; Ben moves up to index 0
Worked example

Tracking a Four-Row Table Through Three Edits

The model starts with four rows: Ana, Ben, Cara, and Dev in column 0, with scores in column 1. Apply these changes in order: clear Cara's score with setValueAt(null, 2, 1), remove row 1 with removeRow(1), then append Eli with score 88 using addRow. What does the table hold at the end?

  1. 1
    Start state

    Four rows exist at indexes 0 to 3: Ana at 0, Ben at 1, Cara at 2, Dev at 3.

  2. 2
    setValueAt(null, 2, 1)

    Only Cara's score cell is replaced with null, so it becomes empty. Cara's row still exists, and the table still has four rows.

  3. 3
    removeRow(1)

    Row 1 is Ben, so Ben's whole row is deleted. Cara and Dev each move up one index: Cara is now at 1 and Dev is now at 2. The table has three rows.

  4. 4
    addRow with Eli and 88

    The new row is appended after the last existing row, so Eli takes index 3. Existing rows do not move.

Result

Four rows: Ana at 0, Cara at 1 with an empty score, Dev at 2, and Eli at 3 with score 88. Ben is gone.

Why Row Indexes Shift After removeRow

After removeRow deletes a row, the rows below it take up the vacated positions. The row numbers you used before the deletion no longer refer to the same data. In the worked example, Cara was at index 2 before Ben was removed, and at index 1 afterward. Any code that stored the number 2 and reused it after the removal would now be reading Dev's row, not Cara's. This is why a stale index can point to the wrong data even though nothing in the code looks wrong.

How getColumnClass Chooses Cell Behavior

The table does not guess what kind of data a column holds by looking at the values in its cells. For each column, it calls getColumnClass and uses the class that the method returns to decide how to display and edit that column's items. The decision depends entirely on what the method returns for that column number, which is why the return value is worth tracing.

The source gives two documented consequences of 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 does not list every possible class and its appearance, so this article treats these two as the documented cases.

Column needsbehaviorCall getColumnClassone call per columnReturnsBoolean.class?Check boxesdisplayed and editedNumeric class?Illegal input refusedOther classesnot covered in this sourcefor each columnuse the return valueyesnoyesno
If getColumnClass returns Boolean.class instead of String.class for a column, how does that change the cell I see and the editor I get when I double-click it?
Key point

Changing the data does not change the column class. If a column's cells look wrong, first confirm what getColumnClass returns for that column, because that return value is what the table uses to choose its display and editing behavior.

Mistakes When Changing Table Models

  • Common mistake

    Using null when the row should disappear

    What it looks like
    model.setValueAt(null, 1, 0) expecting Ben's row to vanish
    Why it fails

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

    Do this instead

    Use model.removeRow(1) to delete the whole row.

  • Common mistake

    Writing separate code to redraw the table after each edit

    Why it fails

    The source states that the view is automatically updated when the model changes, so extra redraw code is not needed to show the change.

    Do this instead

    Make the change on the model and let the table follow it.

  • Common mistake

    Reusing a row index after removing a row above it

    What it looks like

    Storing Cara's index as 2, calling removeRow(1), then calling setValueAt on row 2

    Why it fails

    After removeRow(1), Cara moved to index 1 and Dev is at index 2, so row 2 now refers to Dev.

    Do this instead

    Look up the row again after a removal, or update any stored index when rows move.

  • Common mistake

    Assuming the column class is inferred from the values

    Why it fails

    The source says the table calls getColumnClass and uses its return value. It does not inspect the cells to decide.

    Do this instead

    Check what getColumnClass returns for that column number.

Tracing a Misbehaving Cell

When a table displays or edits incorrectly, the source recommends three checks in a fixed order. This order follows the path the data takes, so you can find the point where the result diverged from what you expected.

  1. 1
    Check the model first: did the setValueAt, removeRow, or addRow call change the data you thought it changed? Confirm the row and column numbers, because a wrong index writes to the wrong cell.
  2. 2
    Check the column class next: what does getColumnClass return for the column that misbehaves? A Boolean return gives check boxes, and a numeric return refuses illegal typed input.
  3. 3
    Check JTable customization last: has the table's default editor or renderer been changed? The source points to the JTable methods setDefaultEditor and setDefaultRenderer for this, and it names them without showing their full signatures, so consult the Java documentation for their exact use.

Practice: Predicting the Table State

MEDIUM

A model has three rows: Ana, Ben, and Cara. Predict the table after these calls, in order: model.removeRow(0); then model.setValueAt(null, 1, 1); then model.addRow(new Object[]{"Dev", 60}). Write down the row count and the row at each index before you check your answer against the worked example above.

Hints
  • removeRow deletes the whole row, and the rows below it move up by one index.
  • After removeRow(0), the rows are Ben at 0 and Cara at 1, so the next call targets row 1 which is Cara.
  • addRow always appends at the end, so Dev takes the next free index.

Key Takeaways

  • A JTable displays data from a table model. You change what the user sees by calling setValueAt, addRow, or removeRow on the model, and the view updates automatically.
  • setValueAt replaces one cell and keeps the row count. Passing null empties that cell but keeps the row. removeRow deletes a whole row, and the rows below it shift up. 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. A Boolean class gives check boxes, and numeric classes refuse illegal input.
  • When a cell misbehaves, check the model first, then the column class, then whether JTable's default editor or renderer has been customized.