xaml grid control = JTable + GridBag

In Swing,

– JTable — is the most useful component.
– GridBag — is the most flexible, capable but sophisticated layout manager.

I feel WPF grid panel combines them.

I use grid for tabular data, like a jtable

I use grid for precise layout, like a gridbag.

Advertisements

default-default table cell renderer

System.out.println(System.identityHashCode(new JTable().getDefaultRenderer(Object.class)));

System.out.println(System.identityHashCode(new JTable().getDefaultRenderer(Object.class))); // different address

You can see each jtable has a default-default-default render instance. When I say default-default… I mean the renderer for Object.class.

Given this renderer instance is shared by all cells of the jtable, you can customise this instance to control the default appearance of many, many cells. This object is stateful — actually a subclass instance of JLabel.

target a custom cell renderer – laser precision

1) Most examples show how to install a renderer for a particular data type like Integer, but often I don't want to apply a highly customized renderer on all Integer columns

2) To customize for Column 2, use myTableColumn2.setCellRender(). You can do myTableColumn2 = table.getColumn(target column header name used as column identifier)

3) To specify a cell-specific renderer, you need to subclass and override getCellRenderer(int,int). For example, the following code makes the first cell in the first column of the table use a custom renderer:

TableCellRenderer weirdRenderer = new WeirdRenderer();

