现在的位置: 首页 > 综合 > 正文

Graphics的使用及五颜六色满天星的实现

2018年01月30日 ⁄ 综合 ⁄ 共 7816字 ⁄ 字号 评论关闭

上图实现的是每半秒钟出现一个任意边形的随机颜色渲染的星星。或许这一点意义都没有,纯粹是我闲着蛋疼。实现一个任意多半行即简单又复杂:

 private static Shape getStar(double x, double y,  
        double innerRadius, double outerRadius,int pointsCount) {  
    GeneralPath path = new GeneralPath();  
    double outerAngleIncrement = 2 * Math.PI / pointsCount;  
    double outerAngle = 0.0;  
    double innerAngle = outerAngleIncrement / 2.0;  
    x += outerRadius;  
    y += outerRadius;  
    float x1 = (float) (Math.cos(outerAngle) * outerRadius + x);  
    float y1 = (float) (Math.sin(outerAngle) * outerRadius + y);  
    float x2 = (float) (Math.cos(innerAngle) * innerRadius + x);  
    float y2 = (float) (Math.sin(innerAngle) * innerRadius + y);  
    path.moveTo(x1, y1);  
    path.lineTo(x2, y2);  
    outerAngle += outerAngleIncrement;  
    innerAngle += outerAngleIncrement;  
    for (int i = 1; i < pointsCount; i++) {  
        x1 = (float) (Math.cos(outerAngle) * outerRadius + x);  
        y1 = (float) (Math.sin(outerAngle) * outerRadius + y);  
        path.lineTo(x1, y1);  
        x2 = (float) (Math.cos(innerAngle) * innerRadius + x);  
        y2 = (float) (Math.sin(innerAngle) * innerRadius + y);  
        path.lineTo(x2, y2);  
        outerAngle += outerAngleIncrement;  
        innerAngle += outerAngleIncrement;  
    }  
    path.closePath();  
    return path;  
}  

 

    用getStar(...)获得的只是一个Shape,没有颜色,没有形象,只是数学意义上的经过一定算法得到的多边形。如何把这个多边形显示出来并渲染成五颜六色呢,这就要了解了解Graphics了。

     一:Graphics

     Graphics可以说是Swing的灵魂。哦,这里说的Graphics是指Graphics和Graphics2D的统称。Graphics和Swing有关系吗,我用了那么多组件怎么没见过?那只说明你对Swing的了解只停留在表面,或者说现有的组件已满足了你的要求。但你翻遍Swing的所有组件找不到合适的时候怎么办呢,自己动手,丰衣足食。这时Graphics就派上用场了。你不防进各个组件的源码看看,到处都是Graphics的身影。看看源代码,你会发现,几乎所有的Swing组件都是通过Graphics绘制出来的。当然要做出美观绚丽的界面少不了各种各样的渲染。

 

     组件的渲染很简单:

  1. 获得一个Graphics(或Graphics2D)对象。
  2. 设置这个Graphics对象的属性。
  3. 用这个Graphics对象绘制图形基本元素。

     组件的千差万别也在于:

  1. 如果获取Graphics对象:是通过图像还是组件,或者给定一个。
  2. 在这个Graphics对象上设置哪些属性。
  3. 用这个Graphics对象执行什么制图操作。

     拥有点、面、线,就能把整个世界描绘出来。这个Graphics都有,再加上图形学中各种数学知识。还有什么做不出来呢。本例子用到的主要方法有:

  1. setPaint (Paint  paint):
    Graphics2D 上下文设置 Paint 属性。
  2. fillRect (int x, int y, int width, int height): 填充指定的矩形。
  3. setRenderingHint (RenderingHints.Key  hintKey,
    Object  hintValue):
    为呈现算法设置单个首选项的值。
  4. fill (Shape  s): 使用
    Graphics2D 上下文的设置,填充 Shape 的内部区域。
  5. drawString (String  str, int x, int y): 使用
    Graphics2D 上下文中的当前文本属性状态呈现指定的 String 的文本。

    有了这些方法,把Shape画到面板上就轻而易举了:

