表格打印不适合页面大小 [英] Table Print does not fit to page size
问题描述
所以,我有一个打印"按钮,它使用自定义的打印"功能打印我的 jTable2.我还使用调整大小"功能来调整列的大小以进行打印.但是,我试图使表格适合页面的宽度,但它没有这样做,即使我将 PrintMode 更改为 FIT_WIDTH 或 NORMAL,它们之间也没有区别.另外,我尝试过更改表格的字体大小,但也没有用.代码如下:
So, I have a "print" button, that prints my jTable2 using a custom "print" function. I also use a "resize" function, to resize the columns for printing. But, I've tried to make the table fit the width of the page, but it doesn't do this, even if I change the PrintMode to FIT_WIDTH, or NORMAL, it has no difference between them. Also, I've tried changing the font size of the table, but it didn't work too. Here is the code:
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("
").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 <= 0) {
throw new PrinterException("Height of printable area is too small.");
}
// depending on the print mode, we may need a scale factor to
// fit the table's entire width on the page
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;
}
// 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 < pageIndex) {
// if we are finished all columns in all rows
if (row >= 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("
");
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("
");
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() < imgWidth) {
tx = (int) (imgWidth / 2 - g2d.getFontMetrics().getStringBounds(lines[i], g2d).getWidth() / 2);
// otherwise, if the table is LTR, ensure the left side of
// the text shows; the right can be clipped
} else if (table.getComponentOrientation().isLeftToRight()) {
tx = 0;
// otherwise, ensure the right side of the text shows
} else {
tx = -(int) (Math.ceil(rect.getWidth()) - imgWidth);
}
int ty = (int) Math.ceil(Math.abs(rect.getY() + i * rect.getHeight() / lines.length));
g2d.drawString(lines[i], tx, ty);
}
}
private void findNextClip(int pw, int ph) {
final boolean ltr = table.getComponentOrientation().isLeftToRight();
// if we're ready to start a new set of rows
if (col == 0) {
if (ltr) {
// adjust clip to the left of the first column
clip.x = 0;
} else {
// adjust clip to the right of the first column
clip.x = totalColWidth;
}
// adjust clip to the top of the next set of rows
clip.y += clip.height;
// adjust clip width and height to be zero
clip.width = 0;
clip.height = 0;
// fit as many rows as possible, and at least one
int rowCount = table.getRowCount();
int rowHeight = table.getRowHeight(row);
do {
clip.height += rowHeight;
if (++row >= rowCount) {
break;
}
rowHeight = table.getRowHeight(row);
} while (clip.height + rowHeight <= ph);
}
// we can short-circuit for JTable.PrintMode.FIT_WIDTH since
// we'll always fit all columns on the page
if (printMode == JTable.PrintMode.FIT_WIDTH) {
clip.x = 0;
clip.width = totalColWidth;
return;
}
if (ltr) {
// adjust clip to the left of the next set of columns
clip.x += clip.width;
}
// adjust clip width to be zero
clip.width = 0;
// fit as many columns as possible, and at least one
int colCount = table.getColumnCount();
int colWidth = colModel.getColumn(col).getWidth();
do {
clip.width += colWidth;
if (!ltr) {
clip.x -= colWidth;
}
if (++col >= 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 < minWidths.length; i++) {
if (minWidths[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 < widths.length; i++) {
if (widths[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
Nã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
Certifique-se de que todos os
campos estejam preenchidos corretamente.");
System.out.println("Problema com o SQL");
ex.printStackTrace();
}
MessageFormat header = new MessageFormat("Ficha Pedagógica - " + jComboBox1.getSelectedItem() + "
Nome 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
And here's a image of how the page is looking at the moment: http://i.imgur.com/29gHNnj.png
我想说的是页面上的表格非常小,我希望调整其大小以适合页面宽度,并且字体可以更大.我该怎么做?
What I'm trying to say is that the table is very small on the page, and I want it to be resized to fit the page width, and that the font can be bigger. How can I do that?
推荐答案
您有两种可能的选择,您可以尝试调整列的大小,使其在可用页面宽度上均匀分布,或者您可以将结果输出放大所以它适合页面.
There are two possible options you have, you could try and resize the columns so that are evenly distributed across the available page width OR you could scale the resulting output UP so it fits the page.
默认情况下,TablePrintable
只向下缩放,迫使 JTable
太大而无法适应可用的页面大小(宽度).您可以更改此设置以允许它也向上扩展.
By default, the TablePrintable
only scales DOWN, forcing a JTable
that is too large to fit within the available page size (width). You can change this to allow it to also scale UP.
计算比例的这段代码位于 TablePrintable
类的 print
中,看起来像...
The piece of code that calculates the scale is within the print
of the TablePrintable
class and looks like...
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
语句,它读取if printmode 等于 FIT_WIDTH AND the totalColWidth 大于页面宽度"...我们想将其更改为""如果打印模式等于 FIT_WIDTH"只有...
The part we're interested in is the if
statement, which reads "if printmode equals FIT_WIDTH AND the totalColWidth is greater the the page width"...We want to change this to read ""if printmode equals FIT_WIDTH" only...
你可以改变
if (printMode == JTable.PrintMode.FIT_WIDTH && totalColWidth > imgWidth) {
到
if (printMode == JTable.PrintMode.FIT_WIDTH) {
现在允许 TablePrintable
向上和向下缩放表格...
which will now allow the TablePrintable
to both scale the table UP and DOWN...
这将导致类似......
Which will result in something like...
- 顶部是屏幕输出
- 左边是当前结果
- 右边是缩放后的结果
这有点棘手,不应该应用于已经在屏幕上的 JTable
,因为这会干扰它的实际显示方式...
This is a little more tricky and SHOULD never be applied to a JTable
that is already on the screen, as this will mess with how it is actually displayed...
基本上,当表格被打印出来时,我们将覆盖列宽,让它们在整个页面上具有相等的空间...
Basically, when the table is printed, we're going to override the column widths to give them equal space across the page...
首先,我们需要将TablePrintable
中的totalColWidth
从...
First, we need to change totalColWidth
in TablePrintable
from...
private final int totalColWidth;
到
private int totalColWidth;
因为我们需要能够在初始化后修改值...
because we need to be able to modify the value after it's initialised...
接下来,我们需要一个标志来确定列是否已被修改,因为每次调用 print
时都必须重复更新它们的大小是一种浪费.
Next, we need a flag to determine if the columns have been modified or not, as it's a waste to have to repeatedly update their sizes every time print
is called.
在TablePrintable
的字段中添加private boolean updateColumnWidths;
(例如在private final Font footerFont;
下)
Add private boolean updateColumnWidths;
to the fields of TablePrintable
(for example, under private final Font footerFont;
)
现在,当print
被调用时,我们需要做出一系列的决定......
Now, when print
is called, we need to make a series of decisions...
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;
}
//...
产生类似......的东西
Which generates something like...
这篇关于表格打印不适合页面大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!