在从 DefaultTableModel 中删除后使用该行的数据 [英] Use the row's data AFTER its remove from DefaultTableModel

查看:24
本文介绍了在从 DefaultTableModel 中删除后使用该行的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是的,我知道,这听起来很愚蠢.但在我说明我的问题之前.

Yeah I know, this sounds stupid. But before let me illustrate my problem.

我有一个带有很多 JTable 的 GUI.我有各种 DefaultTableModel,每个 JTable 一个.所以,1:1.对于每个 DefaultTableModel,我都创建了一个 TableModelListener.

I have a GUI with A LOT of JTable. I have various DefaultTableModel, one for each JTable. So, 1:1. And for each DefaultTableModel I have create one a TableModelListener.

对于在我的 GUI 中插入和删除元素,我只创建了两个方法,addVehicle 和 removeVehicle:

For insert and delete elements in my GUI I have create only TWO methods, addVehicle and removeVehicle:

public void addVehicle(final DefaultTableModel model, final String s1, final String s2) {
    Runnable addV = new Runnable() {
        @Override
        public void run() {
            model.addRow(new Object[] { s1, s2 });
        } 
    };
    SwingUtilities.invokeLater(addV);
}


public void removeVehicle(final DefaultTableModel model, final int index) {
    if (row!=null){
        String s1= row.elementAt(0).toString();
        Runnable removeV = new Runnable() {
            @Override
            public void run() {
                model.removeRow(index);
            }
        };
        SwingUtilities.invokeLater(removeV);
    }
}

这些方法很完美,自动识别正确的表模型.

These methods are perfect, recognize automatically the right tablemodel.

但我有一个必要:因为我有很多 JTable(和相应的 DefaultTableModels),并且当我从表中添加/删除一行时,必须通知第三方软件,我已经创建了几个 TableModelListener.

But I have a necessity: since I have many JTable (and corresponding DefaultTableModels) and given that when I add/delete a row from a table a third-party software MUST BE INFORMED, I have created several TableModelListener.

例如 listener1:

For example listener1:

TableModelListener listener1 = new TableModelListener() {
    public void tableChanged(TableModelEvent e) {
        DefaultTableModel m = (DefaultTableModel) e.getSource();
        int row = e.getLastRow();
        switch (e.getType()) {
            case (TableModelEvent.INSERT): {
                System.out.println("Insert! Key: "+m.getValueAt(row, 0));

                // My agent, the third-party software: 
                shipperAgent.newTruck((String) m.getValueAt(row, 0));
            } break;

            case (TableModelEvent.DELETE): {
                System.out.println("Delete! Key:"+m.getValueAt(row, 0));

                // My agent, the third-party software: 
                shipperAgent.removeTruck((String)m.getValueAt(row, 0));
            } break;

            case (TableModelEvent.UPDATE): {
                // ...
            } break;
        }
    }
};

另一个例子是监听器 2(我只给你展示了一个片段......):

Another example is listener 2 (I show you just a fragment...):

            case (TableModelEvent.INSERT): {
                System.out.println("Activate! Key: "+m.getValueAt(row, 0));

                // My agent, the third-party software: 
                shipperAgent.activateTruck((String) m.getValueAt(row, 0));
            } break;

            case (TableModelEvent.DELETE): {
                System.out.println("Deactivate! Key:"+m.getValueAt(row, 0));

                // My agent, the third-party software: 
                shipperAgent.deactivateTruck((String)m.getValueAt(row, 0));
            } break;

这就是问题所在:对于插入来说是可以的,但对于 DELETE 则不行.我知道为什么:当我从 GUI 中删除一行时,该行被删除,并且在开关(案例 TableModelEvent.DELETE)中处理另一行(紧接在我删除的行之后).此外,如果这一行是最后一行(因为后面没有更多行),我会收到 NullPointerException.

This is the problem: is all right for the insert, but not for the DELETE. I know why: when I remove a row from the GUI, the row is deleted and in the switch (case TableModelEvent.DELETE) work on another row (that immediately after the one that I deleted). Moreover, if this row is the last (since there are no more lines after) i get a NullPointerException.

在侦听器中,如何在实际删除前使用一行?(或其他绝妙的方式?)

HOW I CAN, in the listener, to use a row BEFORE it is actually removed? (or other brilliant ways?)

推荐答案

...当我从表中添加/删除一行时,必须通知第三方软件,我已经创建了几个 TableModelListener.

如果您看到 TableModelEventAPI 无法从事件本身获取数据,您所拥有的只是 TableModel 这是事件的来源.话虽如此,当表模型事件被触发时,模型中的更改已经完成,您无能为力,因此您不能仅仅因为那些赢得了删除的行值而获得删除的行值不会再出现了.

