繁体   English   中英

JScrollPanel中的Java2D图形效果不佳

[英]Java2D graphics inside JScrollPanel don't come out well

我是荷兰计算机科学系的一名学生,我正在做一项作业,其中我必须绘制几个形状。 为了使这些形状看起来更好,我设置了抗锯齿的渲染提示。 但是现在我的问题是,当我用JScrollPanel滚动到屏幕上未显示形状的位置然后向后滚动时,抗锯齿和透明效果似乎无法正常工作。

在下面链接的图像中,我已滚动到形状的一半,然后向后滚动。

链接到图片

我真的不知道问题出在哪里,所以我在下面的类中提供了完整的代码。

您可以在此处下载完整的eclipse项目文件夹。

我想先谢谢你,

米兰诉迪克

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;

import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")

public class AgendaPanel extends JPanel{
    private final int WIDTH = 24; // width in hours
    private final Color BUTTON_TOP_GRADIENT = new Color(250, 250, 250);
    private final Color BUTTON_BOTTOM_GRADIENT = new Color(210, 210, 210);

    private ArrayList<Line> lines = new ArrayList<Line>();
    private ArrayList<Shape> shadowBoxes = new ArrayList<Shape>();
    private ArrayList<Shape> itemBoxes = new ArrayList<Shape>();
    private ArrayList<Image2D> images = new ArrayList<Image2D>();
    private ArrayList<String2D> names = new ArrayList<String2D>();

    public AgendaPanel(){
        setPreferredSize(new Dimension(WIDTH*100, 300));

        drawGrid();
    }

