Подтвердить что ты не робот

Почему заголовок JTable не отображается на изображении?

Я предлагал совет по захвату изображения табличных данных в Java API или инструменте для преобразования табличных данных в файл изображения PNG - когда OP запросил образец кода. Оказывается, это сложнее, чем я думал! Заголовок JTable исчезает из PNG, который записывает код.

PNG

PNG

Снимок экрана

enter image description here

import javax.swing.*;
import java.awt.Graphics;
import java.awt.BorderLayout;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import java.io.File;

class TableImage {

    public static void main(String[] args) throws Exception {
        Object[][] data = {
            {"Hari", new Integer(23), new Double(78.23), new Boolean(true)},
            {"James", new Integer(23), new Double(47.64), new Boolean(false)},
            {"Sally", new Integer(22), new Double(84.81), new Boolean(true)}
        };

        String[] columns = {"Name", "Age", "GPA", "Pass"};

        JTable table = new JTable(data, columns);
        JScrollPane scroll = new JScrollPane(table);
        JPanel p = new JPanel(new BorderLayout());
        p.add(scroll,BorderLayout.CENTER);

        JOptionPane.showMessageDialog(null, p);

        BufferedImage bi = new BufferedImage(
            (int)p.getSize().getWidth(),
            (int)p.getSize().getHeight(),
            BufferedImage.TYPE_INT_RGB
            );

        Graphics g = bi.createGraphics();
        p.paint(g);

        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
        ImageIO.write(bi,"png",new File("table.png"));
    }
}

Примечание. Я проверил класс camicar Screen Image и включил вызов метода doLayout(Component). Метод полезен, если Component никогда не реализовывался на экране, но не влияет на этот код (который всплывает панель, содержащая таблицу в панели параметров, прежде чем пытаться ее отобразить).

Что необходимо для получения заголовка таблицы?

Обновление 1

Изменение строки.

        p.paint(g);

.. to (с соответствующим импортом)..

        p.paint(g);
        JTableHeader h = table.getTableHeader();
        h.paint(g);

.. производит..

2nd try

Я буду настраивать его.

Обновление 2

kleopatra (стратегия 1) и camickr (стратегия 2) предоставили каждому ответ, оба из которых работают, и ни одно из них не требует добавления JTable к фиктивной компоненте (что является огромным взломом IMO).

В то время как стратегия 2 будет обрезать (или развернуть) до "только таблицы", первая стратегия захватит панель, содержащую таблицу. Это становится проблематичным, если таблица содержит много записей, отображающих изображение усеченной таблицы со строкой прокрутки.

В то время как стратегия 1 может быть дополнительно изменена, чтобы обойти это, мне действительно нравится аккуратная простота стратегии 2, поэтому она получает тик.

Как указывал Клеопатра, не было необходимости в настройке. Поэтому я попробую еще раз.

Обновление 3

Это изображение, созданное методами, предложенными как camickr, так и kleopatra. Я бы поставил его дважды, но, на мой взгляд, они идентичны (хотя я не сделал сравнения по пикселям за пикселями).

JTable in Nimbus PLAF

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import java.io.File;

class TableImage {

    String[] columns = {"Name", "Age", "GPA", "Pass"};
    /** Any resemblance to persons living or dead is purely incidental. */
    Object[][] data = {
        {"André", new Integer(23), new Double(47.64), new Boolean(false)},
        {"Jeanie", new Integer(23), new Double(84.81), new Boolean(true)},
        {"Roberto", new Integer(22), new Double(78.23), new Boolean(true)}
    };

    TableImage() {
    }

    public JTable getTable() {
        JTable table = new JTable(data, columns);
        table.setGridColor(new Color(115,52,158));
        table.setRowMargin(5);
        table.setShowGrid(true);

        return table;
    }

    /** Method courtesy of camickr.
    https://stackoverflow.com/info/7369814/why-does-the-jtable-header-not-appear-in-the-image/7375655#7375655
    Requires ScreenImage class available from..
    http://tips4java.wordpress.com/2008/10/13/screen-image/ */
    public BufferedImage getImage1(JTable table) {
        JScrollPane scroll = new JScrollPane(table);

        scroll.setColumnHeaderView(table.getTableHeader());
        table.setPreferredScrollableViewportSize(table.getPreferredSize());

        JPanel p = new JPanel(new BorderLayout());
        p.add(scroll, BorderLayout.CENTER);

        BufferedImage bi = ScreenImage.createImage(p);
        return bi;
    }

    /** Method courtesy of kleopatra.
    https://stackoverflow.com/info/7369814/why-does-the-jtable-header-not-appear-in-the-image/7372045#7372045 */
    public BufferedImage getImage2(JTable table) {
        JScrollPane scroll = new JScrollPane(table);

        table.setPreferredScrollableViewportSize(table.getPreferredSize());

        JPanel p = new JPanel(new BorderLayout());
        p.add(scroll, BorderLayout.CENTER);

        // without having been shown, fake a all-ready
        p.addNotify();

        // manually size to pref
        p.setSize(p.getPreferredSize());

        // validate to force recursive doLayout of children
        p.validate();

        BufferedImage bi = new BufferedImage(p.getWidth(), p.getHeight(), BufferedImage.TYPE_INT_RGB);

        Graphics g = bi.createGraphics();
        p.paint(g);
        g.dispose();

        return bi;
    }

