【Swing入门教程】Graphics的使用及五颜六色满天星的实现
2011-03-04 01:00
435 查看
这几天,头一阵一阵地剧痛,但愿那是我睡得太晚或是工作太累的缘故,而不是因为我太想你。如果”我再次说我喜欢你“是if语句的条件,很想知道接下来会发生什么。然而,人生就是个没有goto的无限循环,或许我们每天在做重复的事,却无法返回原点。人生理应奋斗不止,却不能太乏味,让这天空飘起五颜六色的多种多样的星星吧。
又忙又累,那就来点轻松简单的把,上图实现的是每半秒钟出现一个任意边形的随机颜色渲染的星星。或许这一点意义都没有,纯粹是我闲着蛋疼。实现一个任意多半行即简单又复杂:
用getStar(...)获得的只是一个Shape,没有颜色,没有形象,只是数学意义上的经过一定算法得到的多边形。如何把这个多边形显示出来并渲染成五颜六色呢,这就要了解了解Graphics了。
组件的渲染很简单:
获得一个Graphics(或Graphics2D)对象。
设置这个Graphics对象的属性。
用这个Graphics对象绘制图形基本元素。
组件的千差万别也在于:
如果获取Graphics对象:是通过图像还是组件,或者给定一个。
在这个Graphics对象上设置哪些属性。
用这个Graphics对象执行什么制图操作。
拥有点、面、线,就能把整个世界描绘出来。这个Graphics都有,再加上图形学中各种数学知识。还有什么做不出来呢。本例子用到的主要方法有:
为
上下文设置
属性。
填充指定的矩形。
为呈现算法设置单个首选项的值。
使用
上下文的设置,填充
的内部区域。
使用
上下文中的当前文本属性状态呈现指定的
的文本。
有了这些方法,把Shape画到面板上就轻而易举了:
要充分看懂以上代码,下面这些介绍可能有点用;只是简单介绍,详细用法请查看javadoc:
通过移动到指定的坐标(以 float 精度指定),将一个点添加到路径中。
通过绘制一条从当前坐标到指定新坐标(以 float 精度指定)的直线,将一个点添加到路径中。
通过绘制一条向后延伸到最后一个
的坐标的直线,封闭当前子路径。
的方法,分周期渐变和非周期渐变两种。我们定义的天空是从上到下由深灰到浅灰渐变,地面是从距底部五分一处到底部由黑到深灰渐变。它的构造方法:
类提供使用圆形辐射颜色渐变模式填充某一形状的方式。用户可以指定两种或多种渐变颜色,此绘制将在颜色与颜色之间提供一个插值。星星就是采用这种渐变方式进行渲染的。这是一种非常有趣的渐变方式,通过不同的参数,可以实现绚丽多彩的图形。详情请看javadoc。
好了,暂时就到这吧,附上全部代码:
当星星有好几千个时会是什么情况呢:
细心的童鞋发现,即使星星达到好几千个,内存的使用几乎没有什么变化。如果把星星定义成一个组件,我不敢想象把几千个组件加到面板上去会是什么状况。
后注:星星的生成算法是参考《Filthy Rich Clients》一书中的DrawShape例子,这里只不过是一个读书笔记罢了。
又忙又累,那就来点轻松简单的把,上图实现的是每半秒钟出现一个任意边形的随机颜色渲染的星星。或许这一点意义都没有,纯粹是我闲着蛋疼。实现一个任意多半行即简单又复杂:
] 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绘制出来的。当然要做出美观绚丽的界面少不了各种各样的渲染。组件的渲染很简单:
获得一个Graphics(或Graphics2D)对象。
设置这个Graphics对象的属性。
用这个Graphics对象绘制图形基本元素。
组件的千差万别也在于:
如果获取Graphics对象:是通过图像还是组件,或者给定一个。
在这个Graphics对象上设置哪些属性。
用这个Graphics对象执行什么制图操作。
拥有点、面、线,就能把整个世界描绘出来。这个Graphics都有,再加上图形学中各种数学知识。还有什么做不出来呢。本例子用到的主要方法有:
setPaint (Paint paint):
为
Graphics2D
上下文设置
Paint
属性。
fillRect (int x, int y, int width, int height):
填充指定的矩形。
setRenderingHint (RenderingHints.Key hintKey, Object hintValue):
为呈现算法设置单个首选项的值。
fill (Shape s):
使用
Graphics2D
上下文的设置,填充
Shape
的内部区域。
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,也是表示任意几何形状路径的简单而又灵活的形状。我们的多边形星星就是采用默认的非零旋绕规则生成的。用到的方法有:moveTo (float x, float y):
通过移动到指定的坐标(以 float 精度指定),将一个点添加到路径中。
lineTo (float x, float y):
通过绘制一条从当前坐标到指定新坐标(以 float 精度指定)的直线,将一个点添加到路径中。
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 monitor * Created on 2011-3-3, 22:47:03 */ 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例子,这里只不过是一个读书笔记罢了。
相关文章推荐
- Graphics的使用及五颜六色满天星的实现
- 使用github实现共享代码的一些入门级教程
- LINQ入门教程示例使用F#的实现
- Android开发-如何在Window使用AndroidStudio开发工具实现JNI的开发—入门教程
- Easyui入门视频教程 第08集---登录实现 ajax button的使用
- SDL入门教程(十):4、用iconv获得正确的Unicode,使用FriBiDi实现UTF-8到Unicode的正确转换
- twisted入门教程之十三:使用Deferred新功能实现新客户端
- RNN 入门教程 Part 2 – 使用 numpy 和 theano 分别实现RNN模型
- SDL入门教程(十):4、用iconv获得正确的Unicode,使用FriBiDi实现UTF-8到Unicode的正确转换
- 分享录制的正则表达式入门、高阶以及使用 .NET 实现网络爬虫视频教程
- iOS8使用Core Graphics实现渐变效果-Swift基础教程
- 【Swing入门教程】一步一步做Netbeans(4):JTree的使用及定制TreeCellRenderer
- 实现童年梦想——RPG游戏入门(RPG制作大师使用教程)
- 使用Python中的greenlet包实现并发编程的入门教程
- 【Winhex】狂派入门: Winhex的简单使用教程
- ASP.NET MVC5 + EF6 入门教程 (6) View中的Razor使用
- 使用Blackmagic切换台采集卡实现网络直播教程
- 使用HAL库、STM32CubeMX和Keil 5开发入门教程(一):点亮一盏LED灯(NUCLEO-F411RE)
- Android greenDao入门以及使用教程
- C#分析数据库结构,使用XSL模板自动生成代码 - 清清月儿 .NET万花筒 Asp.net技术 Asp.net教程 Asp.net源码 Asp.net基础 Asp.net控件 Asp.net入门 - CSDNBlog