java - 转换为 JScrollPane 中 JTable 的图像

标签 java swing jtable jscrollpane

我在 JScrollPane 内有一个 JTable,它位于 JPanel 下。我需要将表格导出为图像。如果表格足够小,可以在 JScrollPane 中完全查看,而无需滚动条,则效果很好。但如果表格太大并且需要滚动条左右或上下移动,则导出的图像中只能看到表格的一部分。 我正在使用以下代码

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;
    }
}

我将 JScrollPane 作为组件传递。 我正在附加带有滚动条的部分图像。但我需要完整的JTable

enter image description here

我无法将 JTable 作为组件传递,因为我在 JScrollPane 中使用两个重叠的表格。一张表仅用于显示行标题并使其始终可见,即使向右滚动也是如此。

最佳答案

根据您的图像,我建议您使用 JScrollPanerowHeader 支持。即使在最好的情况下,渲染 JTable 也不是一件容易的任务,通常您只需利用表的内置打印支持,但这并没有考虑到 JScrollPanes rowHeader,足够大的表格可能想要打印到多个页面,这只会变得困惑。

在您的情况下,您必须拆解 JScrollPane 并渲染 rowHeadercolumnHeader 和主 View 你自己。

在“非常”基本的层面上,这将调用计算渲染所有组件所需的总体大小,计算每个组件的偏移位置并绘制它们,就像这样......

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();

我借用了旧示例中的一些代码,并作为示例实现了基本思想。由于我没有您的代码,因此您遇到的任何其他问题都必须自己尝试解决(很难通过 Crystal 球进行调试),但这应该可以帮助您开始

从窗口...

From the frame

到图像...

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();
        }

    }

}

关于java - 转换为 JScrollPane 中 JTable 的图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47037416/

相关文章:

java - 为什么在 Jaxb2Marshaller 中需要检查根元素?

java - 如何将数据库中的表名显示到JTable中?

Java - 单击第二个单元格时如何防止 JTable 中的水平自动滚动?

Java ActionListener 操作未执行

c# - 可以精确表示为 float / double 的整数范围

java - Lucene IndexReader 提交不起作用

java - 返回抽象方法的实例

java - java中需要的BST图形表示

java - center 在 BorderLayout 中不是公共(public)的;无法从包外部访问

Java swing 在调用 repaint() 之前不会显示 g.drawImage()