截断的JTable打印输出 [英] Truncated JTable print output

查看:121
本文介绍了截断的JTable打印输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用JTextArea作为其TableCellRenderer的JTable,因此表格单元格可以使用自动换行。 JTable显示正常。当我通过JTable 打印方法,输出总是截断大约60%的数据。我尝试过不同的计算机和不同的打印机,以及不同的打印机驱动程序,不同的JVM版本(1.5,1.6),但这些都没有帮助。下面是一个自包含的Java主类,可以重现该问题。有什么想法吗?

I have a JTable that uses JTextArea as its TableCellRenderer, so that table cells can utilize word wrap. The JTable displays fine. When I print the table to a printer via JTable's print method, the output is always truncated at approximately 60% of the data. I have tried different computers and different printers, and different printer drivers, different JVM versions (1.5, 1.6) but none of that has helped. Below is a self-contained Java main class that reproduces the problem. Any ideas?

import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;

public class JTextAreaJTableTest extends javax.swing.JFrame {

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                JTextAreaJTableTest frame = new JTextAreaJTableTest();
                frame.setSize(640, 480);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    JButton jButtonPrint;
    JScrollPane jScrollPane;
    JTable jTable;
    JToolBar jToolBar;

    public JTextAreaJTableTest() {
        initComponents();

        DefaultTableModel dtm = (DefaultTableModel) jTable.getModel();
        Vector<Vector<String>> data = new Vector<Vector<String>>();
        for (int i = 0; i < 50; i++) {
            Vector<String> rowData = new Vector<String>();
            rowData.add("Entry " + i);
            rowData.add("Lorem ipsum dolor sit amet, consectetur adipisicing"
                    + " elit, sed do eiusmod tempor incididunt ut labore et"
                    + " dolore magna aliqua. Ut enim ad minim veniam, quis"
                    + " nostrud exercitation ullamco laboris nisi ut aliquip"
                    + " ex ea commodo consequat. Duis aute irure dolor in"
                    + " reprehenderit in voluptate velit esse cillum dolore"
                    + " eu fugiat nulla pariatur. Excepteur sint occaecat"
                    + " cupidatat non proident, sunt in culpa qui officia"
                    + " deserunt mollit anim id est laborum. " + i);
            data.add(rowData);
        }
        Vector<String> columnNames = new Vector<String>();
        columnNames.add("Key");
        columnNames.add("Value");
        dtm.setDataVector(data, columnNames);
        jTable.setDefaultRenderer(String.class, null);
        jTable.getColumnModel().getColumn(0).setCellRenderer(
                new TextAreaCellRenderer());
        jTable.getColumnModel().getColumn(1).setCellRenderer(
                new TextAreaCellRenderer());
    }

    private void initComponents() {
        jToolBar = new JToolBar();
        jButtonPrint = new JButton();
        jScrollPane = new JScrollPane();
        jTable = new JTable();

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        jToolBar.setRollover(true);

        jButtonPrint.setText("Print");
        jButtonPrint.setFocusable(false);
        jButtonPrint.setHorizontalTextPosition(SwingConstants.CENTER);
        jButtonPrint.setVerticalTextPosition(SwingConstants.BOTTOM);
        jButtonPrint.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                jButtonPrintActionPerformed(evt);
            }
        });
        jToolBar.add(jButtonPrint);

        getContentPane().add(jToolBar, BorderLayout.NORTH);

        jScrollPane.setViewportView(jTable);

        getContentPane().add(jScrollPane, BorderLayout.CENTER);
    }

    private void jButtonPrintActionPerformed(ActionEvent evt)                                             
    {                                                 
        try {
            jTable.print();
        } catch (PrinterException ex) {
            ex.printStackTrace();
        }
    }                                            

    public static class TextAreaCellRenderer extends JTextArea implements
            TableCellRenderer {

        public TextAreaCellRenderer() {
            this.setLineWrap(true);
            this.setWrapStyleWord(true);
        }

        public Component getTableCellRendererComponent(JTable table, 
                Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {
            this.setText(String.valueOf(value));
            TableColumnModel columnModel = table.getColumnModel();
            this.setSize(columnModel.getColumn(column).getWidth(), 1);
            int newHeight = this.getPreferredSize().height;
            if (newHeight > table.getRowHeight(row)) {
                table.setRowHeight(row, this.getPreferredSize().height);
            }
            return this;
        }
    }
}


推荐答案

我相信我找到了根本原因和解决方案。印刷问题源于桌子的高度错误。该表的高度错误,因为某些表的行高度错误。有些行的高度错误,因为它们的单元格渲染器尚未被JTable调用(也就是说,它们的 getTableCellRendererComponent 方法尚未被调用。)JTable跳过一些原因单元格渲染器的优化是 - 它跳过的单元格渲染器用于屏幕外的单元格 - 屏幕外表示不需要渲染; JTable在这方面的优化是有道理的。

I believe I found the root cause and a solution. The print problem stems from the fact that the table is the wrong height. The table is the wrong height because some of the table's rows are the wrong height. Some of the rows are the wrong height because their cell renderers have not been invoked by JTable (that is, their getTableCellRendererComponent method has not been called.) The reason JTable is skipping some of the cell renderers is optimization -- the cell renderers it skips are for cells that are offscreen -- offscreen means rendering isn't needed; JTable's optimization in this area makes sense.

但是,渲染器是程序中唯一一个设置了每个行的正确高度的位置。我在单元格渲染器中设置行高的选择在某种程度上是可以理解的,因为单元格渲染器处于最佳位置以了解该行的高度。

However, the renderers are the only place in the program where the correct height of each individual row is set. My choice to set the row height in the cell renderer is somewhat understandable because the cell renderer is in the best position to know what height the row should be.

修复此示例程序最直接的方法是在每个单元格渲染器上手动调用 getTableCellRendererComponent (这应该在修改表的模型数据之后完成。)这使渲染器有机会将表中的每一行设置为正确的单独高度。每行都在正确的高度,JTable总体上最终是正确的高度,这似乎解决了打印截断问题。以下代码显示了访问所有渲染器:

It seems the most straight-forward way to fix this example program is to manually call getTableCellRendererComponent on every cell renderer (this should be done after modifying the table's model data.) This gives the renderers an opportunity to set every single row in the table to its correct individual height. With each row at its correct height, the JTable overall ends up being the correct height, which seems to resolve the print truncation issue. The following code shows visiting all the renderers to do just that:

for (int colIdx = 0; colIdx < jTable.getColumnCount(); colIdx++)
{
    for (int rowIdx = 0; rowIdx < jTable.getRowCount(); rowIdx++)
    {
        TableColumnModel columnModel = jTable.getColumnModel();
        TableColumn column = columnModel.getColumn(colIdx);
        TableCellRenderer renderer = column.getCellRenderer();
        Object cellValue = jTable.getValueAt(rowIdx, colIdx);
        renderer.getTableCellRendererComponent(jTable, cellValue, 
                    false, false, rowIdx, colIdx);
    }
}

所有单元格渲染器的手动访问绕过JTable的优化仅调用屏幕上单元格的单元格渲染器。因此,您可能只想在用户请求打印之后(但在调用JTable上的print方法之前)执行此变通方法代码。如果用户只使用GUI而不是打印,这可以使JTable优化保持有效。

This manual visitation of all cell renderers bypasses JTable's optimization of only invoking the cell renderers of on-screen cells. As such, you may want to only execute this workaround code after the user has requested printing (but before calling the print method on the JTable). This lets the JTable optimization stay in effect if the user is just using the GUI and not printing.

这篇关于截断的JTable打印输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