当前位置: 首页 > 知识库问答 >
问题:

在使用JTables时,TableCellRenderer和TableModel之间的职责的适当分离是什么?

韦绍晖
2023-03-14

我正在处理一个应用程序的一部分,该应用程序显示表,其中包含有关由类FrameInfo表示的视频文件的统计数据。在我最初有一个可以执行所有操作(包括一些格式设置)的表模型之后,我将其重构为另一个极端,让表模型只为每一行返回FrameInfo实例,然后让CellRenderer决定要呈现什么字段以及如何呈现每列。这是伟大的,因为我可以做一些很好的事情,例如切换显示时间码值之间的刻度,秒或时间码(“00:01:02:03”)只需要重新绘制。我很高兴,直到我将表内容复制并粘贴到一个gdocs电子表格中,并注意到我在所有单元格中只得到了我的模型对象的toString()的输出(当我开始考虑时这是合乎逻辑的,但显然不是我想要的)。

1)将所有内容放回模型中

优点:当我复制时,我会将剪贴板中的所有内容都显示出来

缺点:-意味着在切换时间码的显示模式时触发模型事件-写入荧光笔(我是顺便使用JXTables。)我将再次变得混乱,因为我将不得不进行字符串匹配,在这里我现在可以使用我的模型对象

优点:-表格代码保持干净

缺点:-工作量(?)-对于四舍五入的数字,我会失去准确性

3)将除动态内容(时间码)之外的所有内容放入模型中,并在呈现器中执行时间码,并接受这样的事实,即我没有得到用于复制和粘贴这些列的所见即所得

有什么建议或者是一些我可以使用的退出代码吗,有人吗?

谢谢你抽出时间!

共有1个答案

章威
2023-03-14

扩展@trashgod的答案:选项1显然是错误的:-)TableModel必须包含数据,而不是其他。呈现器的唯一工作是将数据呈现在表中(事实上,在任何Swing的集合视图中)。TransferHandler的工作是以合理的形式导出数据,最好使用与呈现器相同的字符串表示形式。

JXTable使协作者之间共享字符串表示特别容易:生成文本内容的小硬币称为StringValue,所有内部呈现器都是用它配置的。一旦配置好,该字符串就会在所有与字符串相关的扩展功能中使用,如搜索、排序、基于正则表达式的筛选和表的API:

String text = table.getStringAt(row, column);

允许自定义TransferHandler基于以下条件构建字符串:

/**
 * A TableTransferable that uses JXTable string api to build
 * the exported data.
 * 
 * C&p from BasicTableUI, replaced toString with 
 * table.getStringAt(row, col)
 */
public static class XTableTransferHandler extends TransferHandler {

    /**
     * Create a Transferable to use as the source for a data transfer.
     * 
     * @param c The component holding the data to be transfered. This
     *        argument is provided to enable sharing of TransferHandlers by
     *        multiple components.
     * @return The representation of the data to be transfered.
     * 
     */
    @Override
    protected Transferable createTransferable(JComponent c) {
        if (!(c instanceof JXTable))
            return null;
        JXTable table = (JXTable) c;
        int[] rows;
        int[] cols;

        if (!table.getRowSelectionAllowed()
                && !table.getColumnSelectionAllowed()) {
            return null;
        }

        if (!table.getRowSelectionAllowed()) {
            int rowCount = table.getRowCount();

            rows = new int[rowCount];
            for (int counter = 0; counter < rowCount; counter++) {
                rows[counter] = counter;
            }
        } else {
            rows = table.getSelectedRows();
        }

        if (!table.getColumnSelectionAllowed()) {
            int colCount = table.getColumnCount();

            cols = new int[colCount];
            for (int counter = 0; counter < colCount; counter++) {
                cols[counter] = counter;
            }
        } else {
            cols = table.getSelectedColumns();
        }

        if (rows == null || cols == null || rows.length == 0
                || cols.length == 0) {
            return null;
        }

        StringBuffer plainBuf = new StringBuffer();
        StringBuffer htmlBuf = new StringBuffer();

        htmlBuf.append("<html>\n<body>\n<table>\n");

        for (int row = 0; row < rows.length; row++) {
            htmlBuf.append("<tr>\n");
            for (int col = 0; col < cols.length; col++) {
                // original:
                // Object obj = table.getValueAt(rows[row], cols[col]);
                // String val = ((obj == null) ? "" : obj.toString());
                // replaced by JXTable api:
                String val = table.getStringAt(row, col);
                plainBuf.append(val + "\t");
                htmlBuf.append("  <td>" + val + "</td>\n");
            }
            // we want a newline at the end of each line and not a tab
            plainBuf.deleteCharAt(plainBuf.length() - 1).append("\n");
            htmlBuf.append("</tr>\n");
        }

        // remove the last newline
        plainBuf.deleteCharAt(plainBuf.length() - 1);
        htmlBuf.append("</table>\n</body>\n</html>");

        return new BasicTransferable(plainBuf.toString(),
                htmlBuf.toString());
    }

