- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的 GUI 显示了我的公园中的车辆,以及我想在两个不同的 VehicleTables(扩展 JTable 的类)中设置可用的车辆).对于可用性,我打算通过代理(第三方软件)观察这些车辆。这两个表都在行中显示了车辆的描述...为此,我创建了 VehicleTableModel 和 Vehicle 类。Vehicle类是一个抽象类,他的子类有:Car、Truck、Trailer等。
您可以看到我的软件的快照:
我的问题是:在我当前的实现中,我不认为管理行的更新真的很好。您可以在 VehicleTableModel(fire...() 方法)和 ShipperAgentGUI(协调器和监听器)中看到。我想我已经通过使用 Coordinator 内部类进行表间更新部分解决了这个问题,但我不知道如何优化这些问题。例如,在删除或更新一行的情况下,我制作了 xxxTable.repaint(); ...整个表...
...另一种方式?
ShipperAgentGUI.java
public class ShipperAgentGUI extends JFrame implements ActionListener {
// Graphics variables..
// bla bla...
// Headers, TableModels, JTables for the tables
private COLUMNS[] parkModelHeader = {COLUMNS.IMAGE_COLUMN, COLUMNS.TARGA_COLUMN,
COLUMNS.CAR_TYPE_COLUMN, COLUMNS.MARCA_COLUMN, COLUMNS.STATE_COLUMN, COLUMNS.PTT_COLUMN };
private COLUMNS[] availablesModelHeader = {COLUMNS.IMAGE_COLUMN, COLUMNS.TARGA_COLUMN,
COLUMNS.CAR_TYPE_COLUMN, COLUMNS.MARCA_COLUMN };
private VehicleTableModel parkModel = new VehicleTableModel(parkModelHeader);
private VehicleTableModel availablesModel = new VehicleTableModel(availablesModelHeader);
private VehicleTable parkTable;
private VehicleTable availablesTable;
// My third-part software, a JADE agent:
protected ShipperAgent shipperAgent;
// --------------------------------------------------------------------------
// CONSTRUCTOR
ShipperAgentGUI(ShipperAgent agent) {
shipperAgent = agent; // valorizes the agent
setTitle("Shipper Agent: "+agent.getLocalName()+" GUI");
// graphic bla bla...
// Park Table and Available Table:
parkTable = new VehicleTable(parkModel);
// bla bla...
availablesTable = new VehicleTable(availablesModel);
// bla bla...
// JButtons: add/remove vehicle in Park Table and Available Table
btnPM_plus = new JButton();
btnPM_plus.setToolTipText("Add vehicle");
btnPM_plus.setIcon(...);
btnPM_plus.setActionCommand("+park");
btnPM_plus.addActionListener(this);
// similar things for other three buttons:
// remove from parkTable, add and remove from availablesTable
//bla bla...
// Data from agent:
Vector<Vehicle> veicoli = shipperAgent.getVehicles();
Iterator<Vehicle> I = veicoli.iterator();
while (I.hasNext()){
addVehicle(parkCoordinator, I.next());
}
showGui();
}
///////////////////////////////////////////////////////////////////////
// Methods:
public void showGui() {
// bla bla
}
//////////////////////////////////////////////
// actionPerformed method
@Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case "+park": {
new InsertVehicleJDialog(this, parkCoordinator);
} break;
case "-park": {
int selectedRow = parkTable.getSelectedRow();
if (selectedRow != -1)
removeVehicle(parkCoordinator, selectedRow);
} break;
case "+available": {
int selectedRow = parkTable.getSelectedRow();
if (selectedRow != -1){
addVehicle(availablesCoordinator, parkModel.getVehicleAt(selectedRow));
}
} break;
case "-available": {
int selectedRow = availablesTable.getSelectedRow();
if (selectedRow != -1)
removeVehicle(availablesCoordinator, selectedRow);
} break;
}
}
///////////////////////////////////////
// Add/Remove vehicle methods:
void addVehicle(Coordinator coordinator, Vehicle v) {
coordinator.notifyAndAddRow(v);
}
// mhm...
void removeVehicle(Coordinator coordinator, Vehicle v) {
int row = coordinator.indexOf(v);
if (row!=-1)
coordinator.notifyAndDeleteRow(row);
}
void removeVehicle(Coordinator coordinator, int index) {
coordinator.notifyAndDeleteRow(index);
}
// on dispose, delete the agent
public void dispose() {
super.dispose();
shipperAgent.doDelete();
}
///////////////////////////////////////
// INNER CLASS COORDINATOR:
protected abstract class Coordinator {
private VehicleTableModel tableModel;
public Coordinator(VehicleTableModel tm) {
tableModel = tm;
notifyRowUpdated();
}
public abstract void notifyAndAddRow(Vehicle vehicle);
public abstract void notifyAndDeleteRow(int rowIndex);
public abstract void notifyRowUpdated();
public int indexOf(Vehicle v) {
return tableModel.indexOf(v);
}
boolean vehicleExists(Vehicle vehicle){
int bool = indexOf(vehicle);
if (bool==-1) return false;
else return true;
}
}
// Coordinator for parkTable
Coordinator parkCoordinator = new Coordinator(parkModel) {
@Override
public void notifyAndAddRow(final Vehicle vehicle) {
if (!vehicleExists(vehicle)){ // is this the right control? Or in VehicleTableModel ?
shipperAgent.newTruck(vehicle.getPlate());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
parkModel.addRow(vehicle);
if (vehicle.getState().equals(Stato.DISPONIBILE))
availablesModel.addRow(vehicle);
// or with availablesCoordinator.notifyAndAddRow(vehicle) ?
// or with addVehicle(availablesCoordinator, vehicle) ?
// or with a kind of listener on vehicle's state ?
}
});
}
}
@Override
public void notifyAndDeleteRow(final int rowIndex) {
final Vehicle v = parkModel.getVehicleAt(rowIndex);
removeVehicle(availablesCoordinator, v); // Remove also from the "availables"
shipperAgent.removeTruck(v.getPlate());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
parkModel.removeRow(rowIndex);
}
});
}
@Override
public void notifyRowUpdated() {
parkModel.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
switch (e.getType()) {
case (TableModelEvent.DELETE):
parkTable.repaint();
break;
case (TableModelEvent.UPDATE):
int row = e.getLastRow();
Vehicle v = parkModel.getVehicleAt(row);
if (v.getState().equals(Stato.DISPONIBILE)){
addVehicle(availablesCoordinator, v);
availablesTable.repaint();
} else
removeVehicle(availablesCoordinator, v);
parkTable.repaint();
break;
}
}
});
}
};
// Coordinator for availablesTable
Coordinator availablesCoordinator = new Coordinator(availablesModel) {
@Override
public void notifyAndAddRow(final Vehicle vehicle) {
if (!vehicleExists(vehicle)){ // is this the right control? Or in VehicleTableModel ?
vehicle.setStato(Stato.DISPONIBILE);
parkTable.repaint();
shipperAgent.activateTruck(vehicle.getPlate());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
availablesModel.addRow(vehicle);
}
});
}
}
@Override
public void notifyAndDeleteRow(final int rowIndex) {
Vehicle v = availablesModel.getVehicleAt(rowIndex);
if (v!=null){
v.setStato(Stato.NON_DISPONIBILE); // mhm
shipperAgent.deactivateTruck(v.getPlate());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
availablesModel.removeRow(rowIndex);
}
});
}
}
@Override
public void notifyRowUpdated() {
availablesModel.addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
switch (e.getType()) {
case (TableModelEvent.DELETE):
parkTable.repaint();
break;
case (TableModelEvent.UPDATE):
parkTable.repaint();
break;
}
}
});
}
};
}
VehicleTableModel.java
public class VehicleTableModel extends AbstractTableModel {
private ArrayList<Vehicle> vehicles ;
private COLUMNS[] header;
// possible column names:
public enum COLUMNS {
IMAGE_COLUMN,
TARGA_COLUMN,
CAR_TYPE_COLUMN,
MARCA_COLUMN,
STATE_COLUMN,
PTT_COLUMN,
};
///////////////////////////////////////////////////////
// Constructor:
public VehicleTableModel(COLUMNS[] headerTable) {
this.vehicles = new ArrayList<Vehicle>();
this.header = headerTable;
}
///////////////////////////////////////////////////////
// obligatory override methods (from AbstractTableModel):
@Override
public int getColumnCount() {
return header.length;
}
@Override
public int getRowCount() {
return vehicles.size();
}
@Override
public Object getValueAt(int row, int col) {
Object value = "?";
Vehicle v = vehicles.get(row);
if (v!=null) {
COLUMNS column = header[col];
switch (column) {
case IMAGE_COLUMN:
value = VehicleUtils.findImageByColumnCarType(v.getType());
break;
case TARGA_COLUMN:
value = v.getPlate();
break;
case CAR_TYPE_COLUMN:
value = VehicleUtils.findStringByColumnCarType(v.getType());
break;
// other cases... bla bla...
}
}
return value;
}
///////////////////////////////////////////////////////
// My methods:
public void addRow(Vehicle vehicle) {
vehicles.add(vehicle);
fireTableRowsInserted(0, getRowCount()); // is right?
}
/*public boolean removeRow(Vehicle vehicle) {
boolean flag = vehicles.remove(vehicle);
fireTableRowsDeleted(0, getRowCount()); // is right?
return flag;
}*/
public void removeRow(int row) {
vehicles.remove(row);
fireTableRowsDeleted(row, row); // is right?
}
public Vehicle getVehicleAt(int row) {
return vehicles.get(row);
}
public int indexOf(Vehicle v){
return vehicles.indexOf(v);
}
// found the corresponding column index
public int findColumn(COLUMNS columnName) {
for (int i=0; i<getColumnCount(); i++)
if (columnName.equals(header[i]))
return i;
return -1;
}
// a value in that column exist in the table?
private boolean controllIfExist(Object value, int col) {
boolean bool = false;
for (int i=0; i<getRowCount();i++){
if (value.equals(getValueAt(i, col))){
bool=true;
break;
}
}
return bool;
}
public int getColumnIndex(COLUMNS column){
for(int i=0;i<header.length;i++){
if (column.equals(header[i])){
return i;
}
}
return -1;
}
///////////////////////////////////////////////////////
// other methods (from AbstractTableModel) to override:
@Override
public Class<?> getColumnClass(int col) {
Class<?> c;
COLUMNS column = header[col];
if (column.equals(COLUMNS.IMAGE_COLUMN))
c = ImageIcon.class;
else if (column.equals(COLUMNS.STATE_COLUMN))
c = JComboBox.class;
else c = super.getColumnClass(col);
return c;
}
@Override
public String getColumnName(int col) {
COLUMNS column = header[col];
if (column.equals(COLUMNS.IMAGE_COLUMN))
return " ";
else if (column.equals(COLUMNS.TARGA_COLUMN))
return "Targa";
// others... bla bla...
return super.getColumnName(col);
};
@Override
public boolean isCellEditable(int row, int col) {
return true;
}
@Override
public void setValueAt(Object value, int row, int col) {
Vehicle v = vehicles.get(row);
boolean flag = false;
if (v!=null) {
COLUMNS column = header[col];
switch (column) {
case TARGA_COLUMN:
if (!v.getPlate().equals(value)){
if (!controllIfExist(value, col)){ // mhm...
v.setPlate((String) value);
flag = true;
}
}
break;
case MARCA_COLUMN:
if (!v.getMark().equals(value)){
v.setMark((String) value);
flag = true;
}
break;
// others ... bla bla...
}
// update ONLY if necessary:
if (flag) fireTableRowsUpdated(row, row); // is right?
}
}
}
最佳答案
整个事情要从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);
}
}
}
}
其他一些提示:
从不使用repaint()
或updateUI()
来刷新表的数据。将正确的事件通知给 View 是表模型的职责。
从不使用fireTableDataChanged()
(正如有人建议的那样),除非整个表模型数据已经改变。有适当的 fireXxxx()
方法来更改行、列和单元格。
据我了解这个问题,两个表共享车辆列表,因此您必须使它们保持同步。如果是这样,我想知道为什么您需要两种不同的表模型?如果唯一的原因是状态可用/停放(互斥),那么您可以在两个表中共享一个表模型,并根据车辆状态应用不同的过滤器。在状态字段更新时,两个表都会收到通知,车辆将从一个表转移到另一个表。
前段时间在对 this answer 的评论中向 Coordinator
抽象类中添加 notifyRowUpdated()
等方法的想法似乎适合解决两个表之间的同步问题。
但现在我认为最好的方法是与两个表共享相同的表模型,并根据车辆状态过滤第二个表:如果可用(DISPONIBILE)则显示它,如果不可用则隐藏它。
通过这种方式,行更新和行删除都会通知两个表并相应地采取行动。在单元格更新时,我们可以将 TableModelListener 添加到模型中,在第二个表上应用过滤器,显示可用车辆并隐藏不可用车辆。更不用说 Coordinator
抽象类将保持简单并保持其原始目的:在行更新/删除时通知第三方代理。
所以请看下面的代码示例(抱歉扩展)。一些注意事项:
Vehicle
类。状态由可用的 boolean 属性定义。DataObjectTableModel
代码在 tablemodel 中可用标签 wiki我已经使用此类来模拟您的表格模型。Coordinator
类,所以我直接在表模型上添加/删除行,但您应该通过适当的协调器来完成。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();
}
});
}
}
请注意,在第二个表中仅显示可用车辆。
关于java - 更新复杂 JTables、TableModel 等的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26382515/
我之前发布过question已得到答复,但我也需要对此进行查询。我有一个包含这样数据的表结构(日期格式为 dd/mm/yyyy)。 ID Account Number Unit Ad
我正在使用 React Native Calendars 并尝试为议程组件构建我的数据。 预期的数据结构是(一个对象) { '2012-05-22': [{text: 'item 1 - any j
这个问题不太可能对任何 future 的访客有帮助;它只与一个较小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于全世界的互联网受众。如需帮助使此问题更广泛适用,visit the
两列城镇和优先级。 我需要对表进行排序,以便优先级=1的城镇排在第一位,并且不按名称 ASC 排序,而其余城镇则按名称 ASC 排序。 我该怎么做? 谢谢;) 更新 SELECT * FROM map
我有三个表“Hardware_model”、“Warehouse”和“Brand”,并且表以这种方式一起引用:Hardware_model 仓库Hardware_model 品牌 现在我要执行以下
我有一个 MySQL 表 (tbl_filters),包含 3 列:id、cat、val id 和 val 是数字,cat 是 varchar。每个 id 有多行。 我还有另一个包含多个列的表 (tb
我想获取字段的不同值,比方说:field1...这需要一个如下查询:“从表中选择不同的(字段1)” 但是,对于某些记录,field1 为空,并且还有另一列可以替代 field1,即 field2。对于
表 1 - 用户 id username items 1 Paul 1(0020);2(0001); 表 2 - 项目 id name 1 name_here 在我的用户的项目中,我输入了 2(000
我想连接同一个表 4 次以获取列的显示方式,我不确定是否可以在 1 个 SQL 语句中完成。 tbl_用户名 id username 1 Adam 2 Bob 3 Chris tbl_机
首先,我刚刚开始自己学习JS,没有任何编程经验,这意味着我仍然要了解这种出色的编程语言的基本构建模块。 我的问题与我编写的以下代码有关: let orderCount = 0; con
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 9 年前。 Improve t
我正在使用 XMAPP,MySQL 正在正常运行。在 phpMyAdmin 中,我不太明白这一点,所以我尝试在 PHP 中创建一个。使用此代码,它会告诉我数据库 benutzer。尽管我在 phpMy
是否有一种高效的算法可以找到平均度最大的子图(可能是图本身)? 最佳答案 The paper "Finding a Maximum-Density Subgraph" by Andrew Goldbe
目录 1、业务背景 2、场景分析 3、流程设计 1、业务流程 2、导入流程
我有 2 个表: 1) 包含自 1900 年 1 月 1 日以来所有日期的 Masterdates 表 2) Stockdata 表,其中包含表单中的股票数据 日期、交易品种、开盘价、最高价、最低价、
我有一个非常复杂的 UI,其状态栏不断变化,其中包含多种类型的状态消息,并且 UI 具有复杂的图表控件和已加载的指示性地理 map 。 现在这些小而复杂的区域的数据上下文具有同样复杂的 ViewMod
有人可以用简单的方式向我解释为什么常量在大 O 表示法中无关紧要吗?为什么添加常量时复杂性保持不变。这不是作业问题,我只是想更好地理解这一点。让我明白这个大 O 是为了看到一个函数在接近无穷大时的行为
我在 flex 搜索索引中有以下文档。 [{ "_index": "ten2", "_type": "documents", "_id": "c323c
我有一个以零碎的方式构建的 LINQ 查询,如下所示: var initialQuery = from item in MyContext where xxx == yyy select item;
我目前正在涉足 SQL,并且希望针对我所创建的问题获得一些帮助。 为了练习一些编程,我正在制作一个 IOU 应用程序。下面是我存储的表我的借条记录(忽略一些相关栏目)。该表允许用户说“嘿,你欠我 X
我是一名优秀的程序员,十分优秀!