小编典典

JTable,TableModel等的复杂用法

java

我在管理两个JTable和相关数据时遇到一些问题。

我做了这个GUI: 在此处输入图片说明

我解释一下用法:在第一个jTable中,我列出了车辆(卡车,
汽车……)和相关信息。在第二个jTable中
,我按下
绿色箭头,列出了我要使其“可用”的车辆(即sw代理启动)。因此,是第一个列表的子列表:在第一个
表中选择的行将在第二个表中复制。

第一个问题:在第一列中,我有
车辆类型的说明图(在示例中您可以看到卡车)。在第三列和第五列中,我
有不同的jComboBoxs。请参阅TIPO VEICOLO(即Kind)的jComboBox:如果
选择其他车辆,则第一列中的图像必须更改!(如果我
选择从卡车更改为汽车,则相对图标必须更改)。而且,
可能的话,我不想在软件的其他地方处理此图标。我
解释:我想用

Object[] vehicle = {"aaa", "kind1", "marca", "disponibile", "ptt" }

and never

Object[] vehicle = {"/image/truck.png" ,"aaa", "kind1", "marca", "disponibile", "ptt" }

第二个问题:将来,我想在jTable中添加其他功能:
尺寸,车辆的颜色,许可证……我知道卡车
的功能与汽车的功能不同。我想要一种将所有功能保留在
标题中的方法,但要在每行中(根据车辆的类型)
激活/禁用某些单元格。

请注意:jTables的标题不一定相同

package it.transfersimulation;

import it.transfersimulation.Vehicle.Stato;
import it.transfersimulation.Vehicle.TipoVeicolo;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.ComponentOrientation;

import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.BoxLayout;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.JButton;

import java.awt.FlowLayout;

import javax.swing.SwingConstants;


@SuppressWarnings("serial")
public class ShipperAgentGUI extends JFrame implements ActionListener {

// Variabili di classe
private JPanel masterPanel;
private JButton btnPM_plus;
private JButton btnPM_meno;
private JButton btnMD_plus;
private JButton btnMD_meno;
private JTable availablesTable;
private JTable parkTable;

private Object[] parkModelHeader = { "" , "TARGA", "TIPO VEICOLO", "MARCA", "STATO", "PTT" };
private Object[] availablesModelHeader = { "", "TARGA", "TIPO VEICOLO", "MARCA", "STATO", "PTT" };

private DefaultTableModel parkModel = new DefaultTableModel(null, parkModelHeader){
    public Class<?> getColumnClass(int columnIndex) {
        return getValueAt(0, columnIndex).getClass();
    };
};// per aggiungere jCheckBox, jComboBox e ImageIcon

private DefaultTableModel availablesModel = new DefaultTableModel(null, availablesModelHeader){
    public Class<?> getColumnClass(int columnIndex) {
        return getValueAt(0, columnIndex).getClass();
    };
};// per aggiungere jCheckBox, jComboBox e ImageIcon

// My third-part software: a JADE agent:
protected ShipperAgent shipperAgent;

private Coordinator parkCoordinator;
private Coordinator availablesCoordinator;


////////////////////////////////////////////////////
// COSTRUTTORE

ShipperAgentGUI(ShipperAgent agent) {

    // Valorizza l'agente corrispondente
    shipperAgent = agent;


    ///////////////////////////////////////////////////////////////////////
    // Graphics:
    //

    setTitle("Shipper Agent: "+agent.getLocalName());
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    try {
        UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
        //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (ClassNotFoundException | InstantiationException
            | IllegalAccessException | UnsupportedLookAndFeelException e) {
        e.printStackTrace();
    }

    // MasterPanel
    masterPanel = new JPanel();
    masterPanel.setLayout(new BoxLayout(masterPanel, BoxLayout.Y_AXIS));
    masterPanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);


    // Park Panel
    JPanel parkPanel = new JPanel();
    parkPanel.setLayout(new BoxLayout(parkPanel, BoxLayout.Y_AXIS));
    masterPanel.add(parkPanel);

