整个事情开始于TableModel
实现,让我们看一下:
public class VehicleTableModel extends AbstractTableModel {
private ArrayList<Vehicle> vehicles;
// Most of your code here, didn't examine it closer though
public void addRow(Vehicle vehicle) {
int rowIndex = vehicles.size();
vehicles.add(vehicle);
fireTableRowsInserted(rowIndex, rowIndex); // just notify last row == vehicles.size() == getRowCount()
}
public void removeRow(int row) {
vehicles.remove(row);
fireTableRowsDeleted(row, row); // is right? yes, it looks ok.
}
@Override
public void setValueAt(Object value, int row, int col) {
Vehicle v = vehicles.get(row);
if (v != null) {
COLUMNS column = header[col];
switch (column) {
case TARGA_COLUMN:...; break;
case MARCA_COLUMN:...; break;
// others...
}
fireTableCellUpdated(row, column); // this is the appropriate fire method.
}
}
/**
* Convenience method to notify if a vehicle was updated in
* the outside, not through setValueAt(...).
*/
public void notifyVehicleUpdated(Vehicle vehicle) {
Vehicle[] elements = (Vehicles[])vehicles.toArray();
for (int i = 0; i < elements.length; i++) {
if (elements[i] == vehicle) {
fireTableRowsUpdated(i, i);
}
}
}
}
其他一些提示:
Never use repaint()
nor updateUI()
刷新表的数据。表模型有责任通知视图有关正确的事件。
Never use fireTableDataChanged()
(正如有人建议的那样)除非whole表模型数据已更改。有合适的fireXxxx()
行、列和单元格的方法发生变化。
据我了解这个问题,两个表共享车辆列表,因此你必须保持它们同步。如果是这样,我想知道为什么需要两种不同的桌子模型?如果唯一的原因是可用/停放状态(互斥),那么您可以在两个表中共享一个表模型,并根据车辆的状态应用不同的过滤器。在状态字段更新时,两个表都将收到通知,并且车辆将被转入从一张桌子到另一张桌子。
Update
前段时间在评论里这个答案 https://stackoverflow.com/a/25536638/1795530添加一个方法的想法,例如notifyRowUpdated()
to Coordinator
抽象类似乎适合解决两个表之间的同步问题。
但现在我认为最好的方法是与两个表共享相同的表模型,并根据车辆的状态过滤第二个表:如果可用(DISPONIBILE)则显示它,如果不可用则隐藏它。
这样,在行更新和行删除时,两个表都会收到通知并采取相应的操作。在单元格更新时,我们可以向模型添加一个 TableModelListener,该模型在第二个表上应用过滤器,显示可用车辆并隐藏不可用车辆。更不用说Coordinator
抽象类将保持简单并保持其原始目的:通知第三方代理行更新/删除。
因此,请查看下面的代码示例(抱歉扩展)。一些注意事项:
- 我已经效仿你的
Vehicle
与一个更简单的类。状态由可用的布尔属性定义。
-
DataObjectTableModel
代码可在表格模型 /questions/tagged/tablemodel tag wiki https://stackoverflow.com/tags/tablemodel/info我已经使用此类来模拟您的表模型。
- 因为我没有任何
Coordinator
I 类直接在表模型上添加/删除行,但您应该通过适当的协调器来执行此操作。
- 不知道为什么我们必须对表格单元格更新事件重新应用过滤器。据我了解,应该通知表行排序器并自动应用过滤器。然而它并不能以这种方式工作,我们必须手动重新应用 Fitlers。不过是小问题。
代码示例
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultRowSorter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableColumnModel;
public class DemoSharedTableModel {
private DataObjectTableModel<Vehicle> model;
private JTable table1, table2;
private Action addAction, removeAction;
private void createAndShowGui() {
String[] columnIdentifiers = new String[] {
"Plates",
"Description",
"Available"
};
model = new DataObjectTableModel<Vehicle>(Arrays.asList(columnIdentifiers)) {
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
case 1: return String.class;
case 2: return Boolean.class;
}
return super.getColumnClass(columnIndex);
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex == 2;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Vehicle vehicle = getDataObject(rowIndex);
switch (columnIndex) {
case 0 : return vehicle.getPlates();
case 1: return vehicle.getDescription();
case 2: return vehicle.isAvailable();
default: throw new ArrayIndexOutOfBoundsException(columnIndex);
}
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex == 2) {
Vehicle vehicle = getDataObject(rowIndex);
vehicle.setAvailable((Boolean)aValue);
fireTableCellUpdated(rowIndex, columnIndex);
} else {
throw new UnsupportedOperationException("Unsupported for column " + columnIndex);
}
}
};
model.addRow(new Vehicle("AAA1", "Car - Peugeot", true));
model.addRow(new Vehicle("AAA2", "Truck - Volvo", true));
model.addRow(new Vehicle("AAA3", "Car - Ford", false));
model.addRow(new Vehicle("AAA4", "Car - Mercedes-Benz", false));
model.addRow(new Vehicle("AAA5", "Car - Ferrari", true));
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
if (e.getType() == TableModelEvent.UPDATE) {
DemoSharedTableModel.this.applyFilterOnSecondTable();
}
}
});
table1 = new JTable(model);
table1.setAutoCreateRowSorter(true);
table1.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table2 = new JTable(model);
table2.setAutoCreateRowSorter(true);
table2.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// Make third column not visible
TableColumnModel columnModel = table2.getColumnModel();
columnModel.removeColumn(columnModel.getColumn(2));
applyFilterOnSecondTable();
addAction = new AbstractAction("+") {
@Override
public void actionPerformed(ActionEvent e) {
model.addRow(new Vehicle("new", "default text", true));
}
};
removeAction = new AbstractAction("-") {
@Override
public void actionPerformed(ActionEvent e) {
int viewIndex = table1.getSelectedRow();
if (viewIndex != -1) {
int modelIndex = table1.convertRowIndexToModel(viewIndex);
model.deleteRow(modelIndex);
}
setEnabled(model.getRowCount() > 0);
}
};
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(new JButton(addAction));
buttonsPanel.add(new JButton(removeAction));
JPanel content = new JPanel(new BorderLayout(8, 8));
content.add(new JScrollPane(table1), BorderLayout.WEST);
content.add(buttonsPanel, BorderLayout.CENTER);
content.add(new JScrollPane(table2), BorderLayout.EAST);
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(content);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void applyFilterOnSecondTable() {
DefaultRowSorter sorter = (DefaultRowSorter)table2.getRowSorter();
sorter.setRowFilter(new RowFilter() {
@Override
public boolean include(RowFilter.Entry entry) {
Vehicle vehicle = model.getDataObject((Integer)entry.getIdentifier());
return vehicle.isAvailable();
}
});
}
class Vehicle {
private String plates, description;
private Boolean available;
public Vehicle(String plates, String description, Boolean available) {
this.plates = plates;
this.description = description;
this.available = available;
}
public String getPlates() {
return plates;
}
public void setPlates(String plates) {
this.plates = plates;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Boolean isAvailable() {
return available;
}
public void setAvailable(Boolean available) {
this.available = available;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new DemoSharedTableModel().createAndShowGui();
}
});
}
}
截屏
请注意,第二个表中仅显示可用车辆。