0

我有一个 JTable,需要非常频繁地重新绘制每个单元格,其中表格的单元格说明了灰度图像。通常图像需要缩放以适合绘制区域。我在 JComponent 的方法中有两个实现paintComponent(Graphics g)

  1. 创建缩放图像Image.getScaledInstance(),然后使用 Graphics 绘制它。
  2. 让 Graphics “即时”缩放图像;

第一种方法运行速度更快,并且需要更少的 CPU。但它会改变图像的颜色(灰度)。下图说明了这个问题。第一种方法(错误颜色)在左边,第二种方法(真颜色)在右边。

问题:为什么会发生这种情况以及如何解决?或者,任何其他解决方案将不胜感激。

在此处输入图像描述

注意:在此代码示例中,我实际上并未缩放图像,但调用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