0

JTable があり、各セルを頻繁に再描画する必要があります。テーブルのセルはグレースケールの画像を示しています。通常、画像は、ペイントされた領域に合わせてペイントするためにスケーリングする必要があります。JComponent のメソッド内に 2 つの実装がありますpaintComponent(Graphics g)

  1. スケーリングされたイメージImage.getScaledInstance()を作成し、Graphics を使用して描画します。
  2. Graphics に「その場で」画像をスケーリングさせます。

最初の方法はより速く動作し、より少ない CPU を必要とします。ただし、画像の色(グレーレベル)が変わります。以下の画像は、この問題を示しています。左が最初の方法 (間違った色)、右が 2 番目の方法 (真の色)。

質問:これが発生する理由と解決方法を教えてください。あるいは、他の解決策があれば大歓迎です。

ここに画像の説明を入力

注: このコード例では、実際に画像をスケーリングしませんが、呼び出すとImage.getScaledInstance()画像の値が変更されます。

コード:

class CellImage extends JComponent {

    final boolean rescale_img;
    final byte value;

    CellImage(boolean flag, byte v) {
        rescale_img = flag;
        value = v;
    }

    @Override
    public void paintComponent(Graphics g) {
        Rectangle r = g.getClipBounds();
        BufferedImage image = new BufferedImage(r.width, r.height, BufferedImage.TYPE_BYTE_GRAY);
        byte[] bytes = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        Arrays.fill(bytes, value);
        if (rescale_img){
            Image scaled = image.getScaledInstance(r.width, r.height, Image.SCALE_REPLICATE);
            g.drawImage(scaled, 0, 0, null);
        } else {
            g.drawImage(image, 0, 0, null);
        }
    }
}

必要に応じて、以下の SSCCE 全体を参照してください。

package book_test_paint;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.util.Arrays;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;

class CellImage extends JComponent {

    final boolean rescale_img;
    final byte value;

    CellImage(boolean flag, byte v) {
        rescale_img = flag;
        value = v;
    }

    @Override
    public void paintComponent(Graphics g) {
        Rectangle r = g.getClipBounds();
        BufferedImage image = new BufferedImage(r.width, r.height, BufferedImage.TYPE_BYTE_GRAY);
        byte[] bytes = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        Arrays.fill(bytes, value);
        if (rescale_img){
            Image scaled = image.getScaledInstance(r.width, r.height, Image.SCALE_REPLICATE);
            g.drawImage(scaled, 0, 0, null);
        } else {
            g.drawImage(image, 0, 0, null);
        }
    }
}

class CellText extends JComponent {

    final String str;

    CellText(String s){
        str = s;
    }

    @Override
    public void paintComponent(Graphics g) {
        Rectangle r = g.getClipBounds();
        g.setColor(Color.BLACK);
        g.fill3DRect(0, 0, r.width, r.height, true);
        g.setColor(Color.WHITE);
        ((Graphics2D) g).drawString(str, 0.1f * r.width, 0.9f * r.height);
    }
}

class MyTableModel extends DefaultTableModel {

    final int nrows = 17;

    @Override
    public int getRowCount() {
        return nrows;
    }

    @Override
    public int getColumnCount() {
        return 3;
    }

    @Override
    public Object getValueAt(int row, int column) {
        Object obj = null;
        // The value below represents the desired 
        // gray scale of the image in range [0, 255]
        int val = (int)Math.min(255, row * 256.0 / (nrows - 1));
        switch (column) {
            case 0:
                obj = new CellImage(true, (byte)val);
                break;
            case 1:
                obj = new CellText("" + val);
                break;
            case 2:
                obj = new CellImage(false, (byte)val);
                break;
        }
        return obj;
    }
}

public class Image_Scaling extends JTable {

    public Image_Scaling(JPanel panel) {
        setModel(new MyTableModel());
        setRowHeight(25);
        getColumnModel().getColumn(0).setPreferredWidth(200);
        getColumnModel().getColumn(1).setPreferredWidth(40);
        getColumnModel().getColumn(2).setPreferredWidth(200);
        JTableHeader header = getTableHeader();
        header.getColumnModel().getColumn(0).setHeaderValue("with getScaledInstance()");
        header.getColumnModel().getColumn(1).setHeaderValue("gray");
        header.getColumnModel().getColumn(2).setHeaderValue("without getScaledInstance()");
        panel.setLayout(new BorderLayout());
        panel.add(header, BorderLayout.NORTH);
        panel.add(this, BorderLayout.CENTER);
    }

    @Override
    public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
        return (Component) dataModel.getValueAt(row, column);
    }

    public static void main(String[] args) {
        JPanel panel = new JPanel(new BorderLayout());
        final Image_Scaling table = new Image_Scaling(panel);

        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(panel, BorderLayout.CENTER);
        frame.pack();

        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                frame.setVisible(true);
            }
        });
    }
}
4

0 に答える 0