    public void writeImage(BufferedImage image, String name) throws Exception {
        ImageIO.write(image,"png",new File(name + ".png"));
    }

    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        TableImage ti = new TableImage();
        JTable table;
        BufferedImage bi;

        table = ti.getTable();
        bi = ti.getImage1(table);
        ti.writeImage(bi, "1");
        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));

        table = ti.getTable();
        bi = ti.getImage2(table);
        ti.writeImage(bi, "2");
        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
    }
}

Оба достигают цели. Используя метод camickr, вы используете дополнительную силу API ScreenImage. Использование метода kleopatra - около дюжины строк (меньше комментариев и пробелов) чистого J2SE.

В то время как ScreenImage - это класс, который я буду использовать и рекомендовать в будущем, другой подход с использованием ядра J2SE - это то, что я, вероятно, использовал бы для этого точного обстоятельства.

Итак, пока "тик" останется с камикром, щедрость будет клеопатра.

4b9b3361

Ответ 1

Требование этого потока не требовало визуализации таблицы без предварительного ее отображения, но это была конечная цель

ScreenImage обрабатывает это.

Вы должны вручную добавить заголовок в scrollpane.

import javax.swing.*;
import java.awt.Graphics;
import java.awt.BorderLayout;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import java.io.File;

class TableImage {

    public static void main(String[] args) throws Exception {
        Object[][] data = {
            {"Hari", new Integer(23), new Double(78.23), new Boolean(true)},
            {"James", new Integer(23), new Double(47.64), new Boolean(false)},
            {"Sally", new Integer(22), new Double(84.81), new Boolean(true)}
        };

        String[] columns = {"Name", "Age", "GPA", "Pass"};

        JTable table = new JTable(data, columns);
        JScrollPane scroll = new JScrollPane(table);

        scroll.setColumnHeaderView(table.getTableHeader());
        table.setPreferredScrollableViewportSize(table.getPreferredSize());

        JPanel p = new JPanel(new BorderLayout());
        p.add(scroll, BorderLayout.CENTER);

        BufferedImage bi = ScreenImage.createImage(p);

        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
        ImageIO.write(bi,"png",new File("table.png"));
    }
}

Примечание: Kleopatra советует использовать addNotify() на панели не будет работать с ScreenImage. Метод addNotify() делает компонент displayable, а в коде ScreenImage будут отображаться только компоненты для не отображаемых компонентов. Я мог бы задуматься над тем, чтобы сделать это более общим.

Ответ 2

который был жестким

Было озадачено, что этот заголовок вообще не появился на изображении: он не был обрезан или что-то еще, он вообще не был нарисован. Причиной этого является то, что во время рисования панели до изображения заголовок больше не является частью иерархии. При закрытии optionPane, table.removeNotify удаляет заголовок. Чтобы добавить его снова, вызовите addNotify, как в этом фрагменте:

    JScrollPane scroll = new JScrollPane(table);
    JPanel p = new JPanel(new BorderLayout());
    p.add(scroll, BorderLayout.CENTER);
    JOptionPane.showMessageDialog(null, p);
    table.addNotify();
    p.doLayout();
    BufferedImage bi = new BufferedImage(p.getWidth() + 100,
            p.getHeight() + 100, BufferedImage.TYPE_INT_RGB);

    Graphics g = bi.createGraphics();
    p.paint(g);
    g.dispose();

[разрешено в правлении] Что я до сих пор не понимаю, почему панель отображается пустым, но не была показана на панели параметров - обычно некоторая комбинация..

   p.doLayout();
   p.setSize(p.getPreferredSize()) 

... будет делать

Изменить

последняя путаница решена: для принудительной рекурсивной перекомпоновки панели все контейнеры вдоль строки должны быть введены в действие, полагая, что они имеют равноправную проверку, оптимизированы, чтобы ничего не делать, если нет. Выполнение addNotify на панели (а не на столе) плюс проверка достоверности делает трюк

    //        JOptionPane.showMessageDialog(null, p);
    // without having been shown, fake a all-ready
    p.addNotify();
    // manually size to pref
    p.setSize(p.getPreferredSize());
    // validate to force recursive doLayout of children
    p.validate();
    BufferedImage bi = new BufferedImage(p.getWidth() + 100,
            p.getHeight() + 100, BufferedImage.TYPE_INT_RGB);

    Graphics g = bi.createGraphics();
    p.paint(g);
    g.dispose();

    JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));

Не тестируется на побочные эффекты.

Изменить 2

Просто ворча немного о..

стратегия 1 может быть дополнительно изменена, чтобы обойти этот столбец [усеченный столбец]

