I have a JTable
inside a JScrollPane
, which is under a JPanel
. I need to export the table as an image. It works fine if the table is small enough to be viewed completely in the JScrollPane
, without the scrollbar. But if the table is too big and needs scroller to go right and left or up and down, then only part of the table is visible in the exported image.
I am using the following code
public BufferedImage componentToImage( Component component, boolean visible)
{
if (visible)
{
BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TRANSLUCENT);
Graphics2D g2d = (Graphics2D) img.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
component.paintAll(g2d);
try
{
File outputfile = new File("C:\\Users\\SciOme Admin\\Desktop\\a.png");
ImageIO.write(img, "png", outputfile);
}
catch (IOException e)
{
e.printStackTrace();
}
return img;
}
}
where I am passing JScrollPane
as the component.
I am getting attached partial image, with scroll bars. But I need the complete JTable
.
I can't pass the JTable
as the component, as I am using two overlapping tables in the JScrollPane
. One table is used to just show the row headers and keep them visible always, even when scrolling to the right.
Based on you image, I would suggest that you are making use of the JScrollPane
's rowHeader
support. Rendering a JTable
is not an easy task at the best of times, normally you'd just make use of the table's inbuilt support for printing, but that doesn't take into account the JScrollPane
s rowHeader
, and a large enough table might want to print to multiple pages, and that just gets messy.
In your case, you're going to have to disassemble the JScrollPane
and render the rowHeader
, columnHeader
and main view
yourself.
At a "very" basic level, this would invoke calculating the overall size required to render all the components, calculating the offset positions for each component and painting them, something like this...
Component columnHeader = scrollPane.getColumnHeader().getView();
Component rowHeader = scrollPane.getRowHeader().getView();
Component view = scrollPane.getViewport().getView();
int width = rowHeader.getPreferredSize().width + view.getPreferredSize().width;
int height = columnHeader.getPreferredSize().height + view.getPreferredSize().height;
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
int xOffset = rowHeader.getPreferredSize().width;
int yOffset = columnHeader.getPreferredSize().height;
Graphics2D rowHeaderG = (Graphics2D) g2d.create();
rowHeaderG.translate(0, yOffset);
rowHeader.printAll(rowHeaderG);
rowHeaderG.dispose();
Graphics2D colHeaderG = (Graphics2D) g2d.create();
colHeaderG.translate(xOffset, 0);
columnHeader.printAll(colHeaderG);
colHeaderG.dispose();
Graphics2D viewG = (Graphics2D) g2d.create();
viewG.translate(xOffset, yOffset);
view.printAll(viewG);
viewG.dispose();
g2d.dispose();
I borrowed some code from an older example and implemented the basic idea as an example. Since I don't have your code, any additional issues you have you're going to have to try and solve yourself (it's hard to debug by crystal ball), but this should give you helping start
From the window...
to the image...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class TableRowHeaderTest {
public static void main(String[] args) {
new TableRowHeaderTest();
}
public TableRowHeaderTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Object rowData1[][]
= {
{"", "", "", ""},
{"", "", "", ""},
{"", "", "", ""},
{"", "", "", ""}
};
Object columnNames1[] = {"HEADER 1", "HEADER 2", "HEADER 3", "HEADER 4"};
JTable table1 = new TableWithRowHeader(rowData1, columnNames1);
table1.getColumnModel().getColumn(0).setPreferredWidth(120);
JScrollPane scrollPane1 = new JScrollPane(table1);
// scrollPane1.setColumnHeaderView(null);
JButton print = new JButton("Save");
print.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
print(scrollPane1);
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane1);
frame.add(print, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
protected void print(JScrollPane scrollPane) {
Component columnHeader = scrollPane.getColumnHeader().getView();
Component rowHeader = scrollPane.getRowHeader().getView();
Component view = scrollPane.getViewport().getView();
int width = rowHeader.getPreferredSize().width + view.getPreferredSize().width;
int height = columnHeader.getPreferredSize().height + view.getPreferredSize().height;
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
int xOffset = rowHeader.getPreferredSize().width;
int yOffset = columnHeader.getPreferredSize().height;
Graphics2D rowHeaderG = (Graphics2D) g2d.create();
rowHeaderG.translate(0, yOffset);
rowHeader.printAll(rowHeaderG);
rowHeaderG.dispose();
Graphics2D colHeaderG = (Graphics2D) g2d.create();
colHeaderG.translate(xOffset, 0);
columnHeader.printAll(colHeaderG);
colHeaderG.dispose();
Graphics2D viewG = (Graphics2D) g2d.create();
viewG.translate(xOffset, yOffset);
view.printAll(viewG);
viewG.dispose();
g2d.dispose();
try {
ImageIO.write(img, "png", new File("Test.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public class TableWithRowHeader extends JTable {
private TableRowHeader rowHeader;
public TableWithRowHeader(final Object[][] rowData, final Object[] columnNames) {
super(rowData, columnNames);
rowHeader = new TableRowHeader(this);
setGridColor(Color.LIGHT_GRAY);
}
@Override
protected void configureEnclosingScrollPane() {
// This is required as it calls a private method...
super.configureEnclosingScrollPane();
Container parent = SwingUtilities.getUnwrappedParent(this);
if (parent instanceof JViewport) {
JViewport port = (JViewport) parent;
Container gp = port.getParent();
if (gp instanceof JScrollPane) {
JScrollPane scrollPane = (JScrollPane) gp;
JViewport viewport = scrollPane.getViewport();
if (viewport == null || SwingUtilities.getUnwrappedView(viewport) != this) {
return;
}
// scrollPane.setColumnHeaderView(null);
scrollPane.setRowHeaderView(rowHeader);
}
}
}
}
public class TableRowHeader extends JTableHeader {
private JTable table;
public TableRowHeader(JTable table) {
super(table.getColumnModel());
this.table = table;
table.getColumnModel().addColumnModelListener(new TableColumnModelListener() {
@Override
public void columnAdded(TableColumnModelEvent e) {
repaint();
}
@Override
public void columnRemoved(TableColumnModelEvent e) {
repaint();
}
@Override
public void columnMoved(TableColumnModelEvent e) {
repaint();
}
@Override
public void columnMarginChanged(ChangeEvent e) {
repaint();
}
@Override
public void columnSelectionChanged(ListSelectionEvent e) {
// Don't care about this, want to highlight the row...
}
});
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
repaint();
}
});
}
public JTable getTable() {
return table;
}
@Override
public Dimension getPreferredSize() {
Dimension size = new Dimension();
JTable table = getTable();
if (table != null) {
TableColumnModel model = table.getColumnModel();
if (model != null) {
for (int index = 0; index < model.getColumnCount(); index++) {
TableColumn column = model.getColumn(index);
TableCellRenderer renderer = column.getHeaderRenderer();
if (renderer == null) {
renderer = getDefaultRenderer();
}
Component comp = renderer.getTableCellRendererComponent(table, column.getHeaderValue(), false, false, -1, index);
size.width = Math.max(comp.getPreferredSize().width, size.width);
size.height += table.getRowHeight(index);
}
}
}
return size;
}
/**
* Overridden to avoid propagating a invalidate up the tree when the
* cell renderer child is configured.
*/
@Override
public void invalidate() {
}
/**
* If the specified component is already a child of this then we don't
* bother doing anything - stacking order doesn't matter for cell
* renderer components (CellRendererPane doesn't paint anyway).
*/
@Override
protected void addImpl(Component x, Object constraints, int index) {
if (x.getParent() == this) {
return;
} else {
super.addImpl(x, constraints, index);
}
}
@Override
protected void paintComponent(Graphics g) {
// super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(getBackground());
g2d.fillRect(0, 0, getWidth(), getHeight());
JTable table = getTable();
if (table != null) {
int width = getWidth();
TableColumnModel model = table.getColumnModel();
if (model != null) {
for (int index = 0; index < model.getColumnCount(); index++) {
TableColumn column = model.getColumn(index);
TableCellRenderer renderer = column.getHeaderRenderer();
if (renderer == null) {
renderer = getDefaultRenderer();
}
boolean selected = table.getSelectedRow() == index;
Component comp = renderer.getTableCellRendererComponent(table, column.getHeaderValue(), selected, false, 0, index);
add(comp);
comp.validate();
int height = table.getRowHeight(index) - 1;
comp.setBounds(0, 0, width, height);
comp.paint(g2d);
comp.setBounds(-width, -height, 0, 0);
g2d.setColor(table.getGridColor());
g2d.drawLine(0, height, width, height);
g2d.translate(0, height + 1);
}
}
}
g2d.dispose();
removeAll();
}
}
}