@Override  
protected void paintComponent(Graphics g) {  
    Graphics2D g2d = (Graphics2D)g;  
    //天空背景   
    GradientPaint background = new GradientPaint(0f, 0f, Color.GRAY.darker(),  
            0f, (float)getHeight(), Color.GRAY.brighter());  
    g2d.setPaint(background);  
    g2d.fillRect(0, 0, getWidth(), 4*getHeight()/5);  
    //地面背景   
    background = new GradientPaint(0f, (float)4*getHeight()/5,  
            Color.BLACK,  
            0f, (float)getHeight(), Color.GRAY.darker());  
    g2d.setPaint(background);  
    g2d.fillRect(0, 4*getHeight()/5, getWidth(), getHeight()/5);  
    //开启抗锯齿   
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,  
            RenderingHints.VALUE_ANTIALIAS_ON);  
    //画所有的星星   
    for (Shape star : stars) {  
        Rectangle rect = star.getBounds();  
        Point2D center = new Point2D.Float(  
                rect.x + (float)rect.width / 2.0f,  
                rect.y + (float)rect.height / 2.0f);  
        float radius = (float)rect.width / 2.0f;  
        float[] dist = {0.1f, 0.9f};  
        //圆形辐射颜色渐变模式   
        RadialGradientPaint paint = new RadialGradientPaint(center, radius,  
                dist, colors[random.nextInt(colors.length)]);  
        g2d.setPaint(paint);  
        g2d.fill(star);  
    }  
    g2d.drawString(menInfo,10, 10);  
}  

要充分看懂以上代码,下面这些介绍可能有点用;只是简单介绍,详细用法请查看javadoc:

     二:GeneralPath

     GeneralPath类表示根据直线、二次曲线和三次曲线构造的几何图形,其中可以指定一些规则。它是Shape接口的一个实现类。父类是Path2D,也是表示任意几何形状路径的简单而又灵活的形状。我们的多边形星星就是采用默认的非零旋绕规则生成的。用到的方法有:

  1. moveTo (float x, float y): 通过移动到指定的坐标(以 float 精度指定),将一个点添加到路径中。
  2. lineTo (float x, float y): 通过绘制一条从当前坐标到指定新坐标(以 float 精度指定)的直线,将一个点添加到路径中。
  3. closePath (): 通过绘制一条向后延伸到最后一个 moveTo 的坐标的直线,封闭当前子路径。

     三:GradientPaint

     GradientPaint类提供了使用线性颜色渐变模式填充 Shape
的方法,分周期渐变和非周期渐变两种。我们定义的天空是从上到下由深灰到浅灰渐变,地面是从距底部五分一处到底部由黑到深灰渐变。它的构造方法:

    GradientPaint (float x1, float y1,
Color
 color1, float x2, float y2, Color  color2)

    GradientPaint (float x1, float y1,
Color
 color1, float x2, float y2, Color  color2, boolean cyclic)

    
 四:RadialGradientPaint

     RadialGradientPaint 类提供使用圆形辐射颜色渐变模式填充某一形状的方式。用户可以指定两种或多种渐变颜色,此绘制将在颜色与颜色之间提供一个插值。星星就是采用这种渐变方式进行渲染的。这是一种非常有趣的渐变方式,通过不同的参数,可以实现绚丽多彩的图形。详情请看javadoc。

 

     好了,暂时就到这吧,附上全部代码:

 

package com.monitor1394.star;  
import java.awt.Color;  
import java.awt.GradientPaint;  
import java.awt.Graphics;  
import java.awt.Graphics2D;  
import java.awt.RadialGradientPaint;  
import java.awt.Rectangle;  
import java.awt.RenderingHints;  
import java.awt.Shape;  
import java.awt.event.ActionEvent;  
import java.awt.event.ActionListener;  
import java.awt.geom.GeneralPath;  
import java.awt.geom.Point2D;  
import java.util.LinkedList;  
import java.util.List;  
import java.util.Random;  
import javax.swing.JComponent;  
import javax.swing.JFrame;  
import javax.swing.SwingUtilities;  
import javax.swing.Timer;  
import javax.swing.UIManager;  
/** 
 * 五颜六色满天星的实现 
 * 
 * @author  
 * Created on  
 */  