table = new JTable(…) {

public TableCellRenderer getCellRenderer(int row, int column) {

if ((row == 0) && (column == 0)) {

return weirdRenderer;

}

// else…

return super.getCellRenderer(row, column);

content of a TableColumn instance

Summary – a TC instance holds __presentation_settings__ (width, header value etc) for a particular column[1]. This instance remembers (via the this.modelIndex) which “physical” column the presentation settings apply, but this instance doesn’t know if it’s displayed as 1st or last column, or hidden.

Should be renamed ColumnDescriptor

[1] actually a column in the model, which might be excluded from the view, via the TCM.

— First look at the field listing —
* myTableColumn.modelIndex — The model index of the column “covered” by this TableColumn. As columns are moved around in the view or removed, modelIndex remains constant. As the #1 most important field in TableColumn.java, this is first parameter in every ctor except the no-arg.

* myTableColumn.cellRenderer
* myTableColumn.cellEditor

This is a useful but less explored feature —
* myTableColumn.identifier — with getter/setters. This object is not used internally by the drawing machinery of the JTable; identifiers may be set in the TableColumn as as an optional way to tag and locate table columns.

———–

Now we are ready to look at TableColumnModel. #1 job is to hold an ordered list of TableColumn’s. Order is the display order.

getColumns() — #1 method. Returns the ordered list. Underlies these methods
** TableColumn getColumn(int viewColumnIndex) — should be renamed getColumnDescriptor
** getColumnCount() — used by JTable.getColumnCount()

paging long JTable

<![CDATA[ /** * based on <> */ public class PagingTable extends JFrame { public static void main(String args[]) { final PagingTable frame = new PagingTable(); frame.setSize(300, 200); frame.getContentPane().add( PagingModel.createPagingScrollPaneForTable(new JTable( new PagingModel())), BorderLayout.CENTER); frame.setVisible(true); } } class Record { static String headers[] = { “Record Number”, “Batch Number”, “Reserved” }; static int counter; static long start_ = System.nanoTime(); String[] data; public Record() { data = new String[] { “” + (counter++), “” + (System.nanoTime() – start_), “Reserved” }; } public String getValueAt(int i) { return data[i]; } public static String getColumnName(int i) { return headers[i]; } public static int getColumnCount() { return headers.length; } } class PagingModel extends AbstractTableModel { protected int pageSize; protected int pageOffset; protected Record[] data; public PagingModel() { this(500, 100); } public PagingModel(int realRows, int size) { data = new Record[realRows]; pageSize = size; for (int i = 0; i < data.length; i++) data[i] = new Record(); } @Override public int getRowCount() { return pageSize; } @Override public int getColumnCount() { return Record.getColumnCount(); } // Only works on the visible part of the table @Override public Object getValueAt(int row, int col) { return data[row + (pageOffset * pageSize)].getValueAt(col); } @Override public String getColumnName(int col) { return Record.getColumnName(col); } // use this method to figure out which page you are on int getPageOffset() { return pageOffset; } int getTotalPages() { return (int) Math.ceil((double) data.length / pageSize); } void pageDown() { if (pageOffset 0) { pageOffset–; fireTableDataChanged(); } } // we’ll provide our own version of a scroll pane that includes // the page up and page down buttons by default. public static JScrollPane createPagingScrollPaneForTable(JTable jt) { final PagingModel model = (PagingModel) jt.getModel(); final JButton upButton = new JButton(“^”); upButton.setMargin(new Insets(0, 0, 0, 0)); upButton.setEnabled(false); // starts off at 0, so can’t go up final JButton downButton = new JButton(“v”); downButton.setMargin(new Insets(0, 0, 0, 0)); upButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { model.pageUp(); if (model.getPageOffset() == 0) upButton.setEnabled(false); else downButton.setEnabled(true); }//method }); downButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { model.pageDown(); // If we hit the bottom of the data, disable the down button if (model.getPageOffset() == (model.getTotalPages() – 1)) downButton.setEnabled(false); else upButton.setEnabled(true); }//method }); return new JScrollPane(jt) { { // Turn on the scrollbars; otherwise we won’t get our corners setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, upButton); setCorner(ScrollPaneConstants.LOWER_RIGHT_CORNER, downButton); } }; }//method }//class ]]>

each task instance in EventQueue has ptr to 1 listener

EventObject.java doesn’t contain a “handle” [2] on the listener INSTANCE, but look at an event-queue-task (“qtask”) in the Swing EventQueue.

EDT runs all callback methods (such as actionPerformed) sequentially [1]. So if a jtable and a jtree both listen to an event, EDT must execute the 2 callbacks sequentially.

Imagine 2 qtask INSTANCES are in EventQueue. It’s instructional to imagine a qtask having 3 handles
– on that one listener object, sometimes a jcomponent. See http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html
– on the event object, which provides a handle
– on the source object, perhaps a button or table cell

Note in our simple example one source object (button) generates one event (click) at a time. Given the source maintains 2 pointers to 2 listeners, that one event object must be “delivered to” 2 listeners — 1:2 mapping.

Now the English word “deliver-to” is nice but rather vague or (worse) misleading and can permanent damage some learner’s brain. Listener is unlike some jms client process capable of processing event. Instead, Listener is typically
– a stateful object (perhaps a jcomponent) holding a handle on some RESOURCE — DB, bunch of jcomponents..
– exposing a callback like actionPerformed()

So delivery-to means “EDT executing that non-static callback method on the listener instance, passing in the event object”. This is a crucial and non-trivial data-flow worth a hard look and analysis
* Business logic is in … the method source code;
* Data is passed via …. the event object and the event source
* Resources needed to handle the message are in ….. the listener object’s non-static fields

[1] even though a callback method may dispatch the task to a worker thread or back to EDT again – by invokeLater() i.e. packing up the task into a qtask and “enqueue” to the end of the event queue.

[2] basically a reference or pointer, but it’s good to use a generic term here.

A busy live mkt-data GUI table – realistic

1000 records are batched into each chunk and posted to event queue. Every chuck needs to be displayed on a “main” table. Killer is the re-sort/re-filter, which must happen on EDT. As a result, EDT is overwhelmed — when you re-size or move the app, it responds, but is sluggish and leaves an ugly trail.

My suggestions –
* Break up into smaller tables, so sorting is faster.
* Break up into smaller datasets. In fact most users are only interested in a subset of the live data.
* If sort (filter) is the killer….
… adopt a a sort-free JTable that efficiently accesses pre-sorted underlying data. Underlying data can be swapped in/out efficiently, and sorted on a “mirror-site” using another thread, possibly a swing worker. Take inspiration from the 2 GC survivor spaces and use 2 identical data structures. One live, the other used as a sort worktable. Swap (by pointer) and fire table event. However this increase memory consumption.

We also need to completely disable user-triggered sorts. Use a dialog box to educate users that changing sorting policy is non-trivial, and they should configure and install the new sorting policy and be prepared to wait a while to see its effect.

In general, you can only get any 2 of
E) cell editing
R) real time view of fast changing mkt data
C) full rather than subset of data streams

In mkt data streaming,  R alone is often enough — read-only view. Some users needs R+C. Some needs E+R

my own custom cell renderer-cum-editor — simple, light-weight

Note a single instance of text component is shared by all cells. The text component needs no long term memory. The existing text value is always overwritten by “value” when calling get*Component() methods. We only need its transient memory for getCellEditorValue().

Thread safety — object state i.e. text value is modified on EDT only.

Input validation — add document listeners — textComp.getDocument.addDocumentListener()

class CustomRenderer extends AbstractCellEditor /////// avoid DefaultCellEditor
implements TableCellRenderer, TableCellEditor {
JScrollPane scrollPane;
JTextComponent textComp;

public CustomRenderer() {
textComp = new JTextField(); ///////////// or text area
scrollPane = new JScrollPane(textComp); // if text area
}

public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row, int column) {
System.out.println(System.identityHashCode(textComp) + ” render (b) has — ” + textComp.getText());
textComp.setText((String) value);
System.out.println(System.identityHashCode(textComp) + ” render (a) has — ” + textComp.getText());
return scrollPane;
}

@Override
public Component getTableCellEditorComponent(
JTable table,
Object value,
boolean isSelected,
int row,
int column) {
System.out.println(System.identityHashCode(textComp) + ” editor (b) has — ” + textComp.getText());
textComp.setText((String) value);
System.out.println(System.identityHashCode(textComp) + ” editor (a) has — ” + textComp.getText());
return scrollPane;
}

@Override
public Object getCellEditorValue() {
return textComp.getText();
}
}

row sorter – swing fundamentals #my take

A row sorter instance holds
1) an all-important “row index” mapping, somewhat similar to the “col index” translator in TableColumnModel,
2) the list of sort keys