    JPanel pnlHeaderParkPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
    JLabel parkLabel = new JLabel("Parco auto:");
    pnlHeaderParkPanel.add(parkLabel);
    parkPanel.add(pnlHeaderParkPanel);

    JPanel pnlTableParkPanel = new JPanel();
    pnlTableParkPanel.setLayout(new BoxLayout(pnlTableParkPanel, BoxLayout.X_AXIS));
    parkPanel.add(pnlTableParkPanel);

    // Park Table
    parkTable = new JTable();
    parkTable.setModel(parkModel);
    parkTable.setPreferredScrollableViewportSize(new Dimension(500,100));
    parkTable.setFillsViewportHeight(true);
    JScrollPane parkScrollPane = new JScrollPane(parkTable);
    pnlTableParkPanel.add(parkScrollPane);

    JPanel pnlBtnParkPanel = new JPanel();
    pnlTableParkPanel.add(pnlBtnParkPanel);
    pnlBtnParkPanel.setLayout(new BoxLayout(pnlBtnParkPanel, BoxLayout.Y_AXIS));

    // JButtons: add/remove vehicle in Park Table
    btnPM_plus = new JButton();
    btnPM_plus.setToolTipText("Aggiungi mezzo");
    btnPM_plus.setIcon(new ImageIcon(ShipperAgentGUI.class.getResource("/images/lorry-add.png")));
    btnPM_plus.setActionCommand("+parco");
    btnPM_plus.addActionListener(this);
    pnlBtnParkPanel.add(btnPM_plus);

    btnPM_meno = new JButton();
    btnPM_meno.setToolTipText("Rimuovi mezzo");
    btnPM_meno.setIcon(new ImageIcon(ShipperAgentGUI.class.getResource("/images/lorry-delete.png")));
    btnPM_meno.setActionCommand("-parco");
    btnPM_meno.addActionListener(this);
    pnlBtnParkPanel.add(btnPM_meno);


    // Arrow Panel
    JPanel arrowPanel = new JPanel();
    masterPanel.add(arrowPanel);

    // JButtons: available or not vehicle
    btnMD_plus = new JButton();
    btnMD_plus.setToolTipText("Rendi disponibile il mezzo selezionato");
    btnMD_plus.setIcon(new ImageIcon(ShipperAgentGUI.class.getResource("/images/arrow-green-down.png")));
    arrowPanel.add(btnMD_plus);
    btnMD_plus.setActionCommand("+disponibili");
    btnMD_plus.addActionListener(this);

    btnMD_meno = new JButton();
    btnMD_meno.setToolTipText("Rendi indisponibile il mezzo selezionato");
    btnMD_meno.setIcon(new ImageIcon(ShipperAgentGUI.class.getResource("/images/arrow-red-up.png")));
    arrowPanel.add(btnMD_meno);
    btnMD_meno.setActionCommand("-disponibili");
    btnMD_meno.addActionListener(this);


    // Availables Panel
    JPanel availablesPanel = new JPanel();
    masterPanel.add(availablesPanel);
    availablesPanel.setLayout(new BoxLayout(availablesPanel, BoxLayout.Y_AXIS));

    JPanel pnlHeaderAvailablesPanel = new JPanel();
    FlowLayout fl_pnlHeaderAvailablesPanel = (FlowLayout) pnlHeaderAvailablesPanel.getLayout();
    fl_pnlHeaderAvailablesPanel.setAlignment(FlowLayout.LEFT);
    availablesPanel.add(pnlHeaderAvailablesPanel);
    JLabel label_1 = new JLabel("Disponibili:");
    pnlHeaderAvailablesPanel.add(label_1);
    label_1.setHorizontalAlignment(SwingConstants.LEFT);

    // Available Table
    availablesTable = new JTable();
    availablesTable.setModel(availablesModel);
    availablesTable.setPreferredScrollableViewportSize(new Dimension(500, 100));
    availablesTable.setFillsViewportHeight(true);
    JScrollPane availablesScrollPane = new JScrollPane(availablesTable);
    availablesPanel.add(availablesScrollPane);
    getContentPane().add(masterPanel, BorderLayout.CENTER);