public class StarShine extends JComponent{  
    private List<Shape> stars=new LinkedList<Shape>();  
    private static Random random=new Random();  
    private static Color[][] colors={  
        {Color.WHITE, Color.BLACK},  
        {Color.WHITE, Color.BLUE},  
        {Color.ORANGE, Color.PINK},  
        {Color.ORANGE, Color.green}  
    };  
    private String menInfo="";  
    public StarShine(){  
        setBackground(Color.WHITE);  
        //每秒输出内存信息   
        new Timer(500, new ActionListener() {  
            public void actionPerformed(ActionEvent evt) {  
                //随机多边形   
                int centerX =random.nextInt(getWidth());  
                int centerY =random.nextInt(getHeight());  
                double innerSize = 1 + (25 * Math.random());  
                double outerSize = innerSize + 10 + (15 * Math.random());  
                int numPoints = (int)(8 * Math.random() + 5);  
               stars.add(getStar(centerX,centerY,innerSize,outerSize,numPoints));  
                //内存信息   
                long tm=Runtime.getRuntime().totalMemory();  
                long mm=Runtime.getRuntime().maxMemory();  
               long fm=Runtime.getRuntime().freeMemory();  
                long um=tm-fm;  
                menInfo=String.format("%d / %d MB  %d", um/(1024*1024),mm/(1024*1024),stars.size());  
                repaint();  
            }  
        }).start();  
    }  
    @Override  
    protected void paintComponent(Graphics g) {  
        Graphics2D g2d = (Graphics2D)g;  
        //天空背景   
        GradientPaint background = new GradientPaint(0f, 0f, Color.GRAY.darker(),  
                0f, (float)getHeight(), Color.GRAY.brighter());  
        g2d.setPaint(background);  
        g2d.fillRect(0, 0, getWidth(), 4*getHeight()/5);  
        //地面背景   
        background = new GradientPaint(0f, (float)4*getHeight()/5,  
                Color.BLACK,  
                0f, (float)getHeight(), Color.GRAY.darker());  
        g2d.setPaint(background);  
        g2d.fillRect(0, 4*getHeight()/5, getWidth(), getHeight()/5);  
        //开启抗锯齿   
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,  
                RenderingHints.VALUE_ANTIALIAS_ON);  
        //画所有的星星   
        for (Shape star : stars) {  
            Rectangle rect = star.getBounds();  
            Point2D center = new Point2D.Float(  
                    rect.x + (float)rect.width / 2.0f,  
                    rect.y + (float)rect.height / 2.0f);  
            float radius = (float)rect.width / 2.0f;  
            float[] dist = {0.1f, 0.9f};  
            //圆形辐射颜色渐变模式   
            RadialGradientPaint paint = new RadialGradientPaint(center, radius,  
                    dist, colors[random.nextInt(colors.length)]);  
            g2d.setPaint(paint);  
            g2d.fill(star);  
        }  
        g2d.drawString(menInfo,10, 10);  
    }  
    /** 
     * 获得一个随机边的多边形 
     * @param x 中心点X 
     * @param y 中心点Y 
     * @param innerRadius 内圆半径 
     * @param outerRadius 外圆半径 
     * @param pointsCount 角数 
     * @return 一个多边形 
     */  
    private static Shape getStar(double x, double y,  
            double innerRadius, double outerRadius,int pointsCount) {  
        GeneralPath path = new GeneralPath();  
        double outerAngleIncrement = 2 * Math.PI / pointsCount;  
        double outerAngle = 0.0;  
        double innerAngle = outerAngleIncrement / 2.0;  
        x += outerRadius;  
        y += outerRadius;  
        float x1 = (float) (Math.cos(outerAngle) * outerRadius + x);  
        float y1 = (float) (Math.sin(outerAngle) * outerRadius + y);  
        float x2 = (float) (Math.cos(innerAngle) * innerRadius + x);  
        float y2 = (float) (Math.sin(innerAngle) * innerRadius + y);  
        path.moveTo(x1, y1);  
        path.lineTo(x2, y2);  
        outerAngle += outerAngleIncrement;  
        innerAngle += outerAngleIncrement;  
        for (int i = 1; i < pointsCount; i++) {  
            x1 = (float) (Math.cos(outerAngle) * outerRadius + x);  
            y1 = (float) (Math.sin(outerAngle) * outerRadius + y);  
            path.lineTo(x1, y1);  
            x2 = (float) (Math.cos(innerAngle) * innerRadius + x);  
            y2 = (float) (Math.sin(innerAngle) * innerRadius + y);  
            path.lineTo(x2, y2);  
            outerAngle += outerAngleIncrement;  
            innerAngle += outerAngleIncrement;  
        }  
        path.closePath();  
        return path;  
    }  
    /** 创建界面 */  
    private static void createAndShowGUI() {  
        final JFrame f = new JFrame("Star Shine");  
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
        f.setSize(800, 500);  
        f.add(new StarShine());  
        f.setVisible(true);  
        f.setLocationRelativeTo(f.getOwner());  
    }  
    public static void main(String args[]) {  
        SwingUtilities.invokeLater(new Runnable() {  
            public void run() {  
                try {  
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());  
                } catch (Exception ex) {  
                }  
                createAndShowGUI();  
            }  
        });  
    }  
} 

    后注:星星的生成算法是参考《Filthy Rich Clients》一书中的DrawShape例子,这里只不过是一个读书笔记罢了。

抱歉!评论已关闭.