java - jtable 到图像的转换未正确发生

标签 java image swing jtable

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

生成表格的代码是

  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();
    }

表格的图片是here

更新1:我可能已经找到问题的原因了。我使用以下代码片段来增加单元格的大小,以便将文本包装到单元格中。包括导致问题的代码 私有(private)最终 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) 创建表对象时,我使用上面相同的代码生成图像,序列化的 HashMap 被读取并插入到 table_model

最佳答案

基本上,您必须为要绘制到图像的所有组件(在本例中是表格和表头)进行布局工作,方法是设置它们的大小(低于首选项)用来)。

顺便说一句,添加到 JScrollPane 没有帮助(如您所见),除非实现了 Pane - 添加标题是由 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),如您在此处看到的。

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

关于java - jtable 到图像的转换未正确发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6593499/

相关文章:

java - 如何测试GWT的RPC调用?

javascript - 使用 JavaScript 从 JPEG 中读取 JPEG 注释的最合适方法是什么?

ios - 快速滚动时在 UITableView 单元格中异步加载了错误的图片

java - 使用计时器的基本java子弹动画

java - 在 ArrayList 与 LinkedList 中间插入

java - JFileChooser 和 Jbutton 错误

java - 如何让嵌入式Jpanel走向WEST

Java Swing 循环运行多个模拟

java - Map的订单输出

javascript - Safari 中的 CSS 缩放问题