    // Search Panel
    JPanel searchPanel = new JPanel();
    masterPanel.add(searchPanel);
    JButton btnSearch = new JButton("Search");
    searchPanel.add(btnSearch);

    // End of graphics init
    ///////////////////////////////////


    //////////////////////////////////////
    // Editor delle colonne delle tabelle
    // TODO
    JComboBox<TipoVeicolo> tipoVeicoloComboBox = new JComboBox<TipoVeicolo>();
    tipoVeicoloComboBox.setModel(new DefaultComboBoxModel<TipoVeicolo>(TipoVeicolo.values()));
    JComboBox<Stato> statoComboBox = new JComboBox<Stato>();
    statoComboBox.setModel(new DefaultComboBoxModel<Stato>(Stato.values()));

    TableColumn tipoVeicoloColumn = parkTable.getColumnModel().getColumn(2);
    TableColumn statoColumn = parkTable.getColumnModel().getColumn(4);

    tipoVeicoloColumn.setCellEditor(new DefaultCellEditor(tipoVeicoloComboBox));
    statoColumn.setCellEditor(new DefaultCellEditor(statoComboBox));


    /////////////////////////////////////////////////////////////////////
    // Coordinators (ispirati al Mediator pattern)

    parkCoordinator = new Coordinator(shipperAgent, parkModel) {
        @Override
        public void notifyAndAddRow(final Object[] rowData) {
            shipperAgent.newTruck((String) rowData[0]);

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    tableModel.addRow(rowData);
                }
            });
        }

        @Override
        public void notifyAndDeleteRow(final int rowIndex) {
            final String truck = (String)this.tableModel.getValueAt(rowIndex, 0);
            int flag=search(availablesCoordinator.tableModel, truck);
            if (flag!=-1)
                removeVehicle(availablesCoordinator, flag);
            shipperAgent.removeTruck(truck);

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    tableModel.removeRow(rowIndex);
                }
            });
        }
    };


    availablesCoordinator = new Coordinator(shipperAgent, availablesModel) {
        @Override
        public void notifyAndAddRow(final Object[] rowData) {
            shipperAgent.activateTruck((String) rowData[0]);

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    tableModel.addRow(rowData);
                }
            });
        }

        @Override
        public void notifyAndDeleteRow(final int rowIndex) {
            String truck = (String)this.tableModel.getValueAt(rowIndex, 1);
            shipperAgent.deactivateTruck(truck);

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    tableModel.removeRow(rowIndex);
                }
            });
        }
    };


    /////////////////////////////////////////////////////
    // Listeners:

    parkModel.addTableModelListener(parcoListener);
    availablesModel.addTableModelListener(mezziDisponibiliListener);


    /////////////////////////////////////////////////////
    // Contatto con l'agente - Riempimento dati
    // TODO
    Object[] veicoli = shipperAgent.getVehicles();
    for (int i=0; i<veicoli.length;i++){
        Object[] info = (Object[]) veicoli[i];
        Object[] veicolo = new Object[info.length+1];

        veicolo[0] = new ImageIcon(ShipperAgentGUI.class.getResource("/images/lorry-icon.png"));

        for (int j=1;j<info.length+1;j++){
            veicolo[j]=info[j-1];
        }

        parkModel.addRow(veicolo);

        if ( veicolo[4] == Stato.DISPONIBILE )
            availablesModel.addRow(veicolo);
    }

    ////////////////////////////
    // Show GUI
    showGui();
}


public void showGui() {
    pack();
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    int centerX = (int) screenSize.getWidth() / 2;
    int centerY = (int) screenSize.getHeight() / 2;
    setLocation(centerX - getWidth() / 2, centerY - getHeight() / 2);
    super.setVisible(true);
}


//////////////////////////////////////////////
// actionPerformed

