表格打印不适合页面大小

所以,我有一个“打印”按钮,使用自定义“打印”function打印我的jTable2。 我还使用“resize”function来调整列的大小以进行打印。 但是,我试图使表格适合页面的宽度,但它不会这样做,即使我将PrintMode更改为FIT_WIDTH,或者NORMAL,它们之间没有区别。 此外,我已经尝试更改表的字体大小,但它也没有工作。 这是代码:

package sistemabt; import java.sql.*; import java.util.Vector; import javax.swing.JApplet; import javax.swing.JOptionPane; import javax.swing.table.DefaultTableModel; import java.awt.*; import java.awt.event.*; import java.text.*; import java.awt.print.*; import javax.swing.JTable; import javax.swing.table.TableColumn.*; import javax.swing.table.JTableHeader; import javax.swing.table.TableColumnModel; import java.awt.geom.Rectangle2D; import java.awt.geom.AffineTransform; import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.print.PrinterException; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import java.awt.Component; import java.awt.FontMetrics; public class FormNotas extends javax.swing.JFrame { private String driver = "org.postgresql.Driver"; private String banco = "bancoBT"; private String host = "localhost"; private String str_conn = "jdbc:postgresql://localhost:5432/" + banco; private String usuario = "postgres"; private String senha = "root"; public static Connection con; private Statement stmt; private ResultSet rs; public String sql; public PreparedStatement pst; static class TablePrintable implements Printable { private final JTable table; private final JTableHeader header; private final TableColumnModel colModel; private final int totalColWidth; private final JTable.PrintMode printMode; private final MessageFormat headerFormat; private final MessageFormat footerFormat; private int last = -1; private int row = 0; private int col = 0; private final Rectangle clip = new Rectangle(0, 0, 0, 0); private final Rectangle hclip = new Rectangle(0, 0, 0, 0); private final Rectangle tempRect = new Rectangle(0, 0, 0, 0); private static final int H_F_SPACE = 8; private static final float HEADER_FONT_SIZE = 18.0f; private static final float FOOTER_FONT_SIZE = 15.0f; private final Font headerFont; private final Font footerFont; public TablePrintable(JTable table, JTable.PrintMode printMode, MessageFormat headerFormat, MessageFormat footerFormat) { this.table = table; header = table.getTableHeader(); colModel = table.getColumnModel(); totalColWidth = colModel.getTotalColumnWidth(); if (header != null) { // the header clip height can be set once since it's unchanging hclip.height = header.getHeight(); } this.printMode = printMode; this.headerFormat = headerFormat; this.footerFormat = footerFormat; // derive the header and footer font from the table's font headerFont = table.getFont().deriveFont(Font.BOLD, HEADER_FONT_SIZE); footerFont = table.getFont().deriveFont(Font.PLAIN, FOOTER_FONT_SIZE); } @Override public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { // for easy access to these values final int imgWidth = (int) pageFormat.getImageableWidth(); final int imgHeight = (int) pageFormat.getImageableHeight(); if (imgWidth <= 0) { throw new PrinterException("Width of printable area is too small."); } // to pass the page number when formatting the header and footer // text Object[] pageNumber = new Object[]{Integer.valueOf(pageIndex + 1)}; // fetch the formatted header text, if any String headerText = null; if (headerFormat != null) { headerText = headerFormat.format(pageNumber); } // fetch the formatted footer text, if any String footerText = null; if (footerFormat != null) { footerText = footerFormat.format(pageNumber); } // to store the bounds of the header and footer text Rectangle2D hRect = null; Rectangle2D fRect = null; // the amount of vertical space needed for the header and footer // text int headerTextSpace = 0; int footerTextSpace = 0; // the amount of vertical space available for printing the table int availableSpace = imgHeight; // if there's header text, find out how much space is needed for it // and subtract that from the available space if (headerText != null) { graphics.setFont(headerFont); int nbLines = headerText.split("\n").length; hRect = graphics.getFontMetrics().getStringBounds(headerText, graphics); hRect = new Rectangle2D.Double(hRect.getX(), Math.abs(hRect.getY()), hRect.getWidth(), hRect.getHeight() * nbLines); headerTextSpace = (int) Math.ceil(hRect.getHeight() * nbLines); availableSpace -= headerTextSpace + H_F_SPACE; } // if there's footer text, find out how much space is needed for it // and subtract that from the available space if (footerText != null) { graphics.setFont(footerFont); fRect = graphics.getFontMetrics().getStringBounds(footerText, graphics); footerTextSpace = (int) Math.ceil(fRect.getHeight()); availableSpace -= footerTextSpace + H_F_SPACE; } if (availableSpace  imgWidth) { // if not, we would have thrown an acception previously assert imgWidth > 0; // it must be, according to the if-condition, since imgWidth > 0 assert totalColWidth > 1; sf = (double) imgWidth / (double) totalColWidth; } // dictated by the previous two assertions assert sf > 0; // This is in a loop for two reasons: // First, it allows us to catch up in case we're called starting // with a non-zero pageIndex. Second, we know that we can be called // for the same page multiple times. The condition of this while // loop acts as a check, ensuring that we don't attempt to do the // calculations again when we are called subsequent times for the // same page. while (last = table.getRowCount() && col == 0) { return NO_SUCH_PAGE; } // rather than multiplying every row and column by the scale // factor // in findNextClip, just pass a width and height that have // already // been divided by it int scaledWidth = (int) (imgWidth / sf); int scaledHeight = (int) ((availableSpace - hclip.height) / sf); // calculate the area of the table to be printed for this page findNextClip(scaledWidth, scaledHeight); last++; } // create a copy of the graphics so we don't affect the one given to // us Graphics2D g2d = (Graphics2D) graphics.create(); // translate into the co-ordinate system of the pageFormat g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); // to save and store the transform AffineTransform oldTrans; // if there's footer text, print it at the bottom of the imageable // area if (footerText != null) { oldTrans = g2d.getTransform(); g2d.translate(0, imgHeight - footerTextSpace); String[] lines = footerText.split("\n"); printText(g2d, lines, fRect, footerFont, imgWidth); g2d.setTransform(oldTrans); } // if there's header text, print it at the top of the imageable area // and then translate downwards if (headerText != null) { String[] lines = headerText.split("\n"); printText(g2d, lines, hRect, headerFont, imgWidth); g2d.translate(0, headerTextSpace + H_F_SPACE); } // constrain the table output to the available space tempRect.x = 0; tempRect.y = 0; tempRect.width = imgWidth; tempRect.height = availableSpace; g2d.clip(tempRect); // if we have a scale factor, scale the graphics object to fit // the entire width if (sf != 1.0D) { g2d.scale(sf, sf); // otherwise, ensure that the current portion of the table is // centered horizontally } else { int diff = (imgWidth - clip.width) / 2; g2d.translate(diff, 0); } // store the old transform and clip for later restoration oldTrans = g2d.getTransform(); Shape oldClip = g2d.getClip(); // if there's a table header, print the current section and // then translate downwards if (header != null) { hclip.x = clip.x; hclip.width = clip.width; g2d.translate(-hclip.x, 0); g2d.clip(hclip); header.print(g2d); // restore the original transform and clip g2d.setTransform(oldTrans); g2d.setClip(oldClip); // translate downwards g2d.translate(0, hclip.height); } // print the current section of the table g2d.translate(-clip.x, -clip.y); g2d.clip(clip); table.print(g2d); // restore the original transform and clip g2d.setTransform(oldTrans); g2d.setClip(oldClip); // draw a box around the table g2d.setColor(Color.BLACK); g2d.drawRect(0, 0, clip.width, hclip.height + clip.height); // dispose the graphics copy g2d.dispose(); return PAGE_EXISTS; } private void printText(Graphics2D g2d, String[] lines, Rectangle2D rect, Font font, int imgWidth) { g2d.setColor(Color.BLACK); g2d.setFont(font); for (int i = 0; i < lines.length; i++) { int tx; // if the text is small enough to fit, center it if (rect.getWidth() = rowCount) { break; } rowHeight = table.getRowHeight(row); } while (clip.height + rowHeight = colCount) { // reset col to 0 to indicate we're finished all columns col = 0; break; } colWidth = colModel.getColumn(col).getWidth(); } while (clip.width + colWidth <= pw); } } static class ColumnsAutoSizer { public static void sizeColumnsToFit(JTable table) { sizeColumnsToFit(table, 3); } public static void sizeColumnsToFit(JTable table, int columnMargin) { JTableHeader tableHeader = table.getTableHeader(); if (tableHeader == null) { // can't auto size a table without a header return; } FontMetrics headerFontMetrics = tableHeader.getFontMetrics(tableHeader.getFont()); int[] minWidths = new int[table.getColumnCount()]; int[] maxWidths = new int[table.getColumnCount()]; for (int columnIndex = 0; columnIndex < table.getColumnCount(); columnIndex++) { int headerWidth = headerFontMetrics.stringWidth(table.getColumnName(columnIndex)); minWidths[columnIndex] = headerWidth + columnMargin; int maxWidth = getMaximalRequiredColumnWidth(table, columnIndex, headerWidth); maxWidths[columnIndex] = Math.max(maxWidth, minWidths[columnIndex]) + columnMargin; } adjustMaximumWidths(table, minWidths, maxWidths); for (int i = 0; i  0) { table.getColumnModel().getColumn(i).setMinWidth(minWidths[i]); } if (maxWidths[i] > 0) { table.getColumnModel().getColumn(i).setMaxWidth(maxWidths[i]); table.getColumnModel().getColumn(i).setWidth(maxWidths[i]); } } } private static void adjustMaximumWidths(JTable table, int[] minWidths, int[] maxWidths) { if (table.getWidth() > 0) { // to prevent infinite loops in exceptional situations int breaker = 0; // keep stealing one pixel of the maximum width of the highest column until we can fit in the width of the table while (sum(maxWidths) > table.getWidth() && breaker < 10000) { int highestWidthIndex = findLargestIndex(maxWidths); maxWidths[highestWidthIndex] -= 1; maxWidths[highestWidthIndex] = Math.max(maxWidths[highestWidthIndex], minWidths[highestWidthIndex]); breaker++; } } } private static int getMaximalRequiredColumnWidth(JTable table, int columnIndex, int headerWidth) { int maxWidth = headerWidth; TableColumn column = table.getColumnModel().getColumn(columnIndex); TableCellRenderer cellRenderer = column.getCellRenderer(); if (cellRenderer == null) { cellRenderer = new DefaultTableCellRenderer(); } for (int row = 0; row < table.getModel().getRowCount(); row++) { Component rendererComponent = cellRenderer.getTableCellRendererComponent(table, table.getModel().getValueAt(row, columnIndex), false, false, row, columnIndex); double valueWidth = rendererComponent.getPreferredSize().getWidth(); maxWidth = (int) Math.max(maxWidth, valueWidth); } return maxWidth; } private static int findLargestIndex(int[] widths) { int largestIndex = 0; int largestValue = 0; for (int i = 0; i  largestValue) { largestIndex = i; largestValue = widths[i]; } } return largestIndex; } private static int sum(int[] widths) { int sum = 0; for (int width : widths) { sum += width; } return sum; } } /** * Creates new form FormNotas */ public FormNotas() { initComponents(); try { try { Class.forName(driver); } catch (ClassNotFoundException ex) { ex.printStackTrace(); } con = DriverManager.getConnection(str_conn, usuario, senha); stmt = con.createStatement(); sql = "select Nome_Curso from curso order by Nome_Curso"; rs = stmt.executeQuery(sql); while (rs.next()) { jComboBox1.addItem(rs.getString("Nome_Curso")); } } catch (SQLException ex) { JOptionPane.showMessageDialog(null, "Ocorreu um erro ao carregar o ComboBox"); System.out.println("Ocorreu um erro ao carregar o ComboBox"); } try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } DefaultTableModel model = new DefaultTableModel(0, 26); for (int row = 0; row < 26; row++) { Vector data = new Vector(26); for (int col = 0; col < 26; col++) { String value = row + "x" + ((char) (col + 'A')); data.add(value); } model.addRow(data); } JTable jTable2 = new JTable(model); } private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) { Vector vetColuna = new Vector(); Vector vetLinhas = new Vector(); try { Class.forName(driver); con = DriverManager.getConnection(str_conn, usuario, senha); stmt = con.createStatement(); sql = "select topico, nota, datanota from notas where notas.cod_aluno =" + jTextField1.getText() + " and notas.cod_curso =" + jTextField2.getText() + " order by notas.datanota"; rs = stmt.executeQuery(sql); if (rs == null) { return; } ResultSetMetaData rsmd; rsmd = rs.getMetaData(); for (int i = 0; i < rsmd.getColumnCount(); i++) { vetColuna.add(rsmd.getColumnLabel(i + 1)); } while (rs.next()) { Vector vetLinha = new Vector(); for (int i = 0; i < rsmd.getColumnCount(); i++) { vetLinha.add(rs.getObject(i + 1)); } vetLinhas.add(vetLinha); } } catch (ClassNotFoundException ex) { JOptionPane.showMessageDialog(null, "Erro\nNão foi possível carregar o driver."); System.out.println("Nao foi possivel carregar o driver"); ex.printStackTrace(); } catch (SQLException ex) { JOptionPane.showMessageDialog(null, "Erro\nCertifique-se de que todos os\ncampos estejam preenchidos corretamente."); System.out.println("Problema com o SQL"); ex.printStackTrace(); } MessageFormat header = new MessageFormat("Ficha Pedagógica - " + jComboBox1.getSelectedItem() + "\nNome do Aluno - " + jTextField1.getText()); jTable2.setModel(new DefaultTableModel(vetLinhas, vetColuna)); DefaultTableModel dtm = new DefaultTableModel(vetLinhas, vetColuna); JTable jTable2 = new JTable(dtm) { @Override public Printable getPrintable(PrintMode printMode, MessageFormat headerFormat, MessageFormat footerFormat) { return new TablePrintable(this, printMode, headerFormat, footerFormat); } }; ColumnsAutoSizer.sizeColumnsToFit(jTable2); try { jTable2.setSize(jTable2.getPreferredSize()); JTableHeader tableHeader = jTable2.getTableHeader(); tableHeader.setSize(tableHeader.getPreferredSize()); jTable2.print(JTable.PrintMode.FIT_WIDTH, header, null); } catch (PrinterException ex) { ex.printStackTrace(); } } 

这是一个关于页面如何看待当前图像的图像: http : //i.imgur.com/29gHNnj.png

我想说的是页面上的表格非常小​​,我希望它的大小适合页面宽度,并且字体可以更大。 我怎样才能做到这一点?

您有两种可能的选项,您可以尝试调整列的大小,使其均匀分布在可用的页面宽度上,或者您可以将结果输出向上缩放以使其适合页面。

缩放

默认情况下, TablePrintable仅缩放DOWN,强制JTable太大JTable适合可用的页面大小(宽度)。 您可以更改此设置以允许它也按比例缩放。

计算比例的代码片段在TablePrintable类的print内,看起来像……

 double sf = 1.0D; if (printMode == JTable.PrintMode.FIT_WIDTH && totalColWidth > imgWidth) { // if not, we would have thrown an acception previously assert imgWidth > 0; // it must be, according to the if-condition, since imgWidth > 0 assert totalColWidth > 1; sf = (double) imgWidth / (double) totalColWidth; } 

我们感兴趣的部分是if语句,它读取“如果printmode等于FIT_WIDTH并且totalColWidth大于页面宽度”……我们想要将此更改为“”如果printmode等于FIT_WIDTH“仅…

你可以改变

 if (printMode == JTable.PrintMode.FIT_WIDTH && totalColWidth > imgWidth) { 

 if (printMode == JTable.PrintMode.FIT_WIDTH) { 

现在允许TablePrintable扩展表UP和DOWN ……

这会产生类似……

结果

  • 顶部是屏幕输出
  • 左边是当前的结果
  • 正确的是缩放结果

调整列大小

这有点棘手,应该永远不会应用于已经在屏幕上的JTable ,因为这会弄乱它实际显示的方式……

基本上,当打印表格时,我们将覆盖列宽以在页面上给它们相等的空间……

首先,我们需要更改TablePrintable totalColWidth

 private final int totalColWidth; 

 private int totalColWidth; 

因为我们需要能够在初始化后修改它…

接下来,我们需要一个标志来确定列是否已被修改,因为每次调用print都必须重复更新它们的大小。

添加private boolean updateColumnWidths;TablePrintable的字段(例如,在private final Font footerFont;

现在,当print时,我们需要做出一系列决定……

 public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { // for easy access to these values final int imgWidth = (int) pageFormat.getImageableWidth(); final int imgHeight = (int) pageFormat.getImageableHeight(); if (imgWidth <= 0) { throw new PrinterException("Width of printable area is too small."); } // Have we modified the column widths yet?? if (!updateColumnWidths) { // Only update the column widths if the current total column width // is less then the available imgWidth (page width) if (totalColWidth < imgWidth) { // Calculate the required column width to allow the columns to // span the page... int columnCount = table.getColumnCount(); int columnWidth = (int) (imgWidth / (float) columnCount); TableColumnModel columnModel = table.getColumnModel(); // Update the columns... for (int col = 0; col < columnModel.getColumnCount(); col++) { TableColumn tc = columnModel.getColumn(col); tc.setMinWidth(columnWidth); tc.setMaxWidth(columnWidth); tc.setPreferredWidth(columnWidth); tc.setWidth(columnWidth); } // Update the totalColWidth, this should prevent // any scaling been applied totalColWidth = columnModel.getTotalColumnWidth(); } updateColumnWidths = true; } //... 

这会产生类似......

调整大小