The row sorter updates the mapping whenever underlying content changes or sort key list changes. Javadoc says “RowSorter’s primary role is to provide a mapping between two coordinate systems: that of the view (for example a JTable) and that of the underlying data source, typically a model.

One sorter has multiple sort keys.
One sorter covers all the columns — all potential sort columns

public List getSortKeys() – returns the current sort key list
public setSortKeys()

RowSorter need to reference a TableModel. JTable also have a reference to the model. RowSorter should not install a listener on the model. Instead the view class will get model events, and then call into the RowSorter. For example, if a row is updated in a TableModel, JTable gets notified via the EDT event queue then invokes sorter.rowsUpdated(), which is a void method. The rowsUpdated() internally refreshes row sorter’s internal mapping. I believe after this method returns JTable would query row sorter to re-display the rows in the new order.

Because the view makes extensive use of the convertRowIndexToModel() and convertRowIndexToView(), these methods need to be fast.

When you click a header, mouse click handler calls into the sorter’s instance method toggleSortOrder() to
1) change sort key list,
2) then update internal mapping

JTable renderer to check old/new cell values then set color

I feel there are many broken designs, and a few working designs.

If the requirement is needed only upon user input (not during background update like MOM), then property change event or cell editor could probably pass old/new values to cell renderer.

But let’s assume the requirement is that all changes (by user or behind the scene) be covered. Now, how many ways can the underlying data change? Only 2 — Either by setValueAt() or by direct write to underlying. So I’d make underlying data structure (usually 2D) private and provide a setter as a single choke point. In this setter I would save old value into another 2D. Cell renderer has access to the jtable, so it can retrieve the table model, and access the other 2D.

Note you have to install your render as default for Integer.class (not Object.class) if the column is integer.

Note you must save the default background colour early. That color object is a field of the renderer instance. The same renderer instance is reused and persisted. Once you call renderer.setBackground(), that field is changed forever (and the previos color object unreachable), so you must save the before-value.

