2013-07-21 30 views
1

我正在处理应用程序的一部分,该应用程序显示有关由FrameInfo类表示的视频文件的统计数据的表。现在,当我刚开始有一个表格模型可以完成包括格式化在内的所有工作时,我将它重构为另一个极端,并且表格模型只为每行返回FrameInfo实例,然后让CellRenderer决定渲染哪个字段以及每个字段的显示方式柱。这很棒,因为我可以做很棒的事情,比如切换显示屏等。时间码值只能通过重绘,在刻度,秒或时间码(“00:01:02:03”)之间。我很高兴,直到我将表格内容复制并粘贴到gdocs电子表格中,并注意到我只在所有单元格中获得了模型对象的toString()输出(当我开始考虑它时显然不符合逻辑,但显然不是我想要的) 。当使用JTable时,TableCellRenderer和TableModel之间的职责分工是什么?

我的选择,据我现在可以看到他们:

1)把一切恢复到模型

优点: 我会在剪贴板中的一切,因为它显示出来,当我复制

缺点: - 用于触发模型事件切换时间码 的显示模式时 - 写荧光笔(我用JXTables顺便说一句。)将再次成为凌乱,因为我必须做的字符串匹配,在那里我现在可以使用我的模型对象

2)离开,因为它是现在和构建一个使用渲染器,然后提取从渲染标签

优点文本自定义复制动作: - 表代码保持清洁

缺点: - 工作量(?) - 对于像圆形数字这样的东西,我会失去准确性

3)将所有但动态的东西(timecode)放入模型中,并在渲染器中执行时间代码,没有得到WYSIWYG复制&粘贴OSE列

优点&缺点: - 更多或更少的半称职的妥协

任何意见或者甚至退出一些代码,我可以使用,任何人吗?

谢谢你的时间!

+0

为JXTable,要走的路是让一个自定义的TransferHandler使用xTable.getStringValueAt得到完全相同的字符串表示用于重ndering(和搜索,和正则表达式过滤和排序和... :-) – kleopatra

+0

@kleopatra:请考虑做出这个答案。 – trashgod

回答

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()); 
+0

谢谢,这正是我一直在寻找的! – user1573546

2

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

+1

+1 - 但它是SwingX,在那里你会使可转换使用JXTable api(如getStringValueAt(...)) – kleopatra

+0

感谢您花时间,垃圾!你绝对是对的,虽然kleopatra的swingx专用建议适合我的情况。 – user1573546

相关问题