Java TableViewer:实现选中单元格时切换单元格图片的技术问询
Since you're using JFace's TableViewer with a ColumnLabelProvider to show CHECKED/UNCHECKED icons in the third column, the key here is to follow JFace's model-driven approach: update the underlying data model first, then refresh the viewer to reflect the change in the UI.
Here are two standard, maintainable approaches to achieve this:
Approach 1: Use EditingSupport (Recommended, JFace Standard)
This integrates with the TableViewer's built-in editing framework, which supports accessibility, keyboard interactions, and aligns with JFace's best practices.
Step 1: Ensure your Person class has a setter for the married property
First, make sure your Person model can update the married state (this is critical for model-driven UI updates):
public class Person { private boolean married; // Existing getter public boolean isMarried() { return married; } // Add this setter to modify the state public void setMarried(boolean married) { this.married = married; } // Other properties and methods... }
Step 2: Implement the EditingSupport for the third column
Replace your incomplete col.setEditingSupport(new ...) with this full implementation:
col.setEditingSupport(new EditingSupport(tableViewer) { @Override protected boolean canEdit(Object element) { // Allow editing for all rows in this column return true; } @Override protected CellEditor getCellEditor(Object element) { // Use CheckboxCellEditor to handle toggle logic - your custom icon will still be the visible UI element // If you don't want the default checkbox to show, use a NullCellEditor instead (see note below) return new CheckboxCellEditor(tableViewer.getTable()); } @Override protected Object getValue(Object element) { // Sync the editor with the current model state return ((Person) element).isMarried(); } @Override protected void setValue(Object element, Object value) { // Update the model with the new toggled state boolean newMarriedState = (boolean) value; ((Person) element).setMarried(newMarriedState); // Refresh only the affected row to update the icon efficiently tableViewer.update(element, null); } });
Note: If you don't want the default checkbox from CheckboxCellEditor to be visible, replace it with a NullCellEditor (a minimal editor that triggers the edit flow without rendering anything). You'll still get the click-to-toggle behavior, and your custom icon will remain the only visible element.
Approach 2: Mouse Listener for Direct Click Handling
If you prefer a more lightweight approach without using the editing framework, add a mouse listener to detect clicks on the third column:
tableViewer.getTable().addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent e) { Table table = tableViewer.getTable(); // Get the clicked table item and column TableItem clickedItem = table.getItem(new Point(e.x, e.y)); if (clickedItem == null) return; TableColumn clickedColumn = table.getColumn(new Point(e.x, e.y)); if (clickedColumn == null) return; // Verify we're clicking the third column (index 3) if (clickedColumn.getIndex() == 3) { Person person = (Person) clickedItem.getData(); // Toggle the married state in the model person.setMarried(!person.isMarried()); // Refresh the row to update the icon tableViewer.update(person, null); } } });
Important Reminder
Always modify the data model first rather than directly changing UI elements (like swapping images manually). This keeps your code consistent, avoids UI-model desyncs, and follows JFace's core design principles. Using tableViewer.update(element, null) is far more efficient than refreshing the entire viewer, as it only updates the affected row.
内容的提问来源于stack exchange,提问作者J.Doe