What if we force all updates to go through setValueAt(), including MOM updates? Heavy load on EDT given the high volume of MOM. Hard truth — Some updates to model must happen off EDT. However, fireXXX() must always run on EDT. [[java concurrency]] says “data  model  fireXxx  methods always call  the model listeners directly rather than submitting a new event to the event queue, so the fireXxx methods must be called only from the event thread.

use sortKeys AND custom comparator – JTable

After you create a TableRowSorter, you need to install your custom comparator first, before setting sort key list. Reversing the sequence breaks the correct behaviour, but I don’t know why.

If you use sort key list (like sort first by quote price, Then timestamp), you may want to keep the live table sorted that way forever. You need to disable mouse-click-sort on Any columns. Here’s one way to do it —

@Override
public final void toggleSortOrder(int column) {}//disabled

Mouse events are still generated, but when the event handler calls into toggleSortOrder() nothing happens.

keep a live JTable sorted/filtered, again

After updating an existing row, you need to fireTableDataChanged(). This loses user selection. It trigger a re-filter and re-sort. To keep user selection, try

fireTableRowsUpdated(0, getRowCount() – 1) // a broken alternative as it re-sorts and keeps user selection, but doesn’t trigger re-filter, so the updated row may fail to show/hide.

See other post on the performance implications of frequent sorting on a large live table.

every cell update event triggers getTableCellRendererComponent()

Note WPF is similar — PropertyChanged event is an invitation to “query ViewModel and display updates

If you use a swing timer to fire table update events, you will see, in log or debugger, that after every fireTableCellUpdated(a single cell), getTableCellRendererComponent() runs exactly once, on that single cell.

If you don’t use swing timer but use scheduleAtFixedRate() to call invokeLater(), which asynchronously calls fireTableCellUpdated(), you will see the same in the log file. However, debug session will likely show many fire() followed by a getTableCellRendererComponent(). This is illusion. It depends where you break-point — (Let’s say in both cases the event is scheduled to happen once a second. )

* If you break inside invokeLater’s Runnable.run(), you get confusing results. Scheduled tasks continue to call invokeLater() once a second, but your debug may suspend the EDT, so you might see many fire()
* If you break before invokeLater(), you should see one fire() followed by one getTableCellRendererComponent() — ABABABAB

No break point, then no surprise. Bottom line, each fire() is followed by a getTableCellRendererComponent() call. In plain English, after we fire each update event on a cell, that single “cell model” will get queried and rendered exactly once.

As in WPF, our code aren’t allowed to modify the visual component directly. Only way to effect a visual change is to update the model and fire events to invite “Hollywood” to requery the model and Notice the update.

pre1.6 jtable sorter – a simple impl

In a high-speed trading GUI, it’s not uncommon to have 2 tables showing the same live data, but in different sort orders. As data stream in, the 2 tables must auto-refresh (either periodically or event-driven).

This requires a separate-view-shared-model design. Whenever content of the model (object) is updated, the updater method would call myTableModel.fireXXX() on EDT. Since the 2 (JTable) views are always among the listeners of myTableModel, fireXXX() method always invokes the callback on each, sequentially, on EDT. When the callback event handler runs, it basically queries myTableModel and displays its content sorted. This could take many millisec on each table if content is huge. If you have 5 tables on myTableModel, the latency adds up. Use paging if necessary.

Don’t do the naïve sort — recreate a table model instance, and setModel(). This way the 2 views will show inconsistent data — detached.

Table sorting should not change the data, should change the presentation instead. Here’s one simple way to keep a live table (or two) sorted —

Provide a decorator class/object implementing TableModel. This is the object you put into mySortedJtable.setModel(). It holds a decoratee TableModel instance. As you query it via getValueAt(int,int), you go through a row index translator, which translates view-index to physical-index.

* Physical index is the row-index into decoratee.getValueAt(). The sequencing inside decoratee doesn’t change during sort
* view index is the row-index into this.getValueAt()

So when the table is re-drawn, this.getValueAt() gets called 22 times if there are 22 rows. First call (row 0) will hit physical-index 21 in a reverse sort.