    @Override
    public int getSourceActions(JComponent c) {
        return COPY;
    }

}

用法示例:

DefaultTableModel model = new DefaultTableModel(
        new String[]{"Action"}, 0);
JXTable table = new JXTable(model);
Object[] keys = table.getActionMap().allKeys();
for (Object key : keys) {
    model.addRow(new Object[]{table.getActionMap().get(key)});
}
StringValue sv = new StringValue() {

    @Override
    public String getString(Object value) {
        if (value instanceof Action) {
            return (String) ((Action) value).getValue(Action.NAME);
        }
        return StringValues.TO_STRING.getString(value);
    }

};
table.getColumn(0).setCellRenderer(new DefaultTableRenderer(sv));
table.setDragEnabled(true);
table.setTransferHandler(new XTableTransferHandler());
 类似资料:
  • 问题内容: 我目前正在使用带有Spring插件和hibernate的Struts2开发一个Web应用程序,并且在查看在线示例时,我看到了Service和DAO层的使用,现在才知道Service和数据访问对象层的真正用途是什么?如果服务层只是在调用DAO层的方法来执行CRUD操作。直接调用DAO层方法不明智吗? 假设此示例为Dao和Service Layer 人员服务 人道 我的问题是,如果仅将服务

  • 在monorepo中,父repo(主repo)的职责是什么? 它可以打包构件所有的子repo。 它可以发布所有的子repo吗? 还有其他的职责吗? 是pnpm带来的workspace的这个属性功能吗? 但是npm7+ 也有这个功能特点了呀。

  • 我的GUI显示了我的停车场中的车辆,以及我想在两个不同的VehicleTable(扩展JTable的类)中设置可用的车辆。对于可用的车辆,我希望可以通过代理(第三方软件)观察这些车辆。这两个表都显示了行中车辆的描述…为此,我创建了VehicleTableModel和Vehicle类。Vehicle类是一个抽象类,其子类是:Car、Truck、Trailer等。 我的问题是:在我当前的实现中,我认为

  • 问题内容: 什么时候需要在Java中使用关键字。我知道您在创建这样的对象实例时应该使用它: 有时在代码中,我注意到没有使用它,我感到困惑。在这一行代码中: 为什么不这样创建AssetManager的实例: 然后将其设置为等于getAssests()? 什么时候应该使用? 谢谢! 问题答案: 首次明确创建对象时,请使用new关键字。然后,不需要使用新的getter方法获取对象,因为该对象已存在于内存

  • 本文向大家介绍为什么要离职?相关面试题,主要包含被问及为什么要离职?时的应答技巧和注意事项,需要的朋友参考一下 这个问题是每次面试必然会被问的,不管是专业面试还是hr面试都会问这个问题,这类问题有几个原因建议不能说:人际关系复杂问题(说明你沟通能力不到位)、上司问题(说明你人际关系不好,跟老大没法合作)。 建议从以下几个方面回答: 个人发展选择,寻求更大的平台和机会; 因为爱情,比方说女朋友在深圳

  • 问题内容: 在使用jenkins 2(声明性)管道和Maven时,我总是在如何组织管道中的事物以使其可重用和灵活方面遇到问题。 一方面,我想将管道分成逻辑阶段,例如: 另一方面,我有与 我可以简单地将Maven拆分为 但是,“部署”包括以下所有生命周期阶段 验证 编译 测试 包 校验 安装 部署 所以我看了很多例子,例如 和 这导致第二次重复验证和编译步骤,并以此方式浪费“时间/资源”。这可以通过