【问题标题】:JTable duplicate values in row行中的 JTable 重复值
【发布时间】:2012-02-26 07:50:42
【问题描述】:

我有一个JTable 填充了自定义DataModel(粘贴在下面),当我调用populate() 方法时,它似乎用重复的数据填充表格 - 每行都是一遍又一遍地填充相同的值。然而,仔细检查(通过简单地 println() 处理“数据”字段),数据模型没有错误——它以我期望的格式保存正确的数据。什么给了?

import java.util.ArrayList;    
import javax.swing.table.AbstractTableModel;

@SuppressWarnings("serial") // we don't expect this app to ever use serialized classes.  EVER.
public class CollectionDataModel extends AbstractTableModel {
    private ArrayList<ArrayList<String>> data;

    public CollectionDataModel() {
        data = new ArrayList<ArrayList<String>>();
    }

    @Override
    public int getColumnCount() {
        if(data.isEmpty()) return 0;
        return data.get(0).size();
    }

    @Override
    public int getRowCount() {
        return data.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        if(rowIndex > getRowCount()) return null;
        if(columnIndex > getColumnCount()) return null;
        return data.get(rowIndex).get(columnIndex);
    }

    public void populate(Collection c) {
        data.clear();
        for(Item i : c.getItems()) {
            ArrayList<String> row = new ArrayList<String>();
            for(Property p : i.getProperties().values()) {
                row.add(p.toString());
            }
            data.add(row);
        }
        fireTableDataChanged();
    }

}

【问题讨论】:

  • 我在您发布的代码中没有看到明显的错误。如果您没有很快得到一个像样的答案,您可能需要做更多的调试来尝试准确地隔离 where 发生错误。另外,您是否使用自定义渲染器?它会显示错误的数据吗?运气!
  • 不,默认渲染器,我会继续关注它,谢谢。至少我知道我不会发疯!
  • 您是否在为表格使用单元格渲染?
  • @ChrisBrowne:我不声称你的理智程度或稳定性。
  • @HovercraftFullOfEels 采取明智的立场,在我编程时它有泄漏的趋势。

标签: java swing jtable


【解决方案1】:

您可以尝试使填充的更改更多原子。

public void populate(Collection c) {
    ArrayList<ArrayList<String>> data2 = new  ArrayList<ArrayList<String>>();
    for(Item i : c.getItems()) {
        ArrayList<String> row = new ArrayList<String>();
        for(Property p : i.getProperties().values()) {
            row.add(p.toString());
        }
        data2.add(row);
    }
    data = data2;
    fireTableDataChanged();
}

我猜populate 会在之前的populate 调用完成之前再次调用。并且可能c 在其迭代过程中被更改。

【讨论】:

  • 很抱歉,这有什么帮助?
  • 我看不出它会发生什么变化。 Swing 中的一切都是在事件派发线程中完成的,因此表格无法看到任何中间状态。
  • populate 与事件线程无关。每当更改/添加单元格时,可能都会调用它。这使得模型混乱,只显示了一部分。但更严重的是,当集合发生更改时遍历集合c,可能会得到重复值之类的东西。
  • 但我没有在数据中得到重复值,我在我的问题中说过 - 我只在显示 JTable 时得到重复值,实际数据变量在打印时是完整的。这是“数据”变量与我正在尝试调试的 JTable 显示的变量之间的区别。
  • @HovercraftFullOfEels 你是对的,代码解决了 other 并发错误;但是文中提到了并发下天真使用c的谬误。
【解决方案2】:

1)您的TableModel 未完成,我想念JTable's life_cycle 的许多或必需的方法,以TableHeader 等开头。

2)由于有很多基于HashMap的AbstactTableModel,我建议直接返回API中实现的数组类型

Vector<Vector<Object or String>> data; 

String[][] or Object[][] 

而不是

ArrayList<ArrayList<String>> data;

简单的解释是XxxList返回column,Vector或String[]返回Row

3) 我建议直接使用DefaultTableModel,那么您将永远不需要解决重复或错过列/行的问题

【讨论】:

  • 非常抱歉,但我不太明白您的回答。你是说我的 TableModel 缺少方法吗?如果是这样,具体是哪些方法?我没有收到有关未实现方法的任何警告或错误...
  • hmmm 等一下,我要在这个论坛上寻找基于 Vector 的 AbstractTableModel,写 AbstractTableModel(从 DefaultTableModel 覆盖方法)并不容易,需要有关 JTable 和 DefaultTableModel 的基本知识
  • 好的。我并没有真正关注你,但听起来你会尝试用更多信息更新你的答案,所以我会在几分钟后回来查看。感谢您尝试帮助我:)
  • 您是否建议我为我创建的 AbstractTableModel 创建一个自定义渲染器?这真的有必要吗?
  • Renderer与Model无关,底层是AbstractTableModel,触发的方法和事件最少
【解决方案3】:

这是一个完整的示例,可能会有所帮助。由于示例Map 是不可修改的,我建议您参考@mKorbel 的example,了解如何覆盖isCellEditable()setValueAt()

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;

/** @see https://stackoverflow.com/questions/9132987 */
public class EnvTableTest extends JPanel {

    public EnvTableTest() {
        this.setLayout(new GridLayout());
        this.add(new JScrollPane(new JTable(new EnvDataModel())));
    }

    private static class EnvDataModel extends AbstractTableModel {

        private Map<String, String> data = System.getenv();
        private String[] keys;

        public EnvDataModel() {
            keys = data.keySet().toArray(new String[data.size()]);
        }

        @Override
        public String getColumnName(int col) {
            if (col == 0) {
                return "Key";
            } else {
                return "Value";
            }
        }

        @Override
        public int getColumnCount() {
            return 2;
        }

        @Override
        public int getRowCount() {
            return data.size();
        }

        @Override
        public Object getValueAt(int row, int col) {
            if (col == 0) {
                return keys[row];
            } else {
                return data.get(keys[row]);
            }
        }
    }

    private void display() {
        JFrame f = new JFrame("EnvTableTest");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new EnvTableTest().display();
            }
        });
    }
}

【讨论】:

  • 这个例子假设我知道(至少)预先知道的列数。我的代码不需要预先知道列数(出于某种原因)。尽管如此,还是感谢您的帮助。由于这个答案,我将实现缺少的方法并重新排列我的数据类型。接受代替更好的东西,将使用此处给出的建议来构建我自己的解决方案。再次感谢。
  • 优秀。事实上,我的示例被设计为最小化,但它可以作为sscce 的基础,以解决未来可能出现的任何问题。也可以考虑List&lt;List&lt;String&gt;&gt; data = new ArrayList&lt;List&lt;String&gt;&gt;()。仔细看,我看到您的列数是data.get(0).size()。内部列表的长度是否不同有关系吗?
  • 好点,内部列表不应该有不同的长度,但可能会有(在加载损坏数据的情况下,我确实有防范措施,但我认为安全总比抱歉好) - 我会解决这个问题。另外,感谢您提供有关 List 与 ArrayList 的提示,我认为很明显我是 OOP 的新手!再次感谢你的帮助! :)
猜你喜欢
  • 2013-05-05
  • 1970-01-01
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 2012-11-07
  • 2015-04-24
  • 2011-03-28
  • 1970-01-01
相关资源
最近更新 更多