This is enough to present a static content sorted. But our data is live. Every 2 seconds, or whenever MOM delivers new data, some method updates the underlying data structure inside decoratee. Now the view won’t show it. The same method would trigger (perhaps via invokeLater or timer event) a decorator.sort() and decorator.fireXXX(). The sort() would update the row-index translator. The fireXXX() would make the view query its model (i.e. decorator) via decorator.getValueAt().

TableModel fireXXX() skips event queue

Upon mouse click, hardware/OS pumps in a low-level event into EDT queue. After some delay the mouse event is picked up on EDT. The event is examined to get the source which is typically some jcomponent [1]. Then the list of listeners is examined. Each listener object’s mouseClicked() method is invoked sequentially on EDT.

However, in a TableModel’s fireXXX() method, the listener object’s [2] event handler method is invoked directly — on the same thread (as part of) fireXXX(), without pumping event into the queue.

Hold your breath — if you call fireXXX() on any non-EDT, the view (java + native screen objects) would be modified on that thread — disaster. Therefore TableModel should be modified only on EDT.

[1] remember when user clicks, there has to be some screen object she’s hitting.
[2] This object is the JTable instance, i.e. the view object. This object is __automatically__ registered as one of the listeners on the table model object. If the table model instance is a celebrity with a fan club, then JTable instance is her twin sister and the founding member of the fan club.

JTable sorter – mkt-data streaming tips

http://stackoverflow.com/questions/996948/live-sorting-of-jtable shows a subtle difference between

fireTableDataChanged(); // triggers re-sort, but ….loses current row selection 😦
fireTableRowsUpdated(0, getRowCount() – 1); // keeps selection 🙂

That’s all about the subtle difference. Here’s a separate issue.

Both of these send some kind of “update” events. To react to them, TableSorter source code reveals a special field —

private boolean sortsOnUpdates; // false by default, so updates to existing rows will NOT trigger re-sort.

http://stackoverflow.com/questions/996948/live-sorting-of-jtable shows a simple fix. This is all you need to add this powerful feature into your trading apps — keep a live table sorted

tableColumn, tableColumnModel, TableModel

(Outdated. See other posts on TCM.)
Actual Table data (like numbers and string values) are stored in the table model Instance, and should not be redundantly stored in another object such as JTable instance, TCM instance or TC instance. http://www.chka.de/swing/table/TableColumnModel.html points out —

A TableColumnModel Instance holds a bunch of TableColumn Instances, ordered like they are shown in a JTable — #1 job of TCM. You can verify this observation from method “TableColumn getColumn(int)” . The method getColumns(void) actually returns an Enumeration of TC instances.

The 2nd job of a TCM Instance is the listener list. These listeners listen to column-move (and similar) events, NOT table data change events.

(A TCM instance doesn’t hold actual table data.)

In a TC (TableColumn) instance, the most important information is the model index, i.e. which column in the TM is behind this TC instance. A TC Instance holds data fields controlling the appearance of a column. You can think of a TC Instance as a table_column_view object.

(Allow me to repeat — There’s no actual table data in a TC instance.)

workhorse methods of JTable + TableModel + TableColumnModel

Sooner or later you need to internalize these –

———–JT
set/getValueAt() — in both JT/TM, but different behavior

–editor/renderer
TableCellRenderer getCellRenderer(int row, int column)
int getEditingColumn/Row(void) — If nothing is being edited, returns -1
Component getEditorComponent(void) — If nothing is being edited, returns null

–related to table columns
getColumnCount() — JT/TCM identical, covering the View columns
TableColumnModel getColumnModel() — don’t use the createDefaultTableModel()

—less important ones
int getSelectedColumn/Row(void) Returns the index of the first selected column/row, -1 if no column is selected.
int[] getSelectedColumns/Rows() Returns the indices of all selected columns/rows.
convert[Column|Row]IndexToModel (int viewIndex)
convert[Column|Row]IndexToView (int modelIndex)

———–TM
getColumnCount() — different from the JT version. Covers the Model columns
set/getValueAt() — in both JT/TM, but different behavior
boolean isCellEditable(int, int)
addTableModelListener()

