I want to print a JTable
with background image or water mark. My code is:
public void actionPerformed(ActionEvent ae)
{
boolean status=false;
MessageFormat header = null;
header = new MessageFormat("Header");
MessageFormat footer = null;
footer = new MessageFormat("Page");
boolean fitWidth = true;
boolean showPrintDialog = true;
boolean interactive = true;
/* determine the print mode */
JTable.PrintMode mode = fitWidth ? JTable.PrintMode.FIT_WIDTH
: JTable.PrintMode.NORMAL;
try
{
status = jt.print(mode, header, footer,showPrintDialog,null,interactive);
if(status ==true)
{
frame.dispose();
}
}
catch(Exception ee)
{
System.out.println(ee.getMessage());
}
}
How can I pass or set the background image in this method?
there no easy way to set whatever for BackGround for whole JTable, but JViewPort from JScrollPane can do that easilly, then doesn't matter if is inside JScrollPane
a JTable
or another JComponents
for example
import java.awt.*;
import javax.swing.*;
class ImageAsTableBackround {
private JScrollPane sp;
private JTable table;
private String[] head = {"One", "Two", "Three", "Four", "Five", "Six"};
private String[][] data = new String[25][6];
public void buildGUI() {
sp = new JScrollPane();
// uncomment these codes lines for panting an image from package,
// but then block code table = new TableBackroundPaint0(data, head);
//sp.setViewport(new ImageViewport());
//table = new JTable(data, head);
//table.setOpaque(false);
// code for painting from generated code
table = new TableBackroundPaint0(data, head);
table.setBackground(new Color(0, 0, 0, 0));
table.setFillsViewportHeight(true);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
sp.setViewportView(table);
JFrame frame = new JFrame();
frame.getContentPane().add(sp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
class ImageViewport extends JViewport {
private static final long serialVersionUID = 1L;
private Image img;
public ImageViewport() {
try {
ImageIcon image = new ImageIcon(getClass().getResource("resources/PICT6090.jpg"));
img = image.getImage();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
} else {
g.drawString("This space for rent", 50, 50);
}
}
}
class TableBackroundPaint0 extends JTable {
private static final long serialVersionUID = 1L;
TableBackroundPaint0(Object[][] data, Object[] head) {
super(data, head);
setOpaque(false);
((JComponent) getDefaultRenderer(Object.class)).setOpaque(false);
}
@Override
public void paintComponent(Graphics g) {
Color background = new Color(168, 210, 241);
Color controlColor = new Color(230, 240, 230);
int width = getWidth();
int height = getHeight();
Graphics2D g2 = (Graphics2D) g;
Paint oldPaint = g2.getPaint();
g2.setPaint(new GradientPaint(0, 0, background, width, 0, controlColor));
g2.fillRect(0, 0, width, height);
g2.setPaint(oldPaint);
for (int row : getSelectedRows()) {
Rectangle start = getCellRect(row, 0, true);
Rectangle end = getCellRect(row, getColumnCount() - 1, true);
g2.setPaint(new GradientPaint(start.x, 0, controlColor, (int) ((end.x + end.width - start.x) * 1.25), 0, Color.orange));
g2.fillRect(start.x, start.y, end.x + end.width - start.x, start.height);
}
super.paintComponent(g);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ImageAsTableBackround().buildGUI();
}
});
}
}
The problem has two parts
- print an image an each page
- be sure the image "shines-through" the table
the second is addressed by @mKorbel (though not really solved because there is no nice solution :-)
To solve the first, I would go for a custom Printable and subclass JTable to return it, something like
public class BackgroundPrintable implements Printable {
Printable tablePrintable;
JTable table;
MessageFormat header;
MessageFormat footer;
BufferedImage background;
public BackgroundPrintable(MessageFormat header, MessageFormat footer) {
this.header = header;
this.footer = footer;
}
public void setTablePrintable(JTable table, Printable printable) {
tablePrintable = printable;
this.table = table;
}
@Override
public int print(Graphics graphics, PageFormat pageFormat,
int pageIndex) throws PrinterException {
printImage(graphics, pageFormat, pageIndex);
int exists = tablePrintable.print(graphics, pageFormat, pageIndex);
if (exists != PAGE_EXISTS) {
return exists;
}
return PAGE_EXISTS;
}
private void printImage(Graphics graphics, PageFormat pageFormat,
int pageIndex) {
// grab an untainted graphics
Graphics2D g2d = (Graphics2D)graphics.create();
// do the image painting
....
// cleanup
g2d.dispose();
}
}
// use in JTable subclass
@Override
public Printable getPrintable(PrintMode printMode,
MessageFormat headerFormat, MessageFormat footerFormat) {
Printable printable = super.getPrintable(printMode, null, null);
BackgroundPrintable custom = new BackgroundPrintable(headerFormat, footerFormat);
custom.setTablePrintable(this, printable);
return custom;
}
To achieve the second, both the JTable and its renderers must be transparent. Tricky, because:
- probably only if printing - otherwise they should have their usual opacity
- all of the renderers must be transparent, and there is no completely safe way to get hold of them all
A custom JTable could try to achieve that by forcing the rendering component's opacity in its prepareRenderer:
@Override
public Component prepareRenderer(TableCellRenderer renderer,
int row, int column) {
JComponent comp = (JComponent) super.prepareRenderer(renderer, row, column);
if (isPaintingForPrint()) {
comp.setOpaque(false);
} else {
comp.setOpaque(true);
}
return comp;
}
Actually, that's not entirely valid: the code in the else block might be the wrong-thing-to-do for naturally transparent components. No really reliable solution available, I'm afraid.
精彩评论