На самом деле нет необходимости в настройке (или той же настройки, что и для ScreenImage, зависит от того, что вы считаете настройкой:) - оба требуют, чтобы JScrollPane не выполнял свою работу, установив таблицу prefViewportSize, точно такую ​​же строку в обоих:

    // strategy 1
    table.setPreferredScrollableViewportSize(table.getPreferredSize());
    p.addNotify();

    // strategy 2
    scroll.setColumnHeaderView(table.getTableHeader());
    table.setPreferredScrollableViewportSize(table.getPreferredSize());

Ответ 3

Вручную добавив ваш JPanel к JFrame вашего собственного создания, а не только тот, который использует JOptionPane, похоже, разрешает это.

Представляя JFrame, вы можете пропустить начальный диалог, если хотите.

// ...snip 

JOptionPane.showMessageDialog(null, p);

JFrame frame = new JFrame();
frame.setContentPane(p);
frame.pack();

BufferedImage bi = new BufferedImage(
    (int)p.getSize().getWidth(),
    (int)p.getSize().getHeight(),
    BufferedImage.TYPE_INT_RGB
);

Graphics g = bi.createGraphics();
p.paint(g);
g.dispose();
frame.dispose();

JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
ImageIO.write(bi,"png",new File("table.png"));

Ответ 4

Table image

import javax.swing.*;
import javax.swing.table.JTableHeader;
import java.awt.Graphics;
import java.awt.BorderLayout;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import java.io.File;

class TableImage {

    public static void main(String[] args) throws Exception {
        Object[][] data = {
            {"Hari", new Integer(23), new Double(78.23), new Boolean(true)},
            {"James", new Integer(23), new Double(47.64), new Boolean(false)},
            {"Sally", new Integer(22), new Double(84.81), new Boolean(true)}
        };

        String[] columns = {"Name", "Age", "GPA", "Pass"};

        JTable table = new JTable(data, columns);
        JScrollPane scroll = new JScrollPane(table);
        JPanel p = new JPanel(new BorderLayout());
        p.add(scroll,BorderLayout.CENTER);

        JOptionPane.showMessageDialog(null, p);

        JTableHeader h = table.getTableHeader();
        int x = h.getWidth();
        int y = h.getHeight() + table.getHeight();

        BufferedImage bi = new BufferedImage(
            (int)x,
            (int)y,
            BufferedImage.TYPE_INT_RGB
            );

        Graphics g = bi.createGraphics();
        h.paint(g);
        g.translate(0,h.getHeight());
        table.paint(g);

        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
        ImageIO.write(bi,"png",new File("table.png"));
    }
}

Ответ 5

Пожалуйста, это не ответ, просто комментарий и немного....: -)

@Andrew Thompson, если я правильно понял для пример, просто ссылка на J/Components находится внутри/мимо Graphics2D g2 = (Graphics2D) g;, а не допустимый ссылочный/производный TableHeader ...., вероятно (я ленив, чтобы проверить это) что-то в API

code snipped показывает: -)

g2.scale(scale,scale);
tableView.paint(g2);
g2.scale(1/scale,1/scale);
g2.translate(0f,pageIndex*pageHeightForTable);
g2.translate(0f, -headerHeightOnPage);
g2.setClip(0, 0,
   (int) Math.ceil(tableWidthOnPage), 
   (int)Math.ceil(headerHeightOnPage));
g2.scale(scale,scale);
tableView.getTableHeader().paint(g2);
//paint header at top

enter image description here

import javax.swing.*;
import javax.swing.table.JTableHeader;
import java.awt.Graphics;
import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;

class TableImage {

    public static void main(String[] args) throws Exception {
        Object[][] data = {
            {"Hari", new Integer(23), new Double(78.23), (true)},
            {"James", new Integer(23), new Double(47.64), (false)},
            {"Sally", new Integer(22), new Double(84.81), (true)}
        };
        String[] columns = {"Name", "Age", "GPA", "Pass"};
        JTable table = new JTable(data, columns);
        JScrollPane scroll = new JScrollPane(table);
        JPanel p = new JPanel(new BorderLayout());
        p.add(scroll, BorderLayout.CENTER);
        JOptionPane.showMessageDialog(null, p);
        JTableHeader h = table.getTableHeader();
        int x = h.getWidth();
        int y = h.getHeight() + table.getHeight();
        BufferedImage bi = new BufferedImage(
                x, y, BufferedImage.TYPE_INT_RGB);
        Graphics g = bi.createGraphics();
        //g.translate(0, table.getTableHeader().getHeight());
        Graphics2D g2 = (Graphics2D) g;
        table.paint(g2);
        //table.paint(g);
        table.getTableHeader().paint(g2);
        //h.paint(g);
        JOptionPane.showMessageDialog(null, new JLabel(new ImageIcon(bi)));
        ImageIO.write(bi, "png", new File("ctable.png"));
    }

    private TableImage() {
    }
}