If you see TableModelEvent API there's no way to get data from the event itself, all you have is the TableModel which is the source of the event. Having said this, when a table model event is fired the change in the model has been already done and it's nothing you can do about it, so you cannot get the deleted(s) row(s) value(s) just because those won't be there anymore.

但是,如果您关心的是通知此第三方软件以保持一致性,那么您应该考虑在从表模型中删除行之前.

However if your concern is to notify this third-party software in order to keep consistency I guess, then you should consider do that before removing rows from the table model.

public void removeVehicle(final DefaultTableModel model, final int index) {
    String value = (String)model.getValueAt(index, 0);
    shipperAgent.deactivateTruck(value);
    // If everything went ok, then remove the row from the table model.
    // Of course, do it in the Event Dispatch Thread.
    model.removeRow(index);
}

通过这种方式,您甚至可以协调第三方软件和您的应用程序:如果无法停用该行代表的卡车,则不要删除表模型中的行,而是显示一些错误消息.

This way you can even coordinate that third-party software and your application: if the truck represented by the row cannot be deactivated then don't remove the row in your table model and show some error message instead.

但我想集中与代理(第三方软件)的通信并将其与代码的其余部分分开,而不是传播它.

嗯,这是完全有道理的,我相信有不止一种方法可以实现这一点,但恕我直言,您的设计需要另一种方式来满足这些要求:

Well it makes perfectly sense and I'm sure there are more than one way to accomplish this, but IMHO your design needs another twist in order to fulfil these requirements:

  • 在第三方代理和您的表模型之间只有一点需要协调.
  • 不要写很多几乎做同样事情的方法:DRY 原则
  • 在正确的时间处理操作.
  • 所有职责都必须很好地分开.

我认为有些接近于中介模式(不是完全 这种模式但有些接近)可能会帮助您封装协调逻辑并解耦同一事务中涉及的第三方代理和表模型.例如考虑这个原型类:

I was thinking that something close to Mediator pattern (not exactly this pattern but something close) might help you to encapsulate the coordination logic and decouple the third-party agent and table models involved in the same transaction. For example consider this prototype class:

public 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);
}

由于您在调用 addVehicle(...)removeVehicle(...) 方法时已设法识别出正确的表模型,因此您可能会可以做同样的事情来识别合适的协调器并委托通知第三方代理和更新表模型的任务.例如:

Since you have managed to identify the right table models by the time you call addVehicle(...) and removeVehicle(...) methods, you will probably can do the same to identy the right coordinator and delegate the task of notify the third-party agent and update the table model. For instance:

ShipperAgent sa = new ShipperAgent(...);
DefaultTableModel model1 = new DefaultTableModel(...);
DefaultTableModel model2 = new DefaultTableModel(...);

Coordinator coordinator1 = new Coordinator(sa, model1) {
    @Override
    public void notifyAndAddRow(Object[] rowData) {
        this.shipperAgent.newTruck((String) rowData[0]);
        this.tableModel.addRow(rowData); // do this in the EDT
    }

    @Override
    public void notifyAndDeleteRow(int rowIndex) {
        String truck = (String)this.tableModel.getValueAt(rowIndex, 0);
        this.shipperAgent.removeTruck(truck);
        this.tableModel.removeRow(rowIndex); // do this in the EDT
    }
};

Coordinator coordinator2 = new Coordinator(sa, model2) {
    @Override
    public void notifyAndAddRow(Object[] rowData) {
        this.shipperAgent.activateTruck((String) rowData[0]);
        this.tableModel.addRow(rowData); // do this in the EDT
    }

    @Override
    public void notifyAndDeleteRow(int rowIndex) {
        String truck = (String)this.tableModel.getValueAt(rowIndex, 0);
        this.shipperAgent.removeTruck(truck);
        this.tableModel.removeRow(rowIndex); // do this in the EDT
    }
};

那么您的 addVehicle(...)removeVehicle(...) 方法可能如下所示:

Then your addVehicle(...) and removeVehicle(...) methods could look like this:

public void addVehicle(Coordinator coordinator, String s1, String s2) {
    coordinator.notifyAndAddRow(new Object[]{s1, s2});
}

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

当然,正如我所说的,当您调用 addVehicle(...) 时,您必须设法确定正确的 Coordinator 实例removeVehicle(...) 方法,但我认为您现在拥有解决问题所需的抽象.

Of course as I've said you will have to manage to identify the right Coordinator instance by the time you call addVehicle(...) and removeVehicle(...) methods, but I think you have the abstraction required to solve your problem now.

这篇关于在从 DefaultTableModel 中删除后使用该行的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