@Override
public void actionPerformed(ActionEvent e) {
    switch (e.getActionCommand()) {
    case "+parco": {
        new VehicleInsertJDialog(this, parkCoordinator);
    } break;

    case "-parco": {
        int selectedRow = parkTable.getSelectedRow();
        if (selectedRow != -1)
            removeVehicle(parkCoordinator, selectedRow);
    } break;

    case "+disponibili": {
        int selectedRow = parkTable.getSelectedRow();
        if (selectedRow != -1){
            //TODO controlla la consistenza
            addVehicle(availablesCoordinator,
                    String.valueOf(parkModel.getValueAt(selectedRow, 0)),
                    String.valueOf(parkModel.getValueAt(selectedRow, 1)),
                    String.valueOf(parkModel.getValueAt(selectedRow, 2)),
                    String.valueOf(parkModel.getValueAt(selectedRow, 3)),
                    String.valueOf(parkModel.getValueAt(selectedRow, 4))
                    );

        }
    } break;

    case "-disponibili": {
        int selectedRow = availablesTable.getSelectedRow();
        if (selectedRow != -1)
            removeVehicle(availablesCoordinator, selectedRow);
    } break;

    default:
        System.out.println("Imprevisto in actionPerformed()");
        break;
    }
}



// /////////////////////////////////////
// Add/Remove vehicles methods

public void addVehicle(Coordinator coordinator,
        String targa, String tipo, String marca, String stato, String peso) {
    coordinator.notifyAndAddRow(new Object[]{targa, tipo, marca, stato, peso});
}

public void removeVehicle(Coordinator coordinator, int index) {
    coordinator.notifyAndDeleteRow(index);
}


// //////////////////////////////////////////
// LISTENER:

TableModelListener parcoListener = new TableModelListener() {
    public void tableChanged(TableModelEvent e) {
        switch (e.getType()) {
        case (TableModelEvent.INSERT):
            System.out.println("un inserimento in corso!"); break;
        case (TableModelEvent.DELETE):
            System.out.println("una cancellazione in corso!"); break;
        case (TableModelEvent.UPDATE):
            System.out.println("un aggiornamento in corso!"); break;
        }
    }
};

TableModelListener mezziDisponibiliListener = new TableModelListener() {
    public void tableChanged(TableModelEvent e) {
        switch (e.getType()) {
        case (TableModelEvent.INSERT):
            System.out.println("un inserimento in corso!"); break;
        case (TableModelEvent.DELETE):
            System.out.println("una cancellazione in corso!"); break;
        case (TableModelEvent.UPDATE):
            System.out.println("un aggiornamento in corso!"); break;
        }
    }
};



private int search(DefaultTableModel tableModel, String targa) {
    int flag = -1;
    for (int i=0; i<tableModel.getRowCount(); i++) 
        if (tableModel.getValueAt(i, 0).equals(targa))
            flag=i;
    return flag;
}






///////////////////////////////////////
// INNER CLASS
///////////////////////////////////////

protected abstract class Coordinator {

    /*
     * protected class members so subclasses can access these directly
     */

    protected ShipperAgent shipperAgent;
    protected DefaultTableModel tableModel;

    public Coordinator(ShipperAgent sa, DefaultTableModel tm) {
        shipperAgent = sa;
        tableModel = tm;
    }

    public abstract void notifyAndAddRow(Object[] rowData);

    public abstract void notifyAndDeleteRow(int rowIndex);
}

}

阅读 148

收藏
2020-11-23

共1个答案

小编典典

我知道我的第一个实现方式并不适合我的要求。首先,使用DefaultTableModel是一个很大的限制,
因为您只能使用Vector,Object,String …就我而言,我想通过jtable操纵一组Vehicles。因此,第一件事:

Vehicle.java

public class Vehicle {

    enum TipoVeicolo {
        AUTO, FURGONE,
        AUTOCARRO,
        AUTOARTICOLATO
    };

    private String targa;
    private TipoVeicolo tipoVeicolo;
    private String marca;
    private Stato stato
    private float ptt;
    //... others...

    // constructor
    public Vehicle(String targa, TipoVeicolo tipoVeicolo, String marca, Stato stato, float ptt) {
        this.targa=targa;
        this.tipoVeicolo=tipoVeicolo;
        // ... bla bla
    }

    // GET and SET methods...
    //...
}

