【问题标题】:jtable to image conversion not happening properlyjtable 到图像的转换没有正确发生
【发布时间】:2011-09-29 10:14:13
【问题描述】:

我正在尝试从表格创建缓冲图像,当我将表格添加到应用程序框架并设置大小时,我能够正确查看它,但是当我将其转换为图像时,我只能看到第一行有桌子,其余的都在桌子外面,没有标题。

生成表的代码是

  table = new JTable();

    String[] table_header = null;

    TextAreaRenderer textAreaRenderer = new TextAreaRenderer();
    table_model = new DefaultTableModel() {

        @Override
        public boolean isCellEditable(int row, int column) {
            return false;
        }
    };

    table.setModel(table_model);
    table.setSize(300, 700);
    JScrollPane pane = new JScrollPane(table);
    createTableDataSet(input1, input2, varient, headertype);
    TableColumnModel cmodel = table.getColumnModel();
    table_header = obtainTableHeader(headertype);
    for (int i = 0; i < table_header.length; i++) {
        cmodel.getColumn(i).setCellRenderer(textAreaRenderer);
    }


    return table;

生成图片的代码是:

 JTableHeader header =table.getTableHeader();
    int w = Math.max(table.getWidth(), header.getWidth());
    int h = table.getHeight() + header.getHeight();
    BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2 = bi.createGraphics();
    header.paint(g2);
    g2.translate(0, header.getHeight());
    table.paint(g2);
    g2.dispose();
    try {
        ImageIO.write(bi, "png", new File("year.png"));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

桌子的图片是

更新1:我可能已经找到了问题的原因。我正在使用以下代码 sn-p 来增加单元格的大小,以便将文本包装到单元格中。包括导致问题的代码 私有最终 DefaultTableCellRenderer 渲染器 = new DefaultTableCellRenderer();

// Column heights are placed in this Map 
private final Map<JTable, Map<Object, Map<Object, Integer>>> tablecellSizes = new HashMap<JTable, Map<Object, Map<Object, Integer>>>(); 

/** 
 * Creates a text area renderer. 
 */ 
public TextAreaRenderer() { 
    setLineWrap(true); 
    setWrapStyleWord(true); 
} 

/** 
 * Returns the component used for drawing the cell.  This method is 
 * used to configure the renderer appropriately before drawing. 
 * 
 * @param table      - JTable object 
 * @param value      - the value of the cell to be rendered. 
 * @param isSelected - isSelected   true if the cell is to be rendered with the selection highlighted; 
 *                   otherwise false. 
 * @param hasFocus   - if true, render cell appropriately. 
 * @param row        - The row index of the cell being drawn. 
 * @param column     - The column index of the cell being drawn. 
 * @return - Returns the component used for drawing the cell. 
 */ 
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, 
                                               boolean hasFocus, int row, int column) { 
    // set the Font, Color, etc. 
    renderer.getTableCellRendererComponent(table, value, 
            isSelected, hasFocus, row, column); 
    setForeground(renderer.getForeground()); 
    setBackground(renderer.getBackground()); 
    setBorder(renderer.getBorder()); 
    setFont(renderer.getFont()); 
    setText(renderer.getText()); 

    TableColumnModel columnModel = table.getColumnModel(); 
    setSize(columnModel.getColumn(column).getWidth(), 0); 
    int height_wanted = (int) getPreferredSize().getHeight(); 
    addSize(table, row, column, height_wanted); 
    height_wanted = findTotalMaximumRowSize(table, row); 
    if (height_wanted != table.getRowHeight(row)) { 
        table.setRowHeight(row, height_wanted); 
    } 
    return this; 
} 

/** 
 * @param table  - JTable object 
 * @param row    - The row index of the cell being drawn. 
 * @param column - The column index of the cell being drawn. 
 * @param height - Row cell height as int value 
 *               This method will add size to cell based on row and column number 
 */ 
private void addSize(JTable table, int row, int column, int height) { 
    Map<Object, Map<Object, Integer>> rowsMap = tablecellSizes.get(table); 
    if (rowsMap == null) { 
        tablecellSizes.put(table, rowsMap = new HashMap<Object, Map<Object, Integer>>()); 
    } 
    Map<Object, Integer> rowheightsMap = rowsMap.get(row); 
    if (rowheightsMap == null) { 
        rowsMap.put(row, rowheightsMap = new HashMap<Object, Integer>()); 
    } 
    rowheightsMap.put(column, height); 
} 

/** 
 * Look through all columns and get the renderer.  If it is 
 * also a TextAreaRenderer, we look at the maximum height in 
 * its hash table for this row. 
 * 
 * @param table -JTable object 
 * @param row   - The row index of the cell being drawn. 
 * @return row maximum height as integer value 
 */ 
private int findTotalMaximumRowSize(JTable table, int row) { 
    int maximum_height = 0; 
    Enumeration<TableColumn> columns = table.getColumnModel().getColumns(); 
    while (columns.hasMoreElements()) { 
        TableColumn tc = columns.nextElement(); 
        TableCellRenderer cellRenderer = tc.getCellRenderer(); 
        if (cellRenderer instanceof TextAreaRenderer) { 
            TextAreaRenderer tar = (TextAreaRenderer) cellRenderer; 
            maximum_height = Math.max(maximum_height, 
                    tar.findMaximumRowSize(table, row)); 
        } 
    } 
    return maximum_height; 
} 

