1

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

我的选择,据我现在所见:

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

优点:当我复制时,我会在剪贴板中显示所有内容

缺点: - 意味着在切换时间码的显示模式时触发模型事件 - 编写荧光笔(我正在使用 JXTables btw。)会再次变得混乱,因为我必须进行字符串匹配,现在我可以使用我的模型对象

2)保持原样并构建一个使用渲染器的自定义复制操作,然后从渲染的标签中提取文本

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

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

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

优点和缺点: - 或多或少是半途而废的妥协

任何建议,甚至是一些我可以使用的现有代码,有人吗?

谢谢你的时间!

4

2 回答 2

3

扩展@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());
于 2013-07-22T05:40:35.040 回答
2

TableModel应该包含数据,并且选择的渲染器应该格式化单元格的内容。如此处所示,您可以在自定义的Transferable. 用于java.text.MessageFormat让您对从模型获得的数据应用相同的格式TableCellRendererTransferable

于 2013-07-21T16:52:15.767 回答