Now, I had already done this. The new is the class that extends
AbstractTableModel (and not DefaultTableModel)

VehicleTableModel.java

public class VehicleTableModel extends AbstractTableModel {

    // private objects
    private ArrayList<Vehicle> vehicles;
    private COLUMNS[] header;

    // possible column names:
    public enum COLUMNS {
        IMAGE_COLUMN,
        TARGA_COLUMN,
        CAR_TYPE_COLUMN,
        //...
    }; // if I want I can add others...



    ///////////////////////////////////////////////////////
    // 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();
    }

    // this works! :D
    @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:
                    int i = findColumn(COLUMNS.CAR_TYPE_COLUMN); // find the right column index
                    Object tipo = getValueAt(row, i); 
                    value = (ImageIcon)findImageByColumnCarType(tipo); // find the right icon for the type of vehicle.
                    break;
                case TARGA_COLUMN:
                    value = v.getTarga();
                    break;
                case CAR_TYPE_COLUMN:
                    value = v.getTipoVeicolo();
                    break;
                //...
            }
        }
        return value;
    }



    ///////////////////////////////////////////////////////
    // My methods:

    public void addRow(Vehicle vehicle) {
        if (!vehicles.contains(vehicle)){
            vehicles.add(vehicle);
            fireTableRowsInserted(0, getRowCount()); // I'm not so sure of this..
    }

    /* I'm not so sure of this..
    public boolean removeRow(Vehicle vehicle) {
        boolean flag = vehicles.remove(vehicle);
        fireTableRowsDeleted(0, getRowCount()); // or fireTableDataChanged(); ?
        return flag;
    }*/

    public void removeRow(int row) {
        vehicles.remove(row);
        fireTableRowsDeleted(row, row);
    }


    public Vehicle getVehicleAt(int row) {
        return vehicles.get(row);
    }

    // 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;
    }

    // found the right image
    protected static ImageIcon findImageByColumnCarType(Object value) {
        ImageIcon i = null;
        if (value.equals(TipoVeicolo.AUTO))
            i = new ImageIcon(VehicleTableModel.class.getResource("/images/Car-icon_32.png"));
        else if (value.equals(TipoVeicolo.AUTOARTICOLATO))
            i = new ImageIcon(VehicleTableModel.class.getResource("/images/City-Truck-blue-icon_32.png"));
        //...
        return i;
    }

    // knows if exist a value (of a column) in all rows
    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;
    }



    ///////////////////////////////////////////////////////
    // other methods (from AbstractTableModel) to ovveride:

    // this works! :D
    @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.CAR_TYPE_COLUMN))
            c =  JComboBox.class;
        // else if blabla....
        else c = super.getColumnClass(col);
        return c;
    }

    // this works! :D 
    @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";
        else if (column.equals(COLUMNS.CAR_TYPE_COLUMN))
            return "Tipo veicolo";
        // else if blabla...
        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.getTarga().equals(value)){
                        if (!controllIfExist(value, col)){
                            v.setTarga((String) value);
                            flag = true;
                        }
                    }
                    break;
                case CAR_TYPE_COLUMN:
                    if (!v.getTipoVeicolo().equals(value)){
                        v.setTipoVeicolo((TipoVeicolo) value);
                        flag = true;
                    }
                    break;
                // other cases bla bla...
            }

            if (flag) // update only if have found modify
                fireTableRowsUpdated(0, getRowCount()); // or fireTableRowsUpdated(row, row); ?
        }
    }

}

After this, for commodity, I create a VehicleTable (extends JTable). Can it
look like useless, but is right for my objective… You can see the right
settings for the special cells (cell with JComboBox, for example)

VehicleTable.java