———–TCM
getColumn(int columnIndex)
getColumnCount() – JT/TCM identical
getColumnIndex(Object columnIdentifier)
removeColumn(TableColumn aColumn) — JT/TCM identical
moveColumn(int column, int targetColumn) — JT/TCM identical
addColumn(TableColumn aColumn) — JT/TCM similar

JTable update – upward^downward (editingStopped()

Upward — update table Model from SQL, MOM (mkt data), or timer (overwhelming mkt data), then fire events.
Downward — mouse/keyb — user editing a cell, then propagate to DB or other UI components.
(–> Here you see the threading issue.)

Q1: How many ways are there to read/write data in jtable?
%%A: i guess 1 — via the table model.

Q1b: is there a separate copy of the model data in the JTable instance?
%%A: i don’t think so.
A: My tests confirm that user edits directly hit the underlying table model (eg 2D array). See also P 449 [[java cookbook]].

   /** Invoked on EDT, when editing is finished.
     * @param  e  the event received
     */
JTable.editingStopped(ChangeEvent e) invokes on EDT —

JTable.getModel.setValueAt(). This method should be customized in your own table model. Your setValueAt() should modify your own data structure (2D array etc) and then fire events
     public void setValueAt(Object value, int row, int col) {
        data[row][col] = …
        fireTableDataChanged();
    }

tree model ^ table model

Tree model and table model are the 2 complex jcomponent models. Each adds a meaningful *structure* to an otherwise unorganized constellation of objects, a structure naturally suited to the target jcomponent.

1) If you stop and think of the typical kind of data organized into a jtable, it’s really a collection of ROWS. Each row contains a strictly ordered list of objects. Order is fixed, so is each data type — First object must be age, 2nd object must be gender … Therefore it’s logical and natural to use a collection of DOMAIN objects.

2) A jtree maps naturally to any hierarchical data. Interestingly, the TreeModel interface accepts any kind of object as a tree node and does not require that nodes be represented by DefaultMutableTreeNode, or even that nodes implement the TreeNode interface. If you have a pre-existing hierarchical data structure, you do not need to duplicate it or force it into the TreeNode mold. You just need to implement your tree model so that it uses the information in the existing data structure.

3) JTextComponent has a Document as its model

what DEFAULT means for JTable renderers

1) The “default” in getDefaultRenderer() means “class-based”. In each jtable, there’s at most ONE class-based renderer for each class. However, multiple classes (say Price column in double, and Qty column in integer) can share the same class-based renderer.

2) The “default” in DefaultTableCellRenderer.java doesn’t mean “class-based”. It means …. “render for all classes”, kind of render of last resort (Sounds like lender of last resort:)

1b) myjtable.getDefaultRenderer(Object.class) would normally return an instance of DefaultTableCellRenderer.java. This call looks up the class-based renderer for Object.java — the last-resort class-based renderer, which is typically DefaultTableCellRenderer.java.

table cell editor^renderer, briefly

Compared to TCR, TCE needs to do more events such as keyboard/mouse.

Customizing TCE is more work than TCR. TCR only requires you to override 1 method — getXXXComponent(). TCE needs a 2nd — getCellEditorValue(), which is invoked during the event handler stopCellEditing(). This getCellEditorValue() returns the value from the cell editor object, to be injected into setValueAt().

A customized TCR/TCE can both target a data type (like Boolean) or a particular TableColumn, which is most practical in trading.

when would table model data change show up (TableModel/EDT fusing)

Q: If on a non-EDT thread, such as a market data thread, I modify the table model beneath a “showing” (“realized”) jtable, say change text from “A” to “B”, but don’t repaint or fire table change event, when will my new text show up on screen?

A: never. I tested with a custom table model. The new text shows up only after I repaint or fire table event.

A: you must send an invitation to the EDT to re-query the table model and then repaint the visual, otherwise the visual will not update. Look at INotifyPropertyChanged in wpf.