/** 
 * This will find the maximum row size 
 * 
 * @param table - JTable object 
 * @param row   - The row index of the cell being drawn. 
 * @return row maximum height as integer value 
 */ 
private int findMaximumRowSize(JTable table, int row) { 
    Map<Object, Map<Object, Integer>> rows = tablecellSizes.get(table); 
    if (rows == null) return 0; 
    Map<Object, Integer> rowheights = rows.get(row); 
    if (rowheights == null) return 0; 
    int maximum_height = 0; 
    for (Map.Entry<Object, Integer> entry : rowheights.entrySet()) { 
        int cellHeight = entry.getValue(); 
        maximum_height = Math.max(maximum_height, cellHeight); 
    } 
    return maximum_height; 
} 

这会导致单元格无法正确显示。一旦我删除了这个代码,表格就会通过包含 kleopatra 的代码正确生成。但我被单元格中的自动换行问题困住了。

谢谢, 八卦

附:在我的代码中使用 new JTable(row,fields) 创建表对象时,我使用上面相同的代码生成图像,序列化的哈希图被读取并插入到 table_model 中

【问题讨论】:

  • table.getPreferredSize().height 怎么样?它返回什么?
  • @Oltarus 抱歉,我意识到这是因为我将表格添加到应用程序框架中,如果我尝试直接创建图像,我会得到表格高度的值,但标题和数据在该表中不正确可见
  • 我看到 header.getHeight 返回 0,我将 header 添加到 table_model 并将 table_model 添加到 table。有解决办法吗?

标签: java image swing jtable


【解决方案1】:

基本上,您必须通过设置它们的大小(在 pref 以下用来)。

顺便说一句,添加到 JScrollPane 没有帮助(如您所见),除非实现窗格 - 添加标题是由 addNotify 中的表完成的。

    JTable table = new JTable(new AncientSwingTeam());
    JTableHeader header =table.getTableHeader();
    table.setSize(table.getPreferredSize());
    header.setSize(header.getPreferredSize());
    int w = Math.max(table.getWidth(), header.getWidth());
    int h = table.getHeight() + header.getHeight();
    BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2 = bi.createGraphics();
    header.paint(g2);
    g2.translate(0, header.getHeight());
    table.paint(g2);
    g2.dispose();
    JLabel label = new JLabel(new ImageIcon(bi));
    showInFrame(label, "image of table");

编辑:对 TextAreaRenderer 的评论

一般规则是永远不要更改渲染器的 getXXRendererComponent 中的调用表,严格来说,作为参数给出的表被视为只读。如您在此处看到的,违反规则可能会导致丑陋的循环(在绘制时设置新的 rowHeight 会触发新的绘制请求)或伪影(无法保证何时调用渲染器,因此可能已设置或未设置正确的 rowheight)。

改为在外面的某个地方进行测量。在检测到可能导致更新大小的变化(模型中的 f.i.)时,遍历行,测量其所有单元格并更新到最大。只需从渲染器中提取所有大小调整代码。

【讨论】:

  • 尽可能简单,我的错我又把简单的事情复杂化了+1
  • @kleopatra 感谢您提供此代码 sn-p 但仅部分解决了我的问题,表头现在可见。
【解决方案2】:

我可以在这里看到一些问题。

  • 在绘制图像时应该使用 printAll 而不是paint。

  • 在调用 pack 方法时设置表格的高度,但这是在填充表格之前。如果您在生成表格后立即创建图像,则可能未设置大小。您应该在包装框架之前填充表格 - 这应该确保在您需要时可以使用尺寸。

编辑:在您更改代码后,我建议删除滚动窗格(如 kleopatra 建议的那样),然后使用 printAll。 paint 不应该用于图像,因为它可以使用双缓冲。要查看标题,您需要使用 kleopatra 提供的代码设置其大小。表头的大小与表无关,因此在表上调用 setSize 不会改变表头。

【讨论】:

  • 我刚刚用 printAll 替换了paint 并检查了,我仍然面临这个问题。是的,我在创建表格后立即创建图像,我只是用应用程序框架尝试过它,即使我得到与上面相同的图像。此外,我不想使用 JFrame 或 ApplicationFrame,因为我将传递要由 servlet 显示的表对象。
  • @Russ Hayward JTable 应该被添加到JScrollPane,然后可能是关于ViewPort 的建议...,但没有人知道通过命令 OP 的描述
  • @mKorbel 再次随机猜测 ;-)
  • @mKorbel 将表添加到此处的 JScrollPane 中:new JScrollPane(table)。我同意滚动窗格绝对不是一个好主意。
  • 好奇:双缓冲有什么问题?只要图像正确,我就不会在意...
【解决方案3】:

我浏览了这个位置 Truncated JTable print output 的帖子,并在那个位置包含了答案,它现在似乎工作正常。

感谢您的帮助

【讨论】:

  • 该答案是错误的,即使它可能适用于您的特定情况。做。不是。改变。调用者的.State.In.Renderer。在此处查看我的答案并在此处查看我的评论
猜你喜欢
  • 2017-12-15
  • 1970-01-01
  • 2020-08-23
  • 2014-10-06
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2012-05-06
相关资源
最近更新 更多