public class VehicleTable extends JTable {

public VehicleTable(VehicleTableModel vehicleModel) {
    super(vehicleModel); 
    this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    this.setColumnSelectionAllowed(false);
    this.setCellSelectionEnabled(false);
    this.setRowSelectionAllowed(true);
    this.setShowHorizontalLines(true);
    this.setRowHeight(25);
    this.setPreferredScrollableViewportSize(new Dimension(700,150));
    this.setFillsViewportHeight(true);

    ////////////////////////////////////
    // Now I set the columns features:
    int flag=-1;
    TableColumn column;

    // Icon Column:
    flag = vehicleModel.findColumn(COLUMNS.IMAGE_COLUMN);
    if (flag!=-1){
        column = this.getColumnModel().getColumn(flag);
        column.setMinWidth(80);
        column.setMaxWidth(80);
    }

    // Targa Column:
    flag = vehicleModel.findColumn(COLUMNS.TARGA_COLUMN);
    if (flag!=-1){
        column = this.getColumnModel().getColumn(flag);
        column.setMinWidth(100);
        column.setMaxWidth(100);
    }

    // Tipo veicolo Column
    flag = vehicleModel.findColumn(COLUMNS.CAR_TYPE_COLUMN);
    if (flag!=-1){
        column = this.getColumnModel().getColumn(flag);
        column.setCellEditor(new DefaultCellEditor(
                new JComboBox<TipoVeicolo>(TipoVeicolo.values())));
        column.setMinWidth(150);
        column.setMaxWidth(150);
    }

    //others...
}

Finally, we can use this. For example in my GUI

ShipperAgentGUI.java (an extract. I focus on ONE table)

public class ShipperAgentGUI extends JFrame implements ActionListener {

    // ... bla bla

    private COLUMNS[] parkModelHeader = {COLUMNS.IMAGE_COLUMN, COLUMNS.TARGA_COLUMN,
        COLUMNS.CAR_TYPE_COLUMN, COLUMNS.MARCA_COLUMN, COLUMNS.STATE_COLUMN, COLUMNS.PTT_COLUMN };
    private VehicleTableModel parkModel = new VehicleTableModel(parkModelHeader);
    private VehicleTable parkTable; 
    private Coordinator parkCoordinator; // long story

    protected ShipperAgent shipperAgent; // my agent, my third-part software

    // ... bla bla

    // Constructor:
    ShipperAgentGUI(ShipperAgent agent) {

        //... bla bla

        // Park Table:
        parkTable = new VehicleTable(parkModel);
        JScrollPane parkScrollPane = new JScrollPane(parkTable);
        pnlTableParkPanel.add(parkScrollPane);

        //... bla bla

        // Coordinators (Mediator pattern's ispired)
        // Long story. Is for coordinating with my agent and others tables in my GUI
        parkCoordinator = new Coordinator(shipperAgent, parkModel) {

            @Override
            public void notifyAndAddRow(final Vehicle vehicle) {
                shipperAgent.newTruck(vehicle.getTarga()); // comunicate with the agent

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        parkModel.addRow(vehicle);
                    }
                });
            }

            @Override
            public void notifyAndDeleteRow(final int rowIndex) {
                final Vehicle v = this.tableModel.getVehicleAt(rowIndex);
                // bla bla
                shipperAgent.removeTruck(v.getTarga()); // comunicate with the agent

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        //parkModel.removeRow(v);
                        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();
                    int col = parkModel.getIndexColumn(COLUMNS.STATE_COLUMN);
                    if (parkModel.getValueAt(row, col).equals(Stato.DISPONIBILE))
                        addVehicle(availablesCoordinator, parkModel.getVehicleAt(row));
                    else
                        //removeVehicle(availablesCoordinator, row); error!
                        availablesModel.removeRow(parkModel.getVehicleAt(row));
                    repaint();
                    break;
            }
        }
    });
}
        };


        ArrayList<Vehicle> veicoli = shipperAgent.getVehicles(); // from agent
        Iterator<Vehicle> I = veicoli.iterator();
        while (I.hasNext()){
            addVehicle(parkCoordinator, I.next());
        }

        //... bla bla

    } // end of constructor

    // ... others methods...

    private void addVehicle(Coordinator coordinator, Vehicle v) {
        coordinator.notifyAndAddRow(v);
    }

    public void removeVehicle(Coordinator coordinator, int index) {
        coordinator.notifyAndDeleteRow(index);
    }

    // ...

}
2020-11-23