A (from a veteran): For custom table model, we need to fire events, either cell change event or table data change event.
A (from a veteran, echoed on http://stackoverflow.com/questions/3179136/jtable-how-to-refresh-table-model-after-insert-delete-or-update-the-data): in some cases like default table model setValueAt()/addRow(), the event is fired automatically. I’d say the more common and standard procedure is to always fire events manually

Q: Will firing event involve repaint()?
A: not according to my debug test

Q: will firing the event trigger paint()?
A: yes according to my debug test. EDT runs paint().

Q2: is it safe for non-EDT thread to make state change on the table model object?
A: not sure. The only way to propagate the state change to the screen is via native screen object.
There are perhaps 4 (or more) objects involved:
– JTable instance (view-controller?)
– Model instance
– ?UI delegate object
– native screen object

We are modifying the model object, not the “real” object (whatever it is), so screen won’t update. UI delegate or native screen object are probably not directly accessible.

http://docs.oracle.com/javase/6/docs/api/javax/swing/package-summary.html#threading says “This restriction also applies to models attached to Swing components. For example, if a TableModel is attached to a JTable, the TableModel should only be modified on the event dispatching thread. If you modify the model on a separate thread you run the risk of exceptions and possible display corruption.” This seems to suggest that TableModel objects are modified by even handlers due to user actions or due to timers …

Q: when user edits a table cell, does the table model object change via an event callback or automatically without any event callback?
A: via Event callback, on EDT. My debug test show stopCellEditing(..) is invoked by Hollywood. This indirectly calls editingStopped(…), which calls setValueAt(..)

JTable vs database table

Logically and Implementation-wise, a Jtable consists of a small number of columns. In contrast, the jtable can contain unlimited rows. As an analogy, a couple can have a small number of kids, and unlimited number
of books. Adding a child is a big deal, just like adding a jtable column, just like adding a database table column. At the core and from the onset, jtable’s basic design and implementation resemble database tables.

In a typical business application, a database RECORD maps to an entity bean. A jtable displays an unlimited number of entity beans, each with a known number of attributes. Each attribute occupies a jtable/database column, therefore each jtable/database column has a data type, and a distinct meaning with a title. What if all the fields of the bean have the same meaning ….[1]?

In any GUI framework, if we create a UI component capable of manipulating a single column of data, resizing, editing, firing events … then we are 90% close to creating a table. Therefore, most of the capabilities of Jtable probably “come from” the column thingy, even though I’m not familiar with the TableColumn.java and
TableColumnModel.java classes.

Each column (not “each row”) has its data type, width, color, renderer(!), editor(!), position among other columns… It’s like a small kingdom within a large federation.

[1]A: Then the jtable is a grid.

telltail fields of JTable.java

Most people do not look at (they don’t need to) these protected fields, but these provide valuable insights into the internal contents of jtable.

int editingColumn — currently edited
int editingRow — currently edited
Component editorComp — If editing, the Component that is handling the editing.

Hashtable defaultEditorsByColumnClass
Hashtable defaultRenderersByColumnClass

–Now The big 3
TableModel dataModel
TableColumnModel columnModel
JTableHeader tableHeader

## swing – sources of events (brief list)

Swing supports semantic events and low-level events — http://tech.stolsvik.com/2009/03/awt-swing-event-pumping-and-targeting.html. Most of the “visible” events that litter our source code are semantic, so that’s the focus of most app-developer. However authors often include low-level events when “swing event” is mentioned in literature.

We mostly care about events on the EDT. Nothing stops a swing app from using any number of events on some independent thread unrelated to the EDT, but anything that affects the display must use EDT, unless the method is marked “thread-safe”. Here are some common sources of events.

– UI events — from mouse and keyboard. It’s possible to write many small swing apps with no other events than UI events.
– MOM events — A swing app often has MOM listeners that can fire events that affect the UI.
– timer events — Always en-queue to EDT. Often affects UI.
– property change events — example? See Action.java
– UI model change events — model is always, always attached to a UI component, so the change usually affects some UI. Additionally, a change can affect other UI components. Example? Say a table model should update jtable + some row-counter + background color to indicate new data in the jtable.k
** TableModel changes can occur due to user actions — P449 [[Java cookbook]]