    public void drawGrid(){
        for(int i=100; i < WIDTH*100; i+=100){
            lines.add(new Line(i,0,i,300,Color.GRAY));
        }

        for(int i=50; i < WIDTH*100; i+=100){
            lines.add(new Line(i,0,i,300, Color.LIGHT_GRAY));
        }

        // change to the amount of podia
        for(int i=75; i < 300; i+=75){
            lines.add(new Line(0, i, WIDTH*100, i, Color.black));
        }

        repaint();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;

        RenderingHints qualityHints = new RenderingHints(
                  RenderingHints.KEY_ANTIALIASING,
                  RenderingHints.VALUE_ANTIALIAS_ON );

        qualityHints.put(
                  RenderingHints.KEY_RENDERING,
                  RenderingHints.VALUE_RENDER_QUALITY );

        g2.setRenderingHints( qualityHints );

        // Add agenda items to the draw queue
        addAgendaItem("logo.png", "Minus Militia", 2, 2, 170);

        //draw time grid
        for(Line line : lines){
            g2.setColor(line.color);
            g2.drawLine(line.x1, line.y1, line.x2, line.y2);
        }

        //Shape roundRect = new RoundRectangle2D.Double(2, 2, 170, 71, 20, 20);

        //Paint all shadow shapes as the first layer over the grid with a transparacy of 30%
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.3f));

        for (Shape shadow : shadowBoxes){
            paintBorderShadow(g2,4,shadow);
        }
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1f));

        //Paint all boxes as second layer over the shadows
        g2.setStroke(new BasicStroke());
        g2.setPaint(new GradientPaint(  new Point(0, 0),
                BUTTON_TOP_GRADIENT,
                new Point(0, 71),
                BUTTON_BOTTOM_GRADIENT));

        for (Shape box : itemBoxes){
            g2.fill(box);
        }

        // Paint as third layer all the images over the boxes
        for (Image2D image : images){
            g2.drawImage(image.getImage() , image.getX(), image.getY(), null);
        }

        g2.setColor(Color.black);

        //Paint all names as fourth and last layer
        for (String2D name : names){
            g2.drawString(name.getText(), name.getX(), name.getY());
        }

    }

    private void addAgendaItem(String imageFile,String name, int x, int y, int length){

        shadowBoxes.add(new RoundRectangle2D.Double(x+3, y+3, length-3, 68, 20, 20));
        itemBoxes.add(new RoundRectangle2D.Double(x, y, length, 71, 20, 20));

        BufferedImage in = null;

        try {
            in = ImageIO.read(new File("logo.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        images.add(new Image2D(x+8, y+8 ,drawPicture(scaleImage(in, 55, 55,Color.black),20)));

        names.add(new String2D(x+73,y+38, name));

    }

    private BufferedImage drawPicture(BufferedImage image, int cornerRadius){
            int w = image.getWidth();
            int h = image.getHeight();
            BufferedImage output = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

            Graphics2D g2 = output.createGraphics();

            g2.setComposite(AlphaComposite.Src);
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.setColor(Color.WHITE);
            g2.fill(new RoundRectangle2D.Float(0, 0, w, h, cornerRadius, cornerRadius));

            g2.setComposite(AlphaComposite.SrcAtop);
            g2.drawImage(image, 0, 0, null);

            g2.dispose();

            return output;
    }

    public BufferedImage scaleImage(BufferedImage img, int width, int height, Color background) {
        int imgWidth = img.getWidth();
        int imgHeight = img.getHeight();

        if (imgWidth*height < imgHeight*width) {
            width = imgWidth*height/imgHeight;
        } else {
            height = imgHeight*width/imgWidth;
        }
        BufferedImage output = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g = output.createGraphics();
        try {
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                    RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            g.setBackground(background);
            g.clearRect(0, 0, width, height);
            g.drawImage(img, 0, 0, width, height, null);
        } finally {
            g.dispose();
        }
        return output;
    }

    private void paintBorderShadow(Graphics2D g2, int shadowWidth, Shape shape) {

        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
        int sw = shadowWidth*2;
        for (int i=sw; i >= 2; i-=2) {
            float pct = (float)(sw - i) / (sw - 1);
            g2.setColor(getMixedColor(Color.DARK_GRAY, pct,
                                      Color.DARK_GRAY, 1.0f-pct));
            g2.setStroke(new BasicStroke(i));
            g2.draw(shape);
        }
    }

    private static Color getMixedColor(Color c1, float pct1, Color c2, float pct2) {
        float[] clr1 = c1.getComponents(null);
        float[] clr2 = c2.getComponents(null);
        for (int i = 0; i < clr1.length; i++) {
            clr1[i] = (clr1[i] * pct1) + (clr2[i] * pct2);
        }
        return new Color(clr1[0], clr1[1], clr1[2], clr1[3]);
    }

}

Image2D,String2D和Line类:

public class String2D {
    private int x = 0;
    private int y = 0;
    private String text = "";

    public String2D(int x, int y, String text){
        this.x = x;
        this.y = y;
        this.text = text;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

import java.awt.image.BufferedImage;


public class Image2D {
    private int x = 0;
    private int y = 0;
    private BufferedImage image = null;

    public Image2D(int x, int y, BufferedImage image){
        this.x = x;
        this.y = y;
        this.image = image;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public BufferedImage getImage() {
        return image;
    }

    public void setImage(BufferedImage image) {
        this.image = image;
    }
}
import java.awt.*;

public class Line{
    public int x1;
    public int x2;
    public int y1;
    public int y2;
    public Color color;

    public Line(int x1, int y1, int x2, int y2, Color color){
        this.x1 = x1;
        this.x2 = x2;
        this.y1 = y1;
        this.y2 = y2;
        this.color = color;
    }
}

经过个人的尤里卡片刻之后,我发现了我的问题所在。 我正在调整大小,并在每次重画时给圆角图像,这使g2对象以某种方式禁用了我的渲染提示。 我已将此代码放入构造函数中,现在一切都运行顺利。

下面的代码就是问题所在:

    private BufferedImage drawPicture(BufferedImage image, int cornerRadius){
    int w = image.getWidth();
    int h = image.getHeight();
    BufferedImage output = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

    Graphics2D g2 = output.createGraphics();

    g2.setComposite(AlphaComposite.Src);
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(Color.WHITE);
    g2.fill(new RoundRectangle2D.Float(0, 0, w, h, cornerRadius, cornerRadius));

    g2.setComposite(AlphaComposite.SrcAtop);
    g2.drawImage(image, 0, 0, null);

    g2.dispose();

    return output;
    }

    public BufferedImage scaleImage(BufferedImage img, int width, int height, Color background) {
int imgWidth = img.getWidth();
int imgHeight = img.getHeight();

if (imgWidth*height < imgHeight*width) {
    width = imgWidth*height/imgHeight;
} else {
    height = imgHeight*width/imgWidth;
}
BufferedImage output = new BufferedImage(width, height,
        BufferedImage.TYPE_INT_RGB);
Graphics2D g = output.createGraphics();
try {
    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
            RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g.setBackground(background);
    g.clearRect(0, 0, width, height);
    g.drawImage(img, 0, 0, width, height, null);
} finally {
    g.dispose();
}
return output;
}

我在paintcomponent例程中调用了此方法:

addAgendaItem("logo.png", "Minus Militia", 2, 2, 170);

这是哪种方法:

private void addAgendaItem(String imageFile,String name, int x, int y, int length){
shadowBoxes.add(new RoundRectangle2D.Double(x+3, y+3, length-3, 68, 20, 20));
itemBoxes.add(new RoundRectangle2D.Double(x, y, length, 71, 20, 20));

BufferedImage in = null;

try {
    in = ImageIO.read(new File("logo.png"));
} catch (IOException e) {
    e.printStackTrace();
}

images.add(new Image2D(x+8, y+8 ,drawPicture(scaleImage(in, 55, 55,Color.black),20)));

names.add(new String2D(x+73,y+38, name));

}

这就调用了上述两种方法(每次重绘),这导致了我的性能和绘图问题。

这是一种方法,有时可能会提高CPU效率(以及消耗更多的内存),但是,这可以解决此问题。

存在此问题的原因是,您正在更改作为“ paintComponent”方法的参数提供的Graphics对象的状态。 这是一个常见错误,会导致各种奇怪的图形错误。

您不应该更改对象状态的原因是,因为该对象是由其父组件传递到您的组件的,而父组件是从其父组件获取的,依此类推。 链中的每个组件(一直到拥有的窗口)都使用相同的Graphics对象来绘制自身。 相同的Graphics对象也将自动传递给组件的任何子代。 这是Swing工作原理的基础(关于将Swing与AWT甚至SWT进行比较的讨论是完全不同的主题)。

相反,您应该做的就是保留状态。 这可以通过以下两种方式之一来完成:

  1. 在方法返回之前(即方法中的最后几行代码),将更改后的所有内容恢复为原来的方式(在您的情况下,呈现提示等)。 如果您仅对Graphics对象的状态进行了一些更改,那么这是一个好方法。
  2. 在方法的开头使用“创建”方法创建Graphics对象的副本,而不是使用原始对象来绘制对象,然后在其结尾使用“ dispose”方法将其删除。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM