- 浏览: 752031 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
u011487470:
感觉就是知识采集一样,博主能不能整理一下
基于Web的IM简介 -
whxtbest:
whxtbest 写道2里面:如果T本身就是重复的话 比如 ...
关于后缀树的一些理解 -
whxtbest:
2里面:如果T本身就是重复的话 比如S是aaab,T是aa ...
关于后缀树的一些理解 -
刘亮love小雪:
谢谢啦
Java 2D高级绘图 -
bluky999:
收集的资料挺多的 哈哈
基于Web的IM简介
知识要点:
第一节 Java 2D的增强功能
概述、AWT图形能力的不足、Java 2D API
第二节 图形绘制的基本方法
转换Graphics2D对象、Graphics 类特性、绘图的属性和基本编程方法
第三节 曲线问题的高级应用开发
直线问题深入研究、贝塞尔(Bezier)曲线、自定义样条曲线编程、
用户数据的曲线显示、曲线用Applet显示的数据来源问题
第四节 字符串的高级处理
TextLayout类、LineMetrics类
第五节 构造几何形状
2D几何形状的设计、构造型区域几何形状、变换、缓冲的图像
第六节 三维图形处理的设计技术
透视投影、透视图形的显示、隐蔽面消除问题
第七节 同环境交互
GraphicsEnvironment类、GraphicsDevice类、GraphicsConfiguration类
第一节 Java 2D的增强功能
一、概述:
由Sun公司与Adobe系统公司合作推出的Java 2D API,提供了一个功能强大而且非常灵活的二维图形框架。Java 2D API扩展了java.awt包中定义的Graphics类和Image类,提供了高性能的二维图形、图像和文字,同时又维持了对现有AWT应用的兼容。
二、AWT图形能力的不足:
在 AWT 的初始实现中,图形能力并不十分完善。因为开发 JDK 是打算将其作为平台中立的实现平台,所以其原始的功能被限制于“最少公共功能”上,所有被支持的操作系统上保证提供这些公共功能;
在 Java 2D 出现之前,对绘制能力、字体操作和图像控制的支持非常少。而对诸如用图案进行着色、形状操作以及图形变换之类的重要操作的支持则完全没有。
Java 2D 满足了跨平台实现中对这些功能以及其它功能的需求。
三、Java 2D API:
它是JFC (Java Fundation Classes)的一员,加强了传统AWT( Abstract Windowing Toolkit )的描绘功能。在 JDK1.2中已经支援 Java 2D 的使用。透过Java 2D API ,程序员可以轻松地描绘出任意的几何图形、运用不同的填色效果、对图形做旋转( rotate)、缩放( scale)、扭曲( shear)等。如图所示,程序员透过2D API所提供的功能,简单地利用不同类型的线或是填色效果绘出统计图,以区分出不同的资料。
它们是基于Graphics2D类的绘图功能,是对AWT中的Graphics类的进一步的扩展和增强。主要体现在:
1。对渲染质量的控制:消除锯齿以平滑绘制对象的边缘
2.裁剪、合成和透明度:它们允许使用任意形状来限定绘制操作的边界。它们还提供对图形进行分层以及控制透明度和不透明度的能力。
3.控制和填充简单及复杂的形状:这种功能提供了一个 Stroke 代理和一个 Paint 代理,前者定义用来绘制形状轮廓的笔(定义绘制的笔的宽度和样式),后者允许用纯色、渐变色和图案来填充形状。
4。图像处理和变换:Java 2D 同 Java 高级图像 API(Java Advanced Imaging API (JAI))协作,支持用大量图形格式处理复杂的图像。Java 2D 还为您提供了修改图像、形状和字体字符的变换能力。
5。特殊的填充方式,如梯度或者图案
6.高级字体处理和字符串格式化:允许象操作任何其它图形形状一样操作字体字符。除此以外,可以象文字处理程序一样,通过为 String 中的字符应用属性和样式信息来创建格式化文本。
java.awt.geom 包中的Areas类支援联集( union)、交集( intersection)、差集(subtraction )、Exclusive OR (XOR)等布尔运算。最後, AffineTransform 类别则提供图形物件做Scale(比例)、Shear(剪裁) 、Rotate(旋转)等座标上的转换。
第二节 图形绘制的基本方法
一、转换Graphics2D对象
绘制图形时,可以在Graphics对象或者Graphics2D对象上进行,它们都代表了需要绘图的区域,选择那个取决于是否要使用所增加的Java2D的图形功能。但要注意的是,所有的Java2D图形操作都必须在Graphics2D对象上调用。Graphics2D是Graphics的子类,同样包含在java.awt包中。
public void paintComponent(Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
}
或者
public void paint (Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
}
二、Graphics 类特性
Graphics 类支持几种确定图形环境状态的特性。以下列出了部分特性:
1)Color:当前绘制颜色,它属于 java.awt.Color 类型。所有的绘制、着色和纯文本输出都将以指定的颜色显示。
2)Font:当前字体,它属于 java.awt.Font 类型。它是将用于所有纯文本输出的字体。
3)Clip:java.awt.Shape 类型的对象,它充当用来定义几何形状的接口。该特性包含的形状定义了图形环境的区域,绘制将作用于该区域。通常情况下,这一形状与整个图形环境相同,但也并不一定如此。
4)ClipBounds:java.awt.Rectangle 对象,它表示将包围由 Clip 特性定义的 Shape 的最小矩形。它是只读特性。
5)FontMetrics:java.awt.FontMetrics 类型的只读特性。该对象含有关于图形环境中当前起作用的 Font 的信息。如同我们将看到的那样,获取此信息的这种机制已被 LineMetrics 类所取代
6)Paint Mode:该特性控制环境使用当前颜色的方式。如果调用了 setPaintMode() 方法,那么所有绘制操作都将使用当前颜色。如果调用了 setXORMode() 方法(该方法获取一个 Color 类型的参数),那么就用指定的颜色对像素做“XOR”操作。XOR 具有在重新绘制时恢复初始位模式的特性,因此它被用作橡皮擦除和动画操作。
三、绘图的属性和基本编程方法
1)颜色Color类:没有变化。
2)填充方式:
Paint(油漆桶) 接口有几个具体的实现,它们允许用纯色、渐变色或图案来填充形状。
1,纯色填充(Color类):对 java.awt.Color 类做了一些调整以实现 Paint,并且可以用于纯色填充。
2,渐变色来填充(梯度填充GradientPaint类):java.awt.GradientPaint 类允许用线性颜色渐变色来填充形状,线性颜色渐变色允许在两个指定的 Color 对象之间创建过渡。可以将渐变色设置成“周期性的”,这将导致渐变色图案重复出现。
3,图案填充(纹理TexturePaint类):提供了 java.awt.TexturePaint 类,它可以用由 BufferedImage 描述的图案填充形状
编程方法:
使用Graphics2D类中的setPaint()方法并使用Paint对象作为其参数,但由于任何可以作为填充的类如GradientPaint、TexturePaint和Color都实现了Paint接口(该接口注意定义了在Graphics2D下的颜色填充方式),因此可以将它们作为参数。如:
public void paintComponent(Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
GradientPaint pat=new GradientPaint(0f,0f,Color.white,100f,45f,Color.blue);
comp2D.setPaint(pat);
}
3)设置笔的形状:
Stroke 接口由 java.awt.BasicStroke 类实现。该类允许进行大量的选择以修改线的绘制细节。可以编程指定 BasicStroke 宽度,也可以指定对名为柱头和交点的路径上端点和交点的“装饰”。现在也可以绘制点划线了,只须设置 BasicStroke 的破折号属性即可。
在Graphics类中线条是一个点宽,而在Graphics2D中可以通过BasicStoke类中的setStroke()方法来设置。其构造函数是BasicStroke(float width, int cap, int join)
其中width指示线宽(缺省时为1.0)
cap指示线的末端(包头,在BasicStroke类中定义出三个static 类型的常量如CAP_BUTT没有包头( )、CAP_ROUND圆包头( )、CAP_SQUARE方包头( )的样式
join指示线段之间的拐角(在BasicStroke类中定义出三个static 类型的常量如JOIN_BEVEL( )、JOIN_MITER( )、 JOIN_ROUND( )样式。
4)编程方法:
public void paintComponent(Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
BasicStroke pen
=new BasicStroke(2.0f, BasicStroke .CAP_BUTT, BasicStroke .JOIN_ROUND);
comp2D.setStroke (pen);
}
代码示例:
float thick = 0.5f; //设置画刷的粗细为 0.5
BufferedImage bi = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D)bi.getGraphics();
Stroke stroke = g.getStroke(); //得到当前的画刷
g.setStroke(new BasicStroke(thick, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
g.draw(new Line2D.Float(x1, y1, x2, y2)); 画线
g.setStroke( stroke ); //将画刷复原
5)创建要绘制的形状对象
在Java2D中进行绘图时,不是采用对应的方法来实现,而是为要实现某中形状创建出相应的形状对象。这可以通过使用java.awt.geom包中的类来定义所要创建的形状。如线条Line2D.Float类、距形Rectangle2D.Float或者Rectangle2D.Double类、椭圆Ellipes2D.Float、圆弧Arc2D.Float类等。
6)绘制对象:
1,可以使用Graphics2D类中的方法draw()用于绘制轮廓,而fill()方法用于填充。它们都以前面所创建的图形对象作为参数。
2,Java2D中的字符串的绘制仍然采用drawString()方法,但有drawString(String s, float x, float y)和drawString(String str, int x, int y)。
3,绘制轮廓:draw(Shape s)其中的Shape接口在Graphics2D中被定义
新的 Java 2D Shape 类都有“2D”后缀。这些新的形状使用浮点值(而不是整数)来描述其几何形状。
Polygon类(int[] xpoints, int[] ypoints, int npoints)
RectangularShape(抽象类,其子类有Arc2D, Ellipse2D, Rectangle2D, RoundRectangle2D), Rectangle(距形)
QuadCurve2D(二次贝塞尔样条曲线,贝塞尔曲线由两个端点以及一个或两个控制点指定。贝塞尔曲线创建了适合于大多数表示的曲线。)
CubicCurve2D(三次贝塞尔样条曲线)
Area(区域)
GeneralPath(由直线、二次样条曲线、三次样条曲线所构成)
Line2D
8)基本步骤
绘图的第一个步骤是产生 Graphics2D 对象。 然后设定所要的状态属性。例如你想要对一物件做渐层式的填色,可以设定属性 Paint为 GradientPaint。最後再调用Graphics2D所提供的方法fill或是draw,完成整个绘图的程序。
9)程序实例
例一:
这是一个最简单的例子,也可以认为是绘图的一个最简单的框架。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class Map extends JFrame
{ public Map()
{ super("Map");
setSize(350,350);
MapPane map=new MapPane();
getContentPane().add(map);
}
public static void main(String [] arg)
{ Map frame=new Map();
frame.show();
}
}
class MapPane extends JPanel
{ public void paintComponent(Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
comp2D.drawString("sbcd",200,200);
Line2D.Float line=new Line2D.Float(1.0f,2.0f,200.0f,200.0f);
comp2D.draw(line);
}
}
例二:
下面是在Graphics2D模式下的基本绘图框架。我们可以看到,利用:
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
通过该方法的设置,使图形去除锯齿状,可以得到多么细腻的图形。
样例:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class DrawDemo extends JFrame {
public DrawDemo(){
//设置窗口的大小、标题
this.setSize(new Dimension(600, 400));
//创建绘制各种形状的容器
ShapesPanel shapesPanel = new ShapesPanel();
//将该容器加入窗口
getContentPane().add(shapesPanel, BorderLayout.CENTER);
}
public static void main(String[] args) {
DrawDemo frame = new DrawDemo();
frame.setVisible(true);
//当窗口关闭时清空内存
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
//创建各种容器的类
class ShapesPanel extends JPanel {
final int maxCharHeight = 15;
final Color bg = Color.white; //声明背景颜色为灰色
final Color fg = Color.blue; //声明前景颜色为蓝色
public ShapesPanel() {
setBackground(bg); //设置背景颜色
setForeground(fg); //设置前景颜色
//创建组合边框
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createRaisedBevelBorder(),
BorderFactory.createLoweredBevelBorder()));
}
public void paintComponent(Graphics g1) {
super.paintComponent(g1); //清空背景颜色
float thick = 0.5f; //设置画刷的粗细为 0.5
Graphics2D g = (Graphics2D)g1;
Stroke stroke = g.getStroke(); //得到当前的画刷
g.setStroke(new BasicStroke(thick, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
//通过该方法使图形去除锯齿状
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
String txt= "我的文章";
int style=2;//0普通1粗体2斜体3粗斜
g.setFont(new Font("宋体", 2, 15)); //15为字大小
//设置笔刷为黑色
g.setPaint(Color.black);
g.drawString(txt,200,150);
g.setPaint(Color.red);
g.draw(new Line2D.Float(0,0,200,150)); //画线
g.setPaint(Color.blue);
g.draw(new Rectangle2D.Float(200,150,100,100));
g.setStroke(stroke); //将画刷复原
}
}
例三:图形灵活的显示
在上面的例子中,是使用一个继承于JPanel的类,覆盖它的void paintComponent(Graphics g1)事件方法,实现绘图的,这样虽然方便,但显得灵活性不高。
实际上,通过JPanel对象直接赋值给Graphics2D对象,往往可以使程序具有很大的灵活性。程序可以这样来写。
JPanel contentPane= (JPanel) this.getContentPane();
public Graphics2D comp2D=(Graphics2D)contentPane .getGraphics();
样例:
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawDemo1 extends JFrame
{
public JPanel contentPane; //绘图窗口
public Graphics2D comp2D; //绘图对象
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
//构造函数
public DrawDemo1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件的初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(400, 300));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 235, 100, 31));
jButton1.setText("画线保留");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(150, 235, 100, 30));
jButton2.setText("画线删除");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
}
public static void main(String[] args) {
DrawDemo1 frame=new DrawDemo1();
frame.show();
frame.comp2D=(Graphics2D)frame.contentPane .getGraphics();
frame.comp2D.setBackground(Color.white);
frame.comp2D.clearRect(0,0,401,221);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
void jButton1_actionPerformed(ActionEvent e){
comp2D.setPaint(Color.red);
Line2D.Float line=new Line2D.Float(1.0f,2.0f,200.0f,220.0f);
comp2D.draw(line);
}
void jButton2_actionPerformed(ActionEvent e) {
comp2D.clearRect(0,0,401,221);
comp2D.setPaint(Color.blue);
Line2D.Float line=new Line2D.Float(1.0f,100.0f,300.0f,220.0f);
comp2D.draw(line);
}
}
例四:剪裁
图形处理问题中,剪裁由的时候是非常难处理的,所谓剪裁是指超过绘图取得内容不显示,看起来这是个简单问题,但由于所有的线条必须计算与边界的交点,而且边界有四个方向,这就使问题变得很复杂。java 2D很好的解决了这个问题,请看下面的例子。
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawDemo2 extends JFrame
{
public JPanel contentPane; //绘图窗口
public Graphics2D comp2D; //绘图对象
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
//构造函数
public DrawDemo2() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(400, 300));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 235, 100, 31));
jButton1.setText("画线保留");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(150, 235, 100, 30));
jButton2.setText("画线删除");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
}
public static void main(String[] args) {
DrawDemo2 frame=new DrawDemo2();
frame.show();
frame.comp2D=(Graphics2D)frame.contentPane .getGraphics();
frame.comp2D.setBackground(Color.white);
frame.comp2D.clearRect(0,0,401,221);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
void jButton1_actionPerformed(ActionEvent e){
comp2D.setPaint(Color.red);
Line2D.Float line=new Line2D.Float(1.0f,2.0f,200.0f,220.0f);
comp2D.draw(line);
}
void jButton2_actionPerformed(ActionEvent e) {
comp2D.clearRect(0,0,401,221);
//剪裁
comp2D.setClip(50,50,300,150);
comp2D.setPaint(Color.blue);
Line2D.Float line=new Line2D.Float(1.0f,100.0f,300.0f,220.0f);
comp2D.draw(line);
}
}
第三节 曲线问题的高级应用开发
在jdk尚未支援 2D图形之前,只可以画出直的、相同粗细的线条。现在可以通过2D API绘出不同粗细的线条及圆滑的曲线。在java.awt.geom包中提供了Line2D、 QuadCurve2D(二次贝塞尔曲线)及 CubicCurve2D(三次贝塞尔曲线)等相关的类,让程序员能够轻松地绘出想要的线条。
其实绘图的核心是画线,下面通过一些实例对一些问题进行深入的讨论。
一、直线问题深入研究
样例:
我们通过一个例子,深入的研究一下绘制直线和折线需要掌握哪些内容。
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawDemo1 extends JFrame
{
public JPanel contentPane; //绘图窗口
public Graphics2D comp2D; //绘图对象
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
JButton jButton3 = new JButton();
//构造函数
public DrawDemo1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(400, 300));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 235, 100, 31));
jButton1.setText("园头");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(150, 235, 100, 30));
jButton2.setText("方头");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
jButton3.setBounds(new Rectangle(270, 235, 100, 30));
jButton3.setText("封闭");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton3_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
jPanel1.add(jButton3, null);
}
public static void main(String[] args) {
DrawDemo1 frame=new DrawDemo1();
frame.show();
frame.comp2D=(Graphics2D)frame.contentPane .getGraphics();
frame.comp2D.setBackground(Color.white);
frame.comp2D.clearRect(0,0,401,221);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
int Xs1[]={10,60,120,200,260,340};
int Ys1[]={10,200,120,180,60,130};
void jButton1_actionPerformed(ActionEvent e){
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 10f;
//设置笔刷
//园头园连接
comp2D.setStroke(new BasicStroke(thick,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
comp2D.setPaint(Color.red);
//通过该方法使图形去除锯齿状
comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
comp2D.drawPolyline(Xs1,Ys1,Xs1.length);
}
void jButton2_actionPerformed(ActionEvent e) {
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 10f;
//设置笔刷
//方头方连接
comp2D.setStroke(new BasicStroke(thick,
BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE));
comp2D.setPaint(Color.blue);
//通过该方法使图形去除锯齿状
//comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
// RenderingHints.VALUE_ANTIALIAS_ON);
comp2D.drawPolyline(Xs1,Ys1,Xs1.length);
}
void jButton3_actionPerformed(ActionEvent e) {
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 1f;
//设置笔刷
//方头方连接
comp2D.setStroke(new BasicStroke(thick,
BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE));
comp2D.setPaint(Color.blue);
//通过该方法使图形去除锯齿状
//comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
// RenderingHints.VALUE_ANTIALIAS_ON);
//画封闭线
comp2D.drawPolygon(Xs1,Ys1,Xs1.length);
}
}
二、贝塞尔(Bezier)曲线
java 2D提供的QuadCurve2D(二次贝塞尔曲线)及 CubicCurve2D(三次贝塞尔曲线)等相关的类,可以很容易的画出贝赛尔曲线。
QuadCurve2D为三个数据,中间一个为控制点。
CubicCurve2D为四个数据,中间两个为控制点。
样例:
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawDemo1 extends JFrame
{
public JPanel contentPane; //绘图窗口
public Graphics2D comp2D; //绘图对象
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
//构造函数
public DrawDemo1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(400, 300));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 235, 150, 31));
jButton1.setText("二阶贝塞尔");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(200, 235, 150, 30));
jButton2.setText("三阶贝塞尔");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
}
public static void main(String[] args) {
DrawDemo1 frame=new DrawDemo1();
frame.show();
frame.comp2D=(Graphics2D)frame.contentPane .getGraphics();
frame.comp2D.setBackground(Color.white);
frame.comp2D.clearRect(0,0,401,221);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
void jButton1_actionPerformed(ActionEvent e){
double[] x1={50,180,300};
double[] y1={100,190,100};
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 1f;
comp2D.setPaint(Color.red);
QuadCurve2D.Double qc=new QuadCurve2D.Double();
qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2]);
comp2D.draw(qc);
comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]);
comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5);
comp2D.setPaint(Color.blue);
x1[1]=180;
y1[1]=30;
qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2]);
comp2D.draw(qc);
comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]);
comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5);
}
void jButton2_actionPerformed(ActionEvent e) {
double[] x1={50,80,200,300};
double[] y1={100,70,190,100};
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 1f;
comp2D.setPaint(Color.red);
CubicCurve2D.Double qc=new CubicCurve2D.Double();
qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2],x1[3],y1[3]);
comp2D.draw(qc);
comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]);
comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5);
comp2D.drawLine((int)x1[2]-5,(int)y1[2],(int)x1[2]+5,(int)y1[2]);
comp2D.drawLine((int)x1[2],(int)y1[2]-5,(int)x1[2],(int)y1[2]+5);
float dash1[] = {10.0f};
//画虚线
BasicStroke dashed = new BasicStroke(1.0f,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER,
10.0f, dash1, 0.0f);
comp2D.setStroke(dashed);
comp2D.setPaint(Color.darkGray);
comp2D.drawLine((int)x1[1],(int)y1[1],(int)x1[2],(int)y1[2]);
//画实线
BasicStroke stroke = new BasicStroke(1.0f);
comp2D.setStroke(stroke);
comp2D.setPaint(Color.blue);
x1[1]=180;
y1[1]=70;
x1[2]=80;
y1[2]=190;
qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2],x1[3],y1[3]);
comp2D.draw(qc);
comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]);
comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5);
comp2D.drawLine((int)x1[2]-5,(int)y1[2],(int)x1[2]+5,(int)y1[2]);
comp2D.drawLine((int)x1[2],(int)y1[2]-5,(int)x1[2],(int)y1[2]+5);
comp2D.setStroke(dashed);
comp2D.setPaint(Color.darkGray);
comp2D.drawLine((int)x1[1],(int)y1[1],(int)x1[2],(int)y1[2]);
comp2D.setStroke(stroke);
}
}
三、自定义样条曲线编程
当我们需要平滑多个数据样本点的时候,贝塞尔曲线就不能满足要求了,为此,可以采用最早由美国“波音”飞机制造公司提出来的样条曲线来完成,这种曲线所以称之为样条,是因为它模拟了造船业中的放样原理。
样条曲线的数学原理请参考计算机图形学,这里给出的是由java编写的三次样条曲线的例子。曲线平滑的原则是,必须通过所有的样本点,另外,不论有多少样本点,曲线的阶次最大为三次,所以是稳定的。
这里我们可以看出来,程序设计的生命是什么呢?数学!这是程序设计着的生命所在。语言只是一种规范或者是一个工具,要真正写出好的程序,没有深厚的数学功底,是万万不可能的。
样例:
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawCurve extends JFrame
{
public JPanel contentPane; //绘图窗口
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
JButton jButton3 = new JButton();
GraphicsCurve gracu;
//构造函数
public DrawCurve() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(500,400));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 310, 100, 31));
jButton1.setText("直线");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(150, 310, 100, 30));
jButton2.setText("样条曲线");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
jButton3.setBounds(new Rectangle(270, 310, 100, 30));
jButton3.setText("粗线条");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton3_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
jPanel1.add(jButton3, null);
gracu=new GraphicsCurve();
}
public static void main(String[] args) {
DrawCurve frame=new DrawCurve();
frame.show();
frame.gracu.myGraphics=(Graphics2D)frame.contentPane .getGraphics();
frame.gracu.myGraphics.setBackground(Color.white);
frame.gracu.myGraphics.clearRect(0,0,500,300);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
int Xs1[]={10,60,120,200,260,340};
int Ys1[]={10,200,120,180,60,130};
//画折线
void jButton1_actionPerformed(ActionEvent e){
gracu.myGraphics.setPaint(Color.blue);
gracu.myGraphics.drawPolyline(Xs1,Ys1,Xs1.length);
}
//画样条
void jButton2_actionPerformed(ActionEvent e) {
gracu.myGraphics.setPaint(Color.red);
gracu.DrawCurves(Xs1,Ys1);
}
//画粗线
void jButton3_actionPerformed(ActionEvent e) {
//笔宽度
float thick = 10f;
//设置笔刷
//方头园连接
//gracu.myGraphics.setStroke(new BasicStroke(thick, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
//园头园连接
gracu.myGraphics.setStroke(new BasicStroke(thick, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
gracu.myGraphics.setPaint(Color.blue);
//通过该方法使图形去除锯齿状
gracu.myGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
gracu.myGraphics.drawPolyline(Xs1,Ys1,Xs1.length);
}
}
class GraphicsCurve
{
//绘图对象
public Graphics2D myGraphics;
public GraphicsCurve()
{
}
public GraphicsCurve(Graphics2D graphics)
{
this.myGraphics=graphics;
}
//参数表
//x数组,y数组,笔刷
public void DrawCurves(int[] xa,int[] ya)
{
int[] x, y;
double[] a, b, c;
double[] px, py, qx, qy, tt;
double[] dx, dy;
int px1,py1,px2,py2;
x=xa;
y=ya;
px1=x[0];
py1=y[0];
int n=x.length;
a=new double[n];
b=new double[n];
c=new double[n];
px=new double[n];
py=new double[n];
qx=new double[n];
qy=new double[n];
tt=new double[n];
dx=new double[n];
dy=new double[n];
int i, t, es;
double bx3, bx4, by3, by4, cx, cy;
bx4 = 0;
by3 = 0;
es = 3;
px[0] = 1;
py[0] = 1;
px[n-1] = 1;
py[n-1] = 1;
if (n>1)
{
for (i = 1;i<n;i++)
tt[i] = Math.sqrt((x[i] - x[i - 1]) * (x[i] - x[i - 1]) + (y[i] - y[i - 1]) * (y[i] - y[i - 1]));
switch(n)
{
case 2:
break;
case 3:
for (i = 1;i<n - 1;i++)
{
a[i] = 2 * (tt[i] + tt[i + 1]);
b[i] = tt[i + 1];
c[i] = tt[i];
dx[i] = 3 * (tt[i] * (x[i + 1] - x[i]) / tt[i + 1] + tt[i + 1] * (x[i] - x[i - 1]) / tt[i]);
dy[i] = 3 * (tt[i] * (y[i + 1] - y[i]) / tt[i + 1] + tt[i + 1] * (y[i] - y[i - 1]) / tt[i]);
}
dx[1] = dx[1] - tt[2] * px[0];
dx[n - 2] = dx[n - 2] - tt[n - 2] * px[n-1];
dy[1] = dy[1] - tt[2] * py[0];
dy[n - 2] = dy[n - 2] - tt[n - 2] * py[n-1];
//注意,这是n=3的情况专有计算
px[1] = dx[1] / a[1];
py[1] = dy[1] / a[1];
break;
default:
for (i = 1;i<n - 1;i++)
{
a[i] = 2 * (tt[i] + tt[i + 1]);
b[i] = tt[i + 1];
c[i] = tt[i];
dx[i] = 3 * (tt[i] * (x[i + 1] - x[i]) / tt[i + 1] + tt[i + 1] * (x[i] - x[i - 1]) / tt[i]);
dy[i] = 3 * (tt[i] * (y[i + 1] - y[i]) / tt[i + 1] + tt[i + 1] * (y[i] - y[i - 1]) / tt[i]);
}
dx[1] = dx[1] - tt[2] * px[0];
dx[n - 2] = dx[n - 2] - tt[n - 2] * px[n-1];
dy[1] = dy[1] - tt[2] * py[0];
dy[n - 2] = dy[n - 2] - tt[n - 2] * py[n-1];
c[1] = c[1]/ a[1];
for (i = 2 ;i< n - 1;i++)
{
a[i] = a[i] - b[i] * c[i - 1];
c[i] = c[i] / a[i];
}
qx[1] = dx[1] / a[1];
qy[1] = dy[1] / a[1];
for (i = 2 ;i< n - 1;i++)
{
qx[i] = (dx[i] - b[i] * qx[i - 1]) / a[i];
qy[i] = (dy[i] - b[i] * qy[i - 1]) / a[i];
}
px[n - 2] = qx[n - 2];
py[n - 2] = qy[n - 2];
for (i = n - 3;i>=1;i--)
{
px[i] = qx[i] - c[i] * px[i + 1];
py[i] = qy[i] - c[i] * py[i + 1];
}
break;
}
for (i = 0 ;i< n - 1;i++)
{
bx3 = (3 * (x[i + 1] - x[i]) / tt[i + 1] - 2 * px[i] - px[i + 1]) / tt[i + 1];
bx4 = ((2 * (x[i] - x[i + 1]) / tt[i + 1] + px[i] + px[i + 1]) / tt[i + 1]) / tt[i + 1];
by3 = (3 * (y[i + 1] - y[i]) / tt[i + 1] - 2 * py[i] - py[i + 1]) / tt[i + 1];
by4 = ((2 * (y[i] - y[i + 1]) / tt[i + 1] + py[i] + py[i + 1]) / tt[i + 1]) / tt[i + 1];
t = 0;
while (t < tt[i + 1])
{
t = t + es;
cx = x[i] + (px[i] + (bx3 + bx4 * t) * t) * t;
cy = y[i] + (py[i] + (by3 + by4 * t) * t) * t;
px2 = (int)cx;
py2 = (int)cy;
myGraphics.drawLine(px1,py1,px2,py2);
px1 = px2;
py1 = py2;
}
}
}
}
}
四、用户数据的曲线显示
当需要用曲线表达数据的时候,我们虽然可以使用由厂家提供的“图表”组件,但更多的还是需要自己编写的,请仔细研究下面的程序,当对图表设计有更深入的理解。
下面的例子,我们构造一个专门处理用户数据的类,在这个类里,实现了用户坐标和屏幕坐标的转换,同时给出了一个自动绘制坐标的方法。我们也直接使用了上面我们讨论过的样条曲线的类实现数据平滑。例子中的数据可以来自于数据库或其它任何地方,仔细的研究这个例子,可以看出只要我们开动脑筋,把java强大的功能和我们对问题的理解结合在一起,就可以写出多么灵活多变的程序来呀!
样例:
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.geom.*;
public class DataDrawDemo extends JFrame
{
public JPanel contentPane; //控件容器
JPanel jPanel1 = new JPanel();//绘图控件
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
JButton jButton3 = new JButton();
JButton jButton4 = new JButton();
JButton jButton5 = new JButton();
JButton jButton6 = new JButton();
JButton jButton7 = new JButton();
JButton jButton8 = new JButton();
JButton jButton9 = new JButton();
JButton jButton10 = new JButton();
JTextField jText1=new JTextField();
JTextField jText2=new JTextField();
boolean kcu=true;
//用户坐标转换对象
myGraphicsData mp=new myGraphicsData();
//曲线转换对象
GraphicsCurve gracu=new GraphicsCurve();
//窗口范围
double wx1,wx2,wy1,wy2;
//构造函数
public DataDrawDemo() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//初始化代码
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(null);
this.setSize(new Dimension(650, 500));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
//jPanel1.setLayout(null);
jPanel1.setBounds(0,90,650,420);
jButton1.setBounds(new Rectangle(30, 20, 80, 25));
jButton1.setText("开始");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(120, 20, 80, 25));
jButton2.setText("左移");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
jButton3.setBounds(new Rectangle(210, 20, 80, 25));
jButton3.setText("右移");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton3_actionPerformed(e);
}
});
jButton4.setBounds(new Rectangle(300, 20, 80, 25));
jButton4.setText("上移");
jButton4.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton4_actionPerformed(e);
}
});
jButton5.setBounds(new Rectangle(390, 20, 80, 25));
jButton5.setText("下移");
jButton5.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton5_actionPerformed(e);
}
});
jButton6.setBounds(new Rectangle(120, 50, 80, 25));
jButton6.setText("X扩");
jButton6.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton6_actionPerformed(e);
}
});
jButton7.setBounds(new Rectangle(210, 50, 80, 25));
jButton7.setText("X缩");
jButton7.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton7_actionPerformed(e);
}
});
jButton8.setBounds(new Rectangle(300, 50, 80, 25));
jButton8.setText("Y扩");
jButton8.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton8_actionPerformed(e);
}
});
jButton9.setBounds(new Rectangle(390, 50, 80, 25));
jButton9.setText("Y缩");
jButton9.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton9_actionPerformed(e);
}
});
//样条控制
jButton10.setBounds(new Rectangle(30, 50, 80, 25));
jButton10.setText("样条");
jButton10.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton10_actionPerformed(e);
}
});
jText1.setBounds(new Rectangle(490, 20, 120, 20));
jText1.setText("");
jText2.setBounds(new Rectangle(490, 50, 120, 20));
jText2.setText("");
//鼠标按下侦听器
jPanel1.addMouseListener(new java.awt.event.MouseAdapter(){
public void mousePressed(MouseEvent e) {
JPanel_mousePressed(e);
}
});
//鼠标拖动侦听器
jPanel1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
JPanel_mouseDragged(e);
}
});
//鼠标释放侦听器
jPanel1.addMouseListener(new java.awt.event.MouseAdapter(){
public void mouseReleased(MouseEvent e) {
JPanel_mouseReleased(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
contentPane.add(jButton1, null);
contentPane.add(jButton2, null);
contentPane.add(jButton3, null);
contentPane.add(jButton4, null);
contentPane.add(jButton5, null);
contentPane.add(jButton6, null);
contentPane.add(jButton7, null);
contentPane.add(jButton8, null);
contentPane.add(jButton9, null);
contentPane.add(jButton10, null);
contentPane.add(jText1, null);
contentPane.add(jText2, null);
}
public static void main(String[] args) {
DataDrawDemo frame=new DataDrawDemo();
frame.show();
frame.gracu.myGraphics=(Graphics2D)frame.jPanel1.getGraphics();
frame.mp.myGraphics=(Graphics2D)frame.jPanel1.getGraphics();
frame.mp.myGraphics.setBackground(Color.white);
frame.mp.myGraphics.clearRect(0,0,650,375);
}
//第一组数据
double[] Xs1=new double[]{-2,2,4,6,8,10,12,14};
double[] Ys1=new double[]{-4,10,3,14,4,10,6,7};
//第二组数据
double[] Xs2=new double[]{-1,2,4,6,8,10,12,14,16};
double[] Ys2=new double[]{1,5,7,1,13,11,4,10,8};
//这是一个画曲线的程序
void DwData()
{
//剪裁,可以试试没有剪裁是什么表现?
mp.myGraphics.clipRect(10,10,621,351);
//由于是用两个对象绘图,所以应该分别剪切
gracu.myGraphics.clipRect(10,10,621,351);
//清除绘图空间
mp.myGraphics.clearRect(0,0,650,375);
//用户坐标和屏幕坐标转换
mp.truemode(10,630,10,360,wx1,wx2,wy1,wy2);
//设置颜色
mp.myGraphics.setPaint(Color.darkGray);
//画边框
mp.myGraphics.drawRect(10,10,620,350);
mp.myGraphics.setFont(new Font("宋体", 0, 10)); //9为字大小
//画坐标
mp.axis(2,2,2,2);
//画红线
int[] x=new int[Xs1.length];
int[] y=new int[Ys1.length];
int[] myxy;
//统一实现坐标转换
for (int i=0;i<x.length;i++)
{
myxy=mp.moxy(Xs1[i],Ys1[i]);
x[i]=myxy[0];
y[i]=myxy[1];
}
if (kcu)
{
mp.myGraphics.setPaint(Color.red);
mp.myGraphics.drawPolyline(x,y,x.length);
}
else
{
gracu.myGraphics.setPaint(Color.red);
gracu.DrawCurves(x,y);
}
//画蓝线
x=new int[Xs2.length];
y=new int[Ys2.length];
for (int i=0;i<x.length;i++)
{
myxy=mp.moxy(Xs2[i],Ys2[i]);
x[i]=myxy[0];
y[i]=myxy[1];
}
if (kcu)
{
mp.myGraphics.setPaint(Color.blue);
mp.myGraphics.drawPolyline(x,y,x.length);
}
else
{
gracu.myGraphics.setPaint(Color.blue);
gracu.DrawCurves(x,y);
}
}
//退出窗口事件
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
//鼠标按下事件
void JPanel_mousePressed(MouseEvent e)
{
double[] zs=mp.ScrtoCon(e.getX(),e.getY());
jText1.setText(String.valueOf((float)zs[0]));
jText2.setText(String.valueOf((float)zs[1]));
}
//鼠标释放事件
void JPanel_mouseReleased(MouseEvent e)
{
double[] zs=mp.ScrtoCon(e.getX(),e.getY());
jText1.setText("");
jText2.setText("");
//画红线
mp.myGraphics.setPaint(Color.darkGray);
mp.myGraphics.drawLine(e.getX()-3,e.getY(),e.getX()+3,e.getY());
mp.myGraphics.drawLine(e.getX(),e.getY()-3,e.getX(),e.getY()+3);
mp.myGraphics.drawString(String.valueOf((float)zs[0]),e.getX()+10,e.getY());
mp.myGraphics.drawString(String.valueOf((float)zs[1]),e.getX()+10,e.getY()+12);
}
//鼠标拖动事件
void JPanel_mouseDragged(MouseEvent e)
{
double[] zs=mp.ScrtoCon(e.getX(),e.getY());
jText1.setText(String.valueOf((float)zs[0]));
jText2.setText(String.valueOf((float)zs[1]));
}
//开始
void jButton1_actionPerformed(ActionEvent e){
wx1=1000000;
wy1=1000000;
wx2=-1000000;
wy2=-1000000;
//试验中数据来自一个数组,实际中可来自任何地方
//设置初始范围
for (int i=0;i<Xs1.length;i++)
{
if (Xs1[i]< wx1)
wx1=Xs1[i];
if (Xs1[i]> wx2)
wx2=Xs1[i];
if (Ys1[i]< wy1)
wy1=Ys1[i];
if (Ys1[i]> wy2)
wy2=Ys1[i];
}
for (int i=0;i<Xs2.length;i++)
{
if (Xs2[i]< wx1)
wx1=Xs2[i];
if (Xs2[i]> wx2)
wx2=Xs2[i];
if (Ys2[i]< wy1)
wy1=Ys2[i];
if (Ys2[i]> wy2)
wy2=Ys2[i];
}
DwData();
}
//左移
void jButton2_actionPerformed(ActionEvent e) {
wx1-=1;
wx2-=1;
DwData();
}
//右移
void jButton3_actionPerformed(ActionEvent e) {
wx1+=1;
wx2+=1;
DwData();
}
//上移
void jButton4_actionPerformed(ActionEvent e) {
wy1-=1;
wy2-=1;
DwData();
}
//下移
void jButton5_actionPerformed(ActionEvent e) {
wy1+=1;
wy2+=1;
DwData();
}
//X扩
void jButton6_actionPerformed(ActionEvent e) {
wx1-=1;
wx2+=1;
DwData();
}
//X缩
void jButton7_actionPerformed(ActionEvent e) {
wx1+=1;
wx2-=1;
DwData();
}
//Y扩
void jButton8_actionPerformed(ActionEvent e) {
wy1-=1;
wy2+=1;
DwData();
}
//Y缩
void jButton9_actionPerformed(ActionEvent e) {
wy1+=1;
wy2-=1;
DwData();
}
//样条控制
void jButton10_actionPerformed(ActionEvent e) {
if (kcu)
{
jButton10.setText("直线");
kcu=false;
}
else
{
jButton10.setText("样条");
kcu=true;
}
DwData();
}
}
//图形处理类
class myGraphicsData
{
//屏幕坐标
private int X11, Y11, X12, Y12; //x1,y1,x2,y2
//用户坐标
private double W1, W2, W3, W4; //x1,x2,y1,y2
//绘图对象
public Graphics2D myGraphics;
double Ax8, Ay8;
//用户窗口与屏幕窗口的转换
//x1,x2,,y1,y2为屏幕坐标
//wx1,wx2,wy1,wy2为用户坐标
public void truemode(int x1, int x2, int y1,int y2, double wx1, double wx2, double wy1, double wy2)
{
X11 = x1 ; X12 = x2;
Y11 = y1 ; Y12 = y2;
W1 = wx1 ; W2 = wx2;
W3 = wy1 ; W4 = wy2;
Ax8 = (X12 - X11) / (wx2 - wx1);
Ay8 = (Y12 - Y11) / (wy2 - wy1);
}
//把用户坐标转为屏幕坐标
public int[] moxy(double Xa, double Ya)
{
int[] myout=new int[2];
myout[0] = (int)(Ax8 * (Xa - W1) + X11);
myout[1] = (int)(Y12 - Ay8 * (Ya - W3));
return myout;
}
//把屏幕坐标转为用户坐标
public double[] ScrtoCon(int X6, int Y6)
{
double[] myout=new double[2];
myout[0] = (X6 - X11) / Ax8 + W1;
myout[1] = (Y12 - Y6) / Ay8 + W3;
return myout;
}
//画线
public void Dline(double xa, double ya, double xb, double yb)
{
try
{
int x6, y6, x7, y7;
x6 = (int)(Ax8 * (xa - W1) + X11);
y6 = (int)(Y12 - Ay8 * (ya - W3));
x7 = (int)(Ax8 * (xb - W1) + X11);
y7 = (int)(Y12 - Ay8 * (yb - W3));
myGraphics.drawLine(x6, y6, x7, y7);
}
catch(Exception e){}
}
//画坐标U,V为 X,Y轴单位,ns,nt为 x,y轴写字间隔
public void axis(double u, double v, int ns, int nt)
{
double p9, q9, s;
int n2, swx,swy;
int xk=0;
int yk=0;
double ge;
int[] showxy=new int[2];
swx = 0;
swy=4;
ge = (double)0.008 * (W2 - W1);
p9 = W1;
q9 = (double)(W3 + (W4 - W3) * 0.05);
if ((W1 < 0) && (W2 > 0)) p9 = 0;
if ((W3 < 0) && (W4 > 0)) q9 = 0;
Dline(p9, W3, p9, W4);
n2 = 0;
s = 0;
while (s < W4)
{
Dline(p9, s, p9 + ge, s);
if (n2 >= nt)
{
Dline(p9, s, p9 + ge + ge, s);
n2 = 1;
showxy=moxy(p9 + ge + ge,s);
myGraphics.drawString(String.valueOf(s),showxy[0] - swx+4, showxy[1] - swy+4);
}
else
{
n2++;
}
s += v;
}
//End While
s = 0;
n2 = 0;
while (s > W3)
{
Dline(p9, s, p9 + ge, s);
if (n2 >= nt)
{
Dline(p9, s, p9 + ge + ge, s);
n2 = 1;
showxy=moxy(p9 + ge + ge, s);
myGraphics.drawString(String.valueOf(s),showxy[0] - swx+4, showxy[1] - swy+4);
}
else
{
n2 ++;
}
s -= v;
}
//End While
Dline(W1, q9, W2, q9);
ge = (float)(0.008 * (W4 - W3));
n2 = 0;
s = 0;
while (s < W2)
{
Dline(s, q9, s, q9 + ge);
if (n2 >= ns)
{
Dline(s, q9, s, q9 + ge + ge);
n2 = 1;
showxy=moxy(s, q9);
myGraphics.drawString(String.valueOf(s),showxy[0] - swx, showxy[1] - swy-4);
}
else
{
n2 ++;
}
s += u;
}
//End While
s = 0;
n2 =0 ;
while (s > W1)
{
Dline(s, q9, s, q9 + ge);
if (n2 >= ns)
{
Dline(s, q9, s, q9 + ge + ge);
n2 = 1;
showxy=moxy(s, q9);
myGraphics.drawString(String.valueOf(s),showxy[0] - swx, showxy[1] - swy-4);
}
else
{
n2 ++;
}
s -= u;
}
//End While
}
}
// GraphicsCurve类与子定义样条曲线相同
五、曲线用Applet显示的数据来源问题
如果需要Applet显示曲线图形,就牵涉到如何提供数据的问题,最简单的办法,是在站点上放置一个有关数据的文本文件,由Applet直接调用这个文本文件,从而读出数据来。但这种办法缺乏必要的灵活性,也是不受推荐的。关键是要能调用数据库数据。当然,经过某些特殊的处理,Applet调用服务器端的数据库也不是不可能,不过这样一来将会带来很多安全隐患,在实用中价值不大。比较好的办法,是在服务器端设置一个动态网页,由这个网页调用数据库,而Applet则通过这个网页取得数据库的数据,由于动态网页的调用是在服务器中执行的,这种方法无论在安全性还是效率上效果都比较好,我们下面来具体讨论一下这种方法。
为了讨论简单,这种动态网页使用最简单的ASP,其它如JSP等的写法,和这个例子是相似的。
数据库
数据处理页面
jsp
asp等
Applet
首先做一个数据库:BookDB
两张表:
1)xytable
2)图表
做ASP页面:qt.asp
注意,这里把表名作为传入值使用。
<% tname=Request("tablename") %>
<%
Set cnnDB = Server.CreateObject("ADODB.Connection")
'建立Connection(资料库连结)对象,并设定由cnnDB对象变数引用
cnnDB.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & Server.MapPath("BookDB.mdb")
'设定连结对象的连结字串
cnnDB.Open '开启资料库
Set rstObj = Server.CreateObject ("ADODB.Recordset")
'建立Recordset(记录集)对象,并设定由rstObj对象变数引用
rstObj.Open "select * from " & tname , cnnDB '开启记录集对象
%>
<%
'利用DoLoop循环配合EOF属性将资料表中的记录列出
Do While Not rstObj.EOF
%>
<% = (rstObj("x")) %>
<% = vbCrLf %>
<% = (rstObj("y")) %>
<% = vbCrLf %>
<%
rstObj.Mov
第一节 Java 2D的增强功能
概述、AWT图形能力的不足、Java 2D API
第二节 图形绘制的基本方法
转换Graphics2D对象、Graphics 类特性、绘图的属性和基本编程方法
第三节 曲线问题的高级应用开发
直线问题深入研究、贝塞尔(Bezier)曲线、自定义样条曲线编程、
用户数据的曲线显示、曲线用Applet显示的数据来源问题
第四节 字符串的高级处理
TextLayout类、LineMetrics类
第五节 构造几何形状
2D几何形状的设计、构造型区域几何形状、变换、缓冲的图像
第六节 三维图形处理的设计技术
透视投影、透视图形的显示、隐蔽面消除问题
第七节 同环境交互
GraphicsEnvironment类、GraphicsDevice类、GraphicsConfiguration类
第一节 Java 2D的增强功能
一、概述:
由Sun公司与Adobe系统公司合作推出的Java 2D API,提供了一个功能强大而且非常灵活的二维图形框架。Java 2D API扩展了java.awt包中定义的Graphics类和Image类,提供了高性能的二维图形、图像和文字,同时又维持了对现有AWT应用的兼容。
二、AWT图形能力的不足:
在 AWT 的初始实现中,图形能力并不十分完善。因为开发 JDK 是打算将其作为平台中立的实现平台,所以其原始的功能被限制于“最少公共功能”上,所有被支持的操作系统上保证提供这些公共功能;
在 Java 2D 出现之前,对绘制能力、字体操作和图像控制的支持非常少。而对诸如用图案进行着色、形状操作以及图形变换之类的重要操作的支持则完全没有。
Java 2D 满足了跨平台实现中对这些功能以及其它功能的需求。
三、Java 2D API:
它是JFC (Java Fundation Classes)的一员,加强了传统AWT( Abstract Windowing Toolkit )的描绘功能。在 JDK1.2中已经支援 Java 2D 的使用。透过Java 2D API ,程序员可以轻松地描绘出任意的几何图形、运用不同的填色效果、对图形做旋转( rotate)、缩放( scale)、扭曲( shear)等。如图所示,程序员透过2D API所提供的功能,简单地利用不同类型的线或是填色效果绘出统计图,以区分出不同的资料。
它们是基于Graphics2D类的绘图功能,是对AWT中的Graphics类的进一步的扩展和增强。主要体现在:
1。对渲染质量的控制:消除锯齿以平滑绘制对象的边缘
2.裁剪、合成和透明度:它们允许使用任意形状来限定绘制操作的边界。它们还提供对图形进行分层以及控制透明度和不透明度的能力。
3.控制和填充简单及复杂的形状:这种功能提供了一个 Stroke 代理和一个 Paint 代理,前者定义用来绘制形状轮廓的笔(定义绘制的笔的宽度和样式),后者允许用纯色、渐变色和图案来填充形状。
4。图像处理和变换:Java 2D 同 Java 高级图像 API(Java Advanced Imaging API (JAI))协作,支持用大量图形格式处理复杂的图像。Java 2D 还为您提供了修改图像、形状和字体字符的变换能力。
5。特殊的填充方式,如梯度或者图案
6.高级字体处理和字符串格式化:允许象操作任何其它图形形状一样操作字体字符。除此以外,可以象文字处理程序一样,通过为 String 中的字符应用属性和样式信息来创建格式化文本。
java.awt.geom 包中的Areas类支援联集( union)、交集( intersection)、差集(subtraction )、Exclusive OR (XOR)等布尔运算。最後, AffineTransform 类别则提供图形物件做Scale(比例)、Shear(剪裁) 、Rotate(旋转)等座标上的转换。
第二节 图形绘制的基本方法
一、转换Graphics2D对象
绘制图形时,可以在Graphics对象或者Graphics2D对象上进行,它们都代表了需要绘图的区域,选择那个取决于是否要使用所增加的Java2D的图形功能。但要注意的是,所有的Java2D图形操作都必须在Graphics2D对象上调用。Graphics2D是Graphics的子类,同样包含在java.awt包中。
public void paintComponent(Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
}
或者
public void paint (Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
}
二、Graphics 类特性
Graphics 类支持几种确定图形环境状态的特性。以下列出了部分特性:
1)Color:当前绘制颜色,它属于 java.awt.Color 类型。所有的绘制、着色和纯文本输出都将以指定的颜色显示。
2)Font:当前字体,它属于 java.awt.Font 类型。它是将用于所有纯文本输出的字体。
3)Clip:java.awt.Shape 类型的对象,它充当用来定义几何形状的接口。该特性包含的形状定义了图形环境的区域,绘制将作用于该区域。通常情况下,这一形状与整个图形环境相同,但也并不一定如此。
4)ClipBounds:java.awt.Rectangle 对象,它表示将包围由 Clip 特性定义的 Shape 的最小矩形。它是只读特性。
5)FontMetrics:java.awt.FontMetrics 类型的只读特性。该对象含有关于图形环境中当前起作用的 Font 的信息。如同我们将看到的那样,获取此信息的这种机制已被 LineMetrics 类所取代
6)Paint Mode:该特性控制环境使用当前颜色的方式。如果调用了 setPaintMode() 方法,那么所有绘制操作都将使用当前颜色。如果调用了 setXORMode() 方法(该方法获取一个 Color 类型的参数),那么就用指定的颜色对像素做“XOR”操作。XOR 具有在重新绘制时恢复初始位模式的特性,因此它被用作橡皮擦除和动画操作。
三、绘图的属性和基本编程方法
1)颜色Color类:没有变化。
2)填充方式:
Paint(油漆桶) 接口有几个具体的实现,它们允许用纯色、渐变色或图案来填充形状。
1,纯色填充(Color类):对 java.awt.Color 类做了一些调整以实现 Paint,并且可以用于纯色填充。
2,渐变色来填充(梯度填充GradientPaint类):java.awt.GradientPaint 类允许用线性颜色渐变色来填充形状,线性颜色渐变色允许在两个指定的 Color 对象之间创建过渡。可以将渐变色设置成“周期性的”,这将导致渐变色图案重复出现。
3,图案填充(纹理TexturePaint类):提供了 java.awt.TexturePaint 类,它可以用由 BufferedImage 描述的图案填充形状
编程方法:
使用Graphics2D类中的setPaint()方法并使用Paint对象作为其参数,但由于任何可以作为填充的类如GradientPaint、TexturePaint和Color都实现了Paint接口(该接口注意定义了在Graphics2D下的颜色填充方式),因此可以将它们作为参数。如:
public void paintComponent(Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
GradientPaint pat=new GradientPaint(0f,0f,Color.white,100f,45f,Color.blue);
comp2D.setPaint(pat);
}
3)设置笔的形状:
Stroke 接口由 java.awt.BasicStroke 类实现。该类允许进行大量的选择以修改线的绘制细节。可以编程指定 BasicStroke 宽度,也可以指定对名为柱头和交点的路径上端点和交点的“装饰”。现在也可以绘制点划线了,只须设置 BasicStroke 的破折号属性即可。
在Graphics类中线条是一个点宽,而在Graphics2D中可以通过BasicStoke类中的setStroke()方法来设置。其构造函数是BasicStroke(float width, int cap, int join)
其中width指示线宽(缺省时为1.0)
cap指示线的末端(包头,在BasicStroke类中定义出三个static 类型的常量如CAP_BUTT没有包头( )、CAP_ROUND圆包头( )、CAP_SQUARE方包头( )的样式
join指示线段之间的拐角(在BasicStroke类中定义出三个static 类型的常量如JOIN_BEVEL( )、JOIN_MITER( )、 JOIN_ROUND( )样式。
4)编程方法:
public void paintComponent(Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
BasicStroke pen
=new BasicStroke(2.0f, BasicStroke .CAP_BUTT, BasicStroke .JOIN_ROUND);
comp2D.setStroke (pen);
}
代码示例:
float thick = 0.5f; //设置画刷的粗细为 0.5
BufferedImage bi = new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D)bi.getGraphics();
Stroke stroke = g.getStroke(); //得到当前的画刷
g.setStroke(new BasicStroke(thick, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
g.draw(new Line2D.Float(x1, y1, x2, y2)); 画线
g.setStroke( stroke ); //将画刷复原
5)创建要绘制的形状对象
在Java2D中进行绘图时,不是采用对应的方法来实现,而是为要实现某中形状创建出相应的形状对象。这可以通过使用java.awt.geom包中的类来定义所要创建的形状。如线条Line2D.Float类、距形Rectangle2D.Float或者Rectangle2D.Double类、椭圆Ellipes2D.Float、圆弧Arc2D.Float类等。
6)绘制对象:
1,可以使用Graphics2D类中的方法draw()用于绘制轮廓,而fill()方法用于填充。它们都以前面所创建的图形对象作为参数。
2,Java2D中的字符串的绘制仍然采用drawString()方法,但有drawString(String s, float x, float y)和drawString(String str, int x, int y)。
3,绘制轮廓:draw(Shape s)其中的Shape接口在Graphics2D中被定义
新的 Java 2D Shape 类都有“2D”后缀。这些新的形状使用浮点值(而不是整数)来描述其几何形状。
Polygon类(int[] xpoints, int[] ypoints, int npoints)
RectangularShape(抽象类,其子类有Arc2D, Ellipse2D, Rectangle2D, RoundRectangle2D), Rectangle(距形)
QuadCurve2D(二次贝塞尔样条曲线,贝塞尔曲线由两个端点以及一个或两个控制点指定。贝塞尔曲线创建了适合于大多数表示的曲线。)
CubicCurve2D(三次贝塞尔样条曲线)
Area(区域)
GeneralPath(由直线、二次样条曲线、三次样条曲线所构成)
Line2D
8)基本步骤
绘图的第一个步骤是产生 Graphics2D 对象。 然后设定所要的状态属性。例如你想要对一物件做渐层式的填色,可以设定属性 Paint为 GradientPaint。最後再调用Graphics2D所提供的方法fill或是draw,完成整个绘图的程序。
9)程序实例
例一:
这是一个最简单的例子,也可以认为是绘图的一个最简单的框架。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class Map extends JFrame
{ public Map()
{ super("Map");
setSize(350,350);
MapPane map=new MapPane();
getContentPane().add(map);
}
public static void main(String [] arg)
{ Map frame=new Map();
frame.show();
}
}
class MapPane extends JPanel
{ public void paintComponent(Graphics comp)
{ Graphics2D comp2D=(Graphics2D)comp;
comp2D.drawString("sbcd",200,200);
Line2D.Float line=new Line2D.Float(1.0f,2.0f,200.0f,200.0f);
comp2D.draw(line);
}
}
例二:
下面是在Graphics2D模式下的基本绘图框架。我们可以看到,利用:
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
通过该方法的设置,使图形去除锯齿状,可以得到多么细腻的图形。
样例:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class DrawDemo extends JFrame {
public DrawDemo(){
//设置窗口的大小、标题
this.setSize(new Dimension(600, 400));
//创建绘制各种形状的容器
ShapesPanel shapesPanel = new ShapesPanel();
//将该容器加入窗口
getContentPane().add(shapesPanel, BorderLayout.CENTER);
}
public static void main(String[] args) {
DrawDemo frame = new DrawDemo();
frame.setVisible(true);
//当窗口关闭时清空内存
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
//创建各种容器的类
class ShapesPanel extends JPanel {
final int maxCharHeight = 15;
final Color bg = Color.white; //声明背景颜色为灰色
final Color fg = Color.blue; //声明前景颜色为蓝色
public ShapesPanel() {
setBackground(bg); //设置背景颜色
setForeground(fg); //设置前景颜色
//创建组合边框
setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createRaisedBevelBorder(),
BorderFactory.createLoweredBevelBorder()));
}
public void paintComponent(Graphics g1) {
super.paintComponent(g1); //清空背景颜色
float thick = 0.5f; //设置画刷的粗细为 0.5
Graphics2D g = (Graphics2D)g1;
Stroke stroke = g.getStroke(); //得到当前的画刷
g.setStroke(new BasicStroke(thick, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
//通过该方法使图形去除锯齿状
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
String txt= "我的文章";
int style=2;//0普通1粗体2斜体3粗斜
g.setFont(new Font("宋体", 2, 15)); //15为字大小
//设置笔刷为黑色
g.setPaint(Color.black);
g.drawString(txt,200,150);
g.setPaint(Color.red);
g.draw(new Line2D.Float(0,0,200,150)); //画线
g.setPaint(Color.blue);
g.draw(new Rectangle2D.Float(200,150,100,100));
g.setStroke(stroke); //将画刷复原
}
}
例三:图形灵活的显示
在上面的例子中,是使用一个继承于JPanel的类,覆盖它的void paintComponent(Graphics g1)事件方法,实现绘图的,这样虽然方便,但显得灵活性不高。
实际上,通过JPanel对象直接赋值给Graphics2D对象,往往可以使程序具有很大的灵活性。程序可以这样来写。
JPanel contentPane= (JPanel) this.getContentPane();
public Graphics2D comp2D=(Graphics2D)contentPane .getGraphics();
样例:
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawDemo1 extends JFrame
{
public JPanel contentPane; //绘图窗口
public Graphics2D comp2D; //绘图对象
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
//构造函数
public DrawDemo1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件的初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(400, 300));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 235, 100, 31));
jButton1.setText("画线保留");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(150, 235, 100, 30));
jButton2.setText("画线删除");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
}
public static void main(String[] args) {
DrawDemo1 frame=new DrawDemo1();
frame.show();
frame.comp2D=(Graphics2D)frame.contentPane .getGraphics();
frame.comp2D.setBackground(Color.white);
frame.comp2D.clearRect(0,0,401,221);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
void jButton1_actionPerformed(ActionEvent e){
comp2D.setPaint(Color.red);
Line2D.Float line=new Line2D.Float(1.0f,2.0f,200.0f,220.0f);
comp2D.draw(line);
}
void jButton2_actionPerformed(ActionEvent e) {
comp2D.clearRect(0,0,401,221);
comp2D.setPaint(Color.blue);
Line2D.Float line=new Line2D.Float(1.0f,100.0f,300.0f,220.0f);
comp2D.draw(line);
}
}
例四:剪裁
图形处理问题中,剪裁由的时候是非常难处理的,所谓剪裁是指超过绘图取得内容不显示,看起来这是个简单问题,但由于所有的线条必须计算与边界的交点,而且边界有四个方向,这就使问题变得很复杂。java 2D很好的解决了这个问题,请看下面的例子。
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawDemo2 extends JFrame
{
public JPanel contentPane; //绘图窗口
public Graphics2D comp2D; //绘图对象
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
//构造函数
public DrawDemo2() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(400, 300));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 235, 100, 31));
jButton1.setText("画线保留");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(150, 235, 100, 30));
jButton2.setText("画线删除");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
}
public static void main(String[] args) {
DrawDemo2 frame=new DrawDemo2();
frame.show();
frame.comp2D=(Graphics2D)frame.contentPane .getGraphics();
frame.comp2D.setBackground(Color.white);
frame.comp2D.clearRect(0,0,401,221);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
void jButton1_actionPerformed(ActionEvent e){
comp2D.setPaint(Color.red);
Line2D.Float line=new Line2D.Float(1.0f,2.0f,200.0f,220.0f);
comp2D.draw(line);
}
void jButton2_actionPerformed(ActionEvent e) {
comp2D.clearRect(0,0,401,221);
//剪裁
comp2D.setClip(50,50,300,150);
comp2D.setPaint(Color.blue);
Line2D.Float line=new Line2D.Float(1.0f,100.0f,300.0f,220.0f);
comp2D.draw(line);
}
}
第三节 曲线问题的高级应用开发
在jdk尚未支援 2D图形之前,只可以画出直的、相同粗细的线条。现在可以通过2D API绘出不同粗细的线条及圆滑的曲线。在java.awt.geom包中提供了Line2D、 QuadCurve2D(二次贝塞尔曲线)及 CubicCurve2D(三次贝塞尔曲线)等相关的类,让程序员能够轻松地绘出想要的线条。
其实绘图的核心是画线,下面通过一些实例对一些问题进行深入的讨论。
一、直线问题深入研究
样例:
我们通过一个例子,深入的研究一下绘制直线和折线需要掌握哪些内容。
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawDemo1 extends JFrame
{
public JPanel contentPane; //绘图窗口
public Graphics2D comp2D; //绘图对象
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
JButton jButton3 = new JButton();
//构造函数
public DrawDemo1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(400, 300));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 235, 100, 31));
jButton1.setText("园头");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(150, 235, 100, 30));
jButton2.setText("方头");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
jButton3.setBounds(new Rectangle(270, 235, 100, 30));
jButton3.setText("封闭");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton3_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
jPanel1.add(jButton3, null);
}
public static void main(String[] args) {
DrawDemo1 frame=new DrawDemo1();
frame.show();
frame.comp2D=(Graphics2D)frame.contentPane .getGraphics();
frame.comp2D.setBackground(Color.white);
frame.comp2D.clearRect(0,0,401,221);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
int Xs1[]={10,60,120,200,260,340};
int Ys1[]={10,200,120,180,60,130};
void jButton1_actionPerformed(ActionEvent e){
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 10f;
//设置笔刷
//园头园连接
comp2D.setStroke(new BasicStroke(thick,
BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
comp2D.setPaint(Color.red);
//通过该方法使图形去除锯齿状
comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
comp2D.drawPolyline(Xs1,Ys1,Xs1.length);
}
void jButton2_actionPerformed(ActionEvent e) {
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 10f;
//设置笔刷
//方头方连接
comp2D.setStroke(new BasicStroke(thick,
BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE));
comp2D.setPaint(Color.blue);
//通过该方法使图形去除锯齿状
//comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
// RenderingHints.VALUE_ANTIALIAS_ON);
comp2D.drawPolyline(Xs1,Ys1,Xs1.length);
}
void jButton3_actionPerformed(ActionEvent e) {
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 1f;
//设置笔刷
//方头方连接
comp2D.setStroke(new BasicStroke(thick,
BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE));
comp2D.setPaint(Color.blue);
//通过该方法使图形去除锯齿状
//comp2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
// RenderingHints.VALUE_ANTIALIAS_ON);
//画封闭线
comp2D.drawPolygon(Xs1,Ys1,Xs1.length);
}
}
二、贝塞尔(Bezier)曲线
java 2D提供的QuadCurve2D(二次贝塞尔曲线)及 CubicCurve2D(三次贝塞尔曲线)等相关的类,可以很容易的画出贝赛尔曲线。
QuadCurve2D为三个数据,中间一个为控制点。
CubicCurve2D为四个数据,中间两个为控制点。
样例:
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawDemo1 extends JFrame
{
public JPanel contentPane; //绘图窗口
public Graphics2D comp2D; //绘图对象
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
//构造函数
public DrawDemo1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(400, 300));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 235, 150, 31));
jButton1.setText("二阶贝塞尔");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(200, 235, 150, 30));
jButton2.setText("三阶贝塞尔");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
}
public static void main(String[] args) {
DrawDemo1 frame=new DrawDemo1();
frame.show();
frame.comp2D=(Graphics2D)frame.contentPane .getGraphics();
frame.comp2D.setBackground(Color.white);
frame.comp2D.clearRect(0,0,401,221);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
void jButton1_actionPerformed(ActionEvent e){
double[] x1={50,180,300};
double[] y1={100,190,100};
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 1f;
comp2D.setPaint(Color.red);
QuadCurve2D.Double qc=new QuadCurve2D.Double();
qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2]);
comp2D.draw(qc);
comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]);
comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5);
comp2D.setPaint(Color.blue);
x1[1]=180;
y1[1]=30;
qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2]);
comp2D.draw(qc);
comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]);
comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5);
}
void jButton2_actionPerformed(ActionEvent e) {
double[] x1={50,80,200,300};
double[] y1={100,70,190,100};
comp2D.clearRect(0,0,401,221);
//笔宽度
float thick = 1f;
comp2D.setPaint(Color.red);
CubicCurve2D.Double qc=new CubicCurve2D.Double();
qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2],x1[3],y1[3]);
comp2D.draw(qc);
comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]);
comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5);
comp2D.drawLine((int)x1[2]-5,(int)y1[2],(int)x1[2]+5,(int)y1[2]);
comp2D.drawLine((int)x1[2],(int)y1[2]-5,(int)x1[2],(int)y1[2]+5);
float dash1[] = {10.0f};
//画虚线
BasicStroke dashed = new BasicStroke(1.0f,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER,
10.0f, dash1, 0.0f);
comp2D.setStroke(dashed);
comp2D.setPaint(Color.darkGray);
comp2D.drawLine((int)x1[1],(int)y1[1],(int)x1[2],(int)y1[2]);
//画实线
BasicStroke stroke = new BasicStroke(1.0f);
comp2D.setStroke(stroke);
comp2D.setPaint(Color.blue);
x1[1]=180;
y1[1]=70;
x1[2]=80;
y1[2]=190;
qc.setCurve(x1[0],y1[0],x1[1],y1[1],x1[2],y1[2],x1[3],y1[3]);
comp2D.draw(qc);
comp2D.drawLine((int)x1[1]-5,(int)y1[1],(int)x1[1]+5,(int)y1[1]);
comp2D.drawLine((int)x1[1],(int)y1[1]-5,(int)x1[1],(int)y1[1]+5);
comp2D.drawLine((int)x1[2]-5,(int)y1[2],(int)x1[2]+5,(int)y1[2]);
comp2D.drawLine((int)x1[2],(int)y1[2]-5,(int)x1[2],(int)y1[2]+5);
comp2D.setStroke(dashed);
comp2D.setPaint(Color.darkGray);
comp2D.drawLine((int)x1[1],(int)y1[1],(int)x1[2],(int)y1[2]);
comp2D.setStroke(stroke);
}
}
三、自定义样条曲线编程
当我们需要平滑多个数据样本点的时候,贝塞尔曲线就不能满足要求了,为此,可以采用最早由美国“波音”飞机制造公司提出来的样条曲线来完成,这种曲线所以称之为样条,是因为它模拟了造船业中的放样原理。
样条曲线的数学原理请参考计算机图形学,这里给出的是由java编写的三次样条曲线的例子。曲线平滑的原则是,必须通过所有的样本点,另外,不论有多少样本点,曲线的阶次最大为三次,所以是稳定的。
这里我们可以看出来,程序设计的生命是什么呢?数学!这是程序设计着的生命所在。语言只是一种规范或者是一个工具,要真正写出好的程序,没有深厚的数学功底,是万万不可能的。
样例:
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class DrawCurve extends JFrame
{
public JPanel contentPane; //绘图窗口
JPanel jPanel1 = new JPanel();//控件容器
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
JButton jButton3 = new JButton();
GraphicsCurve gracu;
//构造函数
public DrawCurve() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//控件初始化
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
this.setSize(new Dimension(500,400));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
jPanel1.setLayout(null);
jButton1.setBounds(new Rectangle(30, 310, 100, 31));
jButton1.setText("直线");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(150, 310, 100, 30));
jButton2.setText("样条曲线");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
jButton3.setBounds(new Rectangle(270, 310, 100, 30));
jButton3.setText("粗线条");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton3_actionPerformed(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
jPanel1.add(jButton1, null);
jPanel1.add(jButton2, null);
jPanel1.add(jButton3, null);
gracu=new GraphicsCurve();
}
public static void main(String[] args) {
DrawCurve frame=new DrawCurve();
frame.show();
frame.gracu.myGraphics=(Graphics2D)frame.contentPane .getGraphics();
frame.gracu.myGraphics.setBackground(Color.white);
frame.gracu.myGraphics.clearRect(0,0,500,300);
}
//Overridden so we can exit when window is closed
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
int Xs1[]={10,60,120,200,260,340};
int Ys1[]={10,200,120,180,60,130};
//画折线
void jButton1_actionPerformed(ActionEvent e){
gracu.myGraphics.setPaint(Color.blue);
gracu.myGraphics.drawPolyline(Xs1,Ys1,Xs1.length);
}
//画样条
void jButton2_actionPerformed(ActionEvent e) {
gracu.myGraphics.setPaint(Color.red);
gracu.DrawCurves(Xs1,Ys1);
}
//画粗线
void jButton3_actionPerformed(ActionEvent e) {
//笔宽度
float thick = 10f;
//设置笔刷
//方头园连接
//gracu.myGraphics.setStroke(new BasicStroke(thick, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND));
//园头园连接
gracu.myGraphics.setStroke(new BasicStroke(thick, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
gracu.myGraphics.setPaint(Color.blue);
//通过该方法使图形去除锯齿状
gracu.myGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
gracu.myGraphics.drawPolyline(Xs1,Ys1,Xs1.length);
}
}
class GraphicsCurve
{
//绘图对象
public Graphics2D myGraphics;
public GraphicsCurve()
{
}
public GraphicsCurve(Graphics2D graphics)
{
this.myGraphics=graphics;
}
//参数表
//x数组,y数组,笔刷
public void DrawCurves(int[] xa,int[] ya)
{
int[] x, y;
double[] a, b, c;
double[] px, py, qx, qy, tt;
double[] dx, dy;
int px1,py1,px2,py2;
x=xa;
y=ya;
px1=x[0];
py1=y[0];
int n=x.length;
a=new double[n];
b=new double[n];
c=new double[n];
px=new double[n];
py=new double[n];
qx=new double[n];
qy=new double[n];
tt=new double[n];
dx=new double[n];
dy=new double[n];
int i, t, es;
double bx3, bx4, by3, by4, cx, cy;
bx4 = 0;
by3 = 0;
es = 3;
px[0] = 1;
py[0] = 1;
px[n-1] = 1;
py[n-1] = 1;
if (n>1)
{
for (i = 1;i<n;i++)
tt[i] = Math.sqrt((x[i] - x[i - 1]) * (x[i] - x[i - 1]) + (y[i] - y[i - 1]) * (y[i] - y[i - 1]));
switch(n)
{
case 2:
break;
case 3:
for (i = 1;i<n - 1;i++)
{
a[i] = 2 * (tt[i] + tt[i + 1]);
b[i] = tt[i + 1];
c[i] = tt[i];
dx[i] = 3 * (tt[i] * (x[i + 1] - x[i]) / tt[i + 1] + tt[i + 1] * (x[i] - x[i - 1]) / tt[i]);
dy[i] = 3 * (tt[i] * (y[i + 1] - y[i]) / tt[i + 1] + tt[i + 1] * (y[i] - y[i - 1]) / tt[i]);
}
dx[1] = dx[1] - tt[2] * px[0];
dx[n - 2] = dx[n - 2] - tt[n - 2] * px[n-1];
dy[1] = dy[1] - tt[2] * py[0];
dy[n - 2] = dy[n - 2] - tt[n - 2] * py[n-1];
//注意,这是n=3的情况专有计算
px[1] = dx[1] / a[1];
py[1] = dy[1] / a[1];
break;
default:
for (i = 1;i<n - 1;i++)
{
a[i] = 2 * (tt[i] + tt[i + 1]);
b[i] = tt[i + 1];
c[i] = tt[i];
dx[i] = 3 * (tt[i] * (x[i + 1] - x[i]) / tt[i + 1] + tt[i + 1] * (x[i] - x[i - 1]) / tt[i]);
dy[i] = 3 * (tt[i] * (y[i + 1] - y[i]) / tt[i + 1] + tt[i + 1] * (y[i] - y[i - 1]) / tt[i]);
}
dx[1] = dx[1] - tt[2] * px[0];
dx[n - 2] = dx[n - 2] - tt[n - 2] * px[n-1];
dy[1] = dy[1] - tt[2] * py[0];
dy[n - 2] = dy[n - 2] - tt[n - 2] * py[n-1];
c[1] = c[1]/ a[1];
for (i = 2 ;i< n - 1;i++)
{
a[i] = a[i] - b[i] * c[i - 1];
c[i] = c[i] / a[i];
}
qx[1] = dx[1] / a[1];
qy[1] = dy[1] / a[1];
for (i = 2 ;i< n - 1;i++)
{
qx[i] = (dx[i] - b[i] * qx[i - 1]) / a[i];
qy[i] = (dy[i] - b[i] * qy[i - 1]) / a[i];
}
px[n - 2] = qx[n - 2];
py[n - 2] = qy[n - 2];
for (i = n - 3;i>=1;i--)
{
px[i] = qx[i] - c[i] * px[i + 1];
py[i] = qy[i] - c[i] * py[i + 1];
}
break;
}
for (i = 0 ;i< n - 1;i++)
{
bx3 = (3 * (x[i + 1] - x[i]) / tt[i + 1] - 2 * px[i] - px[i + 1]) / tt[i + 1];
bx4 = ((2 * (x[i] - x[i + 1]) / tt[i + 1] + px[i] + px[i + 1]) / tt[i + 1]) / tt[i + 1];
by3 = (3 * (y[i + 1] - y[i]) / tt[i + 1] - 2 * py[i] - py[i + 1]) / tt[i + 1];
by4 = ((2 * (y[i] - y[i + 1]) / tt[i + 1] + py[i] + py[i + 1]) / tt[i + 1]) / tt[i + 1];
t = 0;
while (t < tt[i + 1])
{
t = t + es;
cx = x[i] + (px[i] + (bx3 + bx4 * t) * t) * t;
cy = y[i] + (py[i] + (by3 + by4 * t) * t) * t;
px2 = (int)cx;
py2 = (int)cy;
myGraphics.drawLine(px1,py1,px2,py2);
px1 = px2;
py1 = py2;
}
}
}
}
}
四、用户数据的曲线显示
当需要用曲线表达数据的时候,我们虽然可以使用由厂家提供的“图表”组件,但更多的还是需要自己编写的,请仔细研究下面的程序,当对图表设计有更深入的理解。
下面的例子,我们构造一个专门处理用户数据的类,在这个类里,实现了用户坐标和屏幕坐标的转换,同时给出了一个自动绘制坐标的方法。我们也直接使用了上面我们讨论过的样条曲线的类实现数据平滑。例子中的数据可以来自于数据库或其它任何地方,仔细的研究这个例子,可以看出只要我们开动脑筋,把java强大的功能和我们对问题的理解结合在一起,就可以写出多么灵活多变的程序来呀!
样例:
package myDrawDemo;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.geom.*;
public class DataDrawDemo extends JFrame
{
public JPanel contentPane; //控件容器
JPanel jPanel1 = new JPanel();//绘图控件
JButton jButton1 = new JButton();
JButton jButton2 = new JButton();
JButton jButton3 = new JButton();
JButton jButton4 = new JButton();
JButton jButton5 = new JButton();
JButton jButton6 = new JButton();
JButton jButton7 = new JButton();
JButton jButton8 = new JButton();
JButton jButton9 = new JButton();
JButton jButton10 = new JButton();
JTextField jText1=new JTextField();
JTextField jText2=new JTextField();
boolean kcu=true;
//用户坐标转换对象
myGraphicsData mp=new myGraphicsData();
//曲线转换对象
GraphicsCurve gracu=new GraphicsCurve();
//窗口范围
double wx1,wx2,wy1,wy2;
//构造函数
public DataDrawDemo() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
//初始化代码
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(null);
this.setSize(new Dimension(650, 500));
this.setTitle("Frame Title");
//contentPane.setSize(400,240);
//jPanel1.setLayout(null);
jPanel1.setBounds(0,90,650,420);
jButton1.setBounds(new Rectangle(30, 20, 80, 25));
jButton1.setText("开始");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton1_actionPerformed(e);
}
});
jButton2.setBounds(new Rectangle(120, 20, 80, 25));
jButton2.setText("左移");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton2_actionPerformed(e);
}
});
jButton3.setBounds(new Rectangle(210, 20, 80, 25));
jButton3.setText("右移");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton3_actionPerformed(e);
}
});
jButton4.setBounds(new Rectangle(300, 20, 80, 25));
jButton4.setText("上移");
jButton4.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton4_actionPerformed(e);
}
});
jButton5.setBounds(new Rectangle(390, 20, 80, 25));
jButton5.setText("下移");
jButton5.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton5_actionPerformed(e);
}
});
jButton6.setBounds(new Rectangle(120, 50, 80, 25));
jButton6.setText("X扩");
jButton6.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton6_actionPerformed(e);
}
});
jButton7.setBounds(new Rectangle(210, 50, 80, 25));
jButton7.setText("X缩");
jButton7.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton7_actionPerformed(e);
}
});
jButton8.setBounds(new Rectangle(300, 50, 80, 25));
jButton8.setText("Y扩");
jButton8.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton8_actionPerformed(e);
}
});
jButton9.setBounds(new Rectangle(390, 50, 80, 25));
jButton9.setText("Y缩");
jButton9.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton9_actionPerformed(e);
}
});
//样条控制
jButton10.setBounds(new Rectangle(30, 50, 80, 25));
jButton10.setText("样条");
jButton10.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jButton10_actionPerformed(e);
}
});
jText1.setBounds(new Rectangle(490, 20, 120, 20));
jText1.setText("");
jText2.setBounds(new Rectangle(490, 50, 120, 20));
jText2.setText("");
//鼠标按下侦听器
jPanel1.addMouseListener(new java.awt.event.MouseAdapter(){
public void mousePressed(MouseEvent e) {
JPanel_mousePressed(e);
}
});
//鼠标拖动侦听器
jPanel1.addMouseMotionListener(new java.awt.event.MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
JPanel_mouseDragged(e);
}
});
//鼠标释放侦听器
jPanel1.addMouseListener(new java.awt.event.MouseAdapter(){
public void mouseReleased(MouseEvent e) {
JPanel_mouseReleased(e);
}
});
contentPane.add(jPanel1, BorderLayout.CENTER);
contentPane.add(jButton1, null);
contentPane.add(jButton2, null);
contentPane.add(jButton3, null);
contentPane.add(jButton4, null);
contentPane.add(jButton5, null);
contentPane.add(jButton6, null);
contentPane.add(jButton7, null);
contentPane.add(jButton8, null);
contentPane.add(jButton9, null);
contentPane.add(jButton10, null);
contentPane.add(jText1, null);
contentPane.add(jText2, null);
}
public static void main(String[] args) {
DataDrawDemo frame=new DataDrawDemo();
frame.show();
frame.gracu.myGraphics=(Graphics2D)frame.jPanel1.getGraphics();
frame.mp.myGraphics=(Graphics2D)frame.jPanel1.getGraphics();
frame.mp.myGraphics.setBackground(Color.white);
frame.mp.myGraphics.clearRect(0,0,650,375);
}
//第一组数据
double[] Xs1=new double[]{-2,2,4,6,8,10,12,14};
double[] Ys1=new double[]{-4,10,3,14,4,10,6,7};
//第二组数据
double[] Xs2=new double[]{-1,2,4,6,8,10,12,14,16};
double[] Ys2=new double[]{1,5,7,1,13,11,4,10,8};
//这是一个画曲线的程序
void DwData()
{
//剪裁,可以试试没有剪裁是什么表现?
mp.myGraphics.clipRect(10,10,621,351);
//由于是用两个对象绘图,所以应该分别剪切
gracu.myGraphics.clipRect(10,10,621,351);
//清除绘图空间
mp.myGraphics.clearRect(0,0,650,375);
//用户坐标和屏幕坐标转换
mp.truemode(10,630,10,360,wx1,wx2,wy1,wy2);
//设置颜色
mp.myGraphics.setPaint(Color.darkGray);
//画边框
mp.myGraphics.drawRect(10,10,620,350);
mp.myGraphics.setFont(new Font("宋体", 0, 10)); //9为字大小
//画坐标
mp.axis(2,2,2,2);
//画红线
int[] x=new int[Xs1.length];
int[] y=new int[Ys1.length];
int[] myxy;
//统一实现坐标转换
for (int i=0;i<x.length;i++)
{
myxy=mp.moxy(Xs1[i],Ys1[i]);
x[i]=myxy[0];
y[i]=myxy[1];
}
if (kcu)
{
mp.myGraphics.setPaint(Color.red);
mp.myGraphics.drawPolyline(x,y,x.length);
}
else
{
gracu.myGraphics.setPaint(Color.red);
gracu.DrawCurves(x,y);
}
//画蓝线
x=new int[Xs2.length];
y=new int[Ys2.length];
for (int i=0;i<x.length;i++)
{
myxy=mp.moxy(Xs2[i],Ys2[i]);
x[i]=myxy[0];
y[i]=myxy[1];
}
if (kcu)
{
mp.myGraphics.setPaint(Color.blue);
mp.myGraphics.drawPolyline(x,y,x.length);
}
else
{
gracu.myGraphics.setPaint(Color.blue);
gracu.DrawCurves(x,y);
}
}
//退出窗口事件
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
//鼠标按下事件
void JPanel_mousePressed(MouseEvent e)
{
double[] zs=mp.ScrtoCon(e.getX(),e.getY());
jText1.setText(String.valueOf((float)zs[0]));
jText2.setText(String.valueOf((float)zs[1]));
}
//鼠标释放事件
void JPanel_mouseReleased(MouseEvent e)
{
double[] zs=mp.ScrtoCon(e.getX(),e.getY());
jText1.setText("");
jText2.setText("");
//画红线
mp.myGraphics.setPaint(Color.darkGray);
mp.myGraphics.drawLine(e.getX()-3,e.getY(),e.getX()+3,e.getY());
mp.myGraphics.drawLine(e.getX(),e.getY()-3,e.getX(),e.getY()+3);
mp.myGraphics.drawString(String.valueOf((float)zs[0]),e.getX()+10,e.getY());
mp.myGraphics.drawString(String.valueOf((float)zs[1]),e.getX()+10,e.getY()+12);
}
//鼠标拖动事件
void JPanel_mouseDragged(MouseEvent e)
{
double[] zs=mp.ScrtoCon(e.getX(),e.getY());
jText1.setText(String.valueOf((float)zs[0]));
jText2.setText(String.valueOf((float)zs[1]));
}
//开始
void jButton1_actionPerformed(ActionEvent e){
wx1=1000000;
wy1=1000000;
wx2=-1000000;
wy2=-1000000;
//试验中数据来自一个数组,实际中可来自任何地方
//设置初始范围
for (int i=0;i<Xs1.length;i++)
{
if (Xs1[i]< wx1)
wx1=Xs1[i];
if (Xs1[i]> wx2)
wx2=Xs1[i];
if (Ys1[i]< wy1)
wy1=Ys1[i];
if (Ys1[i]> wy2)
wy2=Ys1[i];
}
for (int i=0;i<Xs2.length;i++)
{
if (Xs2[i]< wx1)
wx1=Xs2[i];
if (Xs2[i]> wx2)
wx2=Xs2[i];
if (Ys2[i]< wy1)
wy1=Ys2[i];
if (Ys2[i]> wy2)
wy2=Ys2[i];
}
DwData();
}
//左移
void jButton2_actionPerformed(ActionEvent e) {
wx1-=1;
wx2-=1;
DwData();
}
//右移
void jButton3_actionPerformed(ActionEvent e) {
wx1+=1;
wx2+=1;
DwData();
}
//上移
void jButton4_actionPerformed(ActionEvent e) {
wy1-=1;
wy2-=1;
DwData();
}
//下移
void jButton5_actionPerformed(ActionEvent e) {
wy1+=1;
wy2+=1;
DwData();
}
//X扩
void jButton6_actionPerformed(ActionEvent e) {
wx1-=1;
wx2+=1;
DwData();
}
//X缩
void jButton7_actionPerformed(ActionEvent e) {
wx1+=1;
wx2-=1;
DwData();
}
//Y扩
void jButton8_actionPerformed(ActionEvent e) {
wy1-=1;
wy2+=1;
DwData();
}
//Y缩
void jButton9_actionPerformed(ActionEvent e) {
wy1+=1;
wy2-=1;
DwData();
}
//样条控制
void jButton10_actionPerformed(ActionEvent e) {
if (kcu)
{
jButton10.setText("直线");
kcu=false;
}
else
{
jButton10.setText("样条");
kcu=true;
}
DwData();
}
}
//图形处理类
class myGraphicsData
{
//屏幕坐标
private int X11, Y11, X12, Y12; //x1,y1,x2,y2
//用户坐标
private double W1, W2, W3, W4; //x1,x2,y1,y2
//绘图对象
public Graphics2D myGraphics;
double Ax8, Ay8;
//用户窗口与屏幕窗口的转换
//x1,x2,,y1,y2为屏幕坐标
//wx1,wx2,wy1,wy2为用户坐标
public void truemode(int x1, int x2, int y1,int y2, double wx1, double wx2, double wy1, double wy2)
{
X11 = x1 ; X12 = x2;
Y11 = y1 ; Y12 = y2;
W1 = wx1 ; W2 = wx2;
W3 = wy1 ; W4 = wy2;
Ax8 = (X12 - X11) / (wx2 - wx1);
Ay8 = (Y12 - Y11) / (wy2 - wy1);
}
//把用户坐标转为屏幕坐标
public int[] moxy(double Xa, double Ya)
{
int[] myout=new int[2];
myout[0] = (int)(Ax8 * (Xa - W1) + X11);
myout[1] = (int)(Y12 - Ay8 * (Ya - W3));
return myout;
}
//把屏幕坐标转为用户坐标
public double[] ScrtoCon(int X6, int Y6)
{
double[] myout=new double[2];
myout[0] = (X6 - X11) / Ax8 + W1;
myout[1] = (Y12 - Y6) / Ay8 + W3;
return myout;
}
//画线
public void Dline(double xa, double ya, double xb, double yb)
{
try
{
int x6, y6, x7, y7;
x6 = (int)(Ax8 * (xa - W1) + X11);
y6 = (int)(Y12 - Ay8 * (ya - W3));
x7 = (int)(Ax8 * (xb - W1) + X11);
y7 = (int)(Y12 - Ay8 * (yb - W3));
myGraphics.drawLine(x6, y6, x7, y7);
}
catch(Exception e){}
}
//画坐标U,V为 X,Y轴单位,ns,nt为 x,y轴写字间隔
public void axis(double u, double v, int ns, int nt)
{
double p9, q9, s;
int n2, swx,swy;
int xk=0;
int yk=0;
double ge;
int[] showxy=new int[2];
swx = 0;
swy=4;
ge = (double)0.008 * (W2 - W1);
p9 = W1;
q9 = (double)(W3 + (W4 - W3) * 0.05);
if ((W1 < 0) && (W2 > 0)) p9 = 0;
if ((W3 < 0) && (W4 > 0)) q9 = 0;
Dline(p9, W3, p9, W4);
n2 = 0;
s = 0;
while (s < W4)
{
Dline(p9, s, p9 + ge, s);
if (n2 >= nt)
{
Dline(p9, s, p9 + ge + ge, s);
n2 = 1;
showxy=moxy(p9 + ge + ge,s);
myGraphics.drawString(String.valueOf(s),showxy[0] - swx+4, showxy[1] - swy+4);
}
else
{
n2++;
}
s += v;
}
//End While
s = 0;
n2 = 0;
while (s > W3)
{
Dline(p9, s, p9 + ge, s);
if (n2 >= nt)
{
Dline(p9, s, p9 + ge + ge, s);
n2 = 1;
showxy=moxy(p9 + ge + ge, s);
myGraphics.drawString(String.valueOf(s),showxy[0] - swx+4, showxy[1] - swy+4);
}
else
{
n2 ++;
}
s -= v;
}
//End While
Dline(W1, q9, W2, q9);
ge = (float)(0.008 * (W4 - W3));
n2 = 0;
s = 0;
while (s < W2)
{
Dline(s, q9, s, q9 + ge);
if (n2 >= ns)
{
Dline(s, q9, s, q9 + ge + ge);
n2 = 1;
showxy=moxy(s, q9);
myGraphics.drawString(String.valueOf(s),showxy[0] - swx, showxy[1] - swy-4);
}
else
{
n2 ++;
}
s += u;
}
//End While
s = 0;
n2 =0 ;
while (s > W1)
{
Dline(s, q9, s, q9 + ge);
if (n2 >= ns)
{
Dline(s, q9, s, q9 + ge + ge);
n2 = 1;
showxy=moxy(s, q9);
myGraphics.drawString(String.valueOf(s),showxy[0] - swx, showxy[1] - swy-4);
}
else
{
n2 ++;
}
s -= u;
}
//End While
}
}
// GraphicsCurve类与子定义样条曲线相同
五、曲线用Applet显示的数据来源问题
如果需要Applet显示曲线图形,就牵涉到如何提供数据的问题,最简单的办法,是在站点上放置一个有关数据的文本文件,由Applet直接调用这个文本文件,从而读出数据来。但这种办法缺乏必要的灵活性,也是不受推荐的。关键是要能调用数据库数据。当然,经过某些特殊的处理,Applet调用服务器端的数据库也不是不可能,不过这样一来将会带来很多安全隐患,在实用中价值不大。比较好的办法,是在服务器端设置一个动态网页,由这个网页调用数据库,而Applet则通过这个网页取得数据库的数据,由于动态网页的调用是在服务器中执行的,这种方法无论在安全性还是效率上效果都比较好,我们下面来具体讨论一下这种方法。
为了讨论简单,这种动态网页使用最简单的ASP,其它如JSP等的写法,和这个例子是相似的。
数据库
数据处理页面
jsp
asp等
Applet
首先做一个数据库:BookDB
两张表:
1)xytable
2)图表
做ASP页面:qt.asp
注意,这里把表名作为传入值使用。
<% tname=Request("tablename") %>
<%
Set cnnDB = Server.CreateObject("ADODB.Connection")
'建立Connection(资料库连结)对象,并设定由cnnDB对象变数引用
cnnDB.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & Server.MapPath("BookDB.mdb")
'设定连结对象的连结字串
cnnDB.Open '开启资料库
Set rstObj = Server.CreateObject ("ADODB.Recordset")
'建立Recordset(记录集)对象,并设定由rstObj对象变数引用
rstObj.Open "select * from " & tname , cnnDB '开启记录集对象
%>
<%
'利用DoLoop循环配合EOF属性将资料表中的记录列出
Do While Not rstObj.EOF
%>
<% = (rstObj("x")) %>
<% = vbCrLf %>
<% = (rstObj("y")) %>
<% = vbCrLf %>
<%
rstObj.Mov
发表评论
-
Saving JFreeChart as SVG vector images using Batik
2008-07-28 15:52 1751JFreeChart is a free Java class ... -
JfreeChart的使用
2008-07-28 13:42 1327先从网上找点介绍。 一、简介 WW 的发展使得基于 ... -
JPanel绘制的东西如何保存成图像
2008-07-28 10:40 3281[/color][color=darkred][color=d ... -
使用Java Servlet动态生成图片
2008-07-24 16:03 1968在Web应用中,经常需要动态生成图片,比如实时股市行情,各种统 ... -
Java解析JSON
2008-06-10 21:00 27780jsp文件 var people = { "pr ... -
Grizzly和comet介绍(译)
2008-06-10 20:59 2875感觉不是什么新技术,也不是什么新创意,可是一旦用起来可能对技术 ... -
DWR2.1 API Doc
2008-05-19 15:50 1236http://getahead.org/dwr-javadoc ... -
servlet/jsp 获取绝对路径和相对路径
2008-05-14 11:03 3136根目录所对应的绝对路径:request.getServletP ... -
load-on-startup作用
2008-05-14 10:53 2340load-on-startup 元素在web应 ... -
使用异步Servlet扩展AJAX应用程序
2008-05-12 23:30 1312作为Web应用程序模型的A ... -
关于Java的java.library.path
2008-04-30 00:37 16875java可以通过System.getProperty获得系统变 ... -
【转】JNI
2008-04-29 23:50 1363JNI是Java Native Interface的缩写。从J ... -
jni.h所在位置
2008-04-29 23:19 5180在%java_home%\include\下 -
servlet重定向
2008-04-23 14:20 9899在servlet/JSP编程中,服务器端重定向可以通过下面两个 ... -
CVS与Eclipse使用摘要
2008-04-16 17:08 22031. 在administrator下安装CVSNT版本,重启计 ... -
ServletContext和ServletConfig深度分析
2008-04-09 14:00 1345对于web容器来说,ServletContext接口定义了一个 ... -
JSP文件在浏览器中显示出现乱码的解决方法
2008-04-02 10:29 1759采用utf-8编码,在jsp文件中,加入下面2句即可: < ... -
GlassFish
2008-03-20 18:32 1529GlassFish社团正在开发一个免费,开源的Java EE5 ... -
jndi与jdbc的区别
2008-03-20 15:59 2773jndi给所有的命名目录服务提供统一的API前端,jdbc给所 ... -
Tomcat5.5下配置JNDI JDBC数据源
2008-03-20 15:57 14761 安装JDBC驱动 通常,将JDBC驱动安 ...
相关推荐
【Java 2D高级绘图技术】是Java编程中用于创建高质量二维图形的API,它弥补了早期AWT图形库的不足。Java 2D API是在JFC(Java Foundation Classes)框架下,从JDK 1.2版本开始引入的,旨在提供更强大的图形处理能力...
Java 2D 高级绘图是Java平台上用于创建高质量二维图形和图像处理的重要部分。这一技术极大地扩展了Java Abstract Windowing Toolkit (AWT)的基础绘图能力,为开发者提供了更多的灵活性和性能优化。 首先,Java 2D ...
Java 2D 高级绘图是Java平台上用于创建高质量二维图形、图像和文本的框架。这个主题涵盖了许多关键知识点,下面将详细阐述。 首先,Java 2D API 是Sun公司与Adobe系统公司合作开发的,它扩展了AWT(Abstract ...
以下是对Java 2D高级绘图技术的详细解释: 1. **Graphics类**:Graphics类位于java.awt包中,它是所有图形绘制的基础。它表示一个组件的绘图环境,包含了绘制图形所需的全部方法。通过Graphics对象,我们可以设置...
`java2d_jfcDemo`可能是一个示例,展示了如何在Swing应用中使用Java 2D进行绘图。 10. **文档**: 压缩包中的文档可能包含关于如何使用这些资源的指南、API参考或教程,对于学习和理解Java 2D编程至关重要。 解压后...
Java 2D是Java平台中的一个图形处理框架,它提供了丰富的功能来创建和操作复杂的二维图形和图像...在给定的压缩包文件"Java2D"中,可能包含了相关的示例代码、教程或者项目,供学习者深入理解和实践Java 2D的相关技术。
这个"java2d绘图实例"显然是一份详细的教学资料,旨在帮助开发者理解和掌握如何在Java环境中创建复杂的图形。Java 2D API扩展了Java AWT(Abstract Window Toolkit)库,使得开发者能够进行高质量、高性能的图形绘制...
Java 2D API 是 Java 平台上的一个高级图形处理库,它为开发人员提供了绘制复杂图形的能力,包括线条、形状、图像等。通过 Java 2D,开发者可以轻松创建复杂的用户界面组件和动画效果。 ##### 1.1 Java 2D 的核心...
通过Java2D Demo的学习,开发者不仅可以掌握Java2D的基本用法,还能探索高级的图形技巧,为开发出富有创意的2D图形应用打下坚实的基础。无论你是游戏开发者、数据可视化工程师还是界面设计师,Java2D都提供了一套...
Java 2D是Java平台的一部分,它提供了高级图形功能,使得开发者能够轻松地创建高质量的二维图形应用程序。通过本指南,您将学习到如何使用Java 2D来绘制复杂的图形、处理图像以及实现各种图形效果。 #### 一、Java ...
5. **`Graphics2D`**:Java2D的主要绘图类,提供了绘制图形的基本方法。 #### 三、具体实现 ##### 1. 创建图形对象 首先,我们定义了几种不同类型的图形对象: - `QuadCurve2D curve_1` 和 `QuadCurve2D curve_2...
Java2D提供了更高级的图像处理功能,如滤镜效果、碰撞检测、图形重叠等。 #### Graphics2D核心属性 - **填充属性(paint)**:决定了图形的填充颜色和填充模式。可以通过`setPaint()`方法设置。 - **笔划属性...
【JAVA2D 相关教程】 JAVA2D 是Java 2平台的核心组件,它极大地扩展了Java应用程序的图形处理能力。本教程旨在介绍Java 2D API的基础知识,帮助初学者掌握如何利用这个强大的工具集创建专业级别的图形应用。 1. **...
### Java2D绘图技术详解 #### 一、Java2D概述与AWT图形能力的不足 ##### 1. Java2D的推出背景与特点 Java2D API是由Sun Microsystems与Adobe Systems合作推出的,旨在为Java平台提供一个强大的二维图形框架。它是...
本教程的标题"java2D超经典例程(包含2D各个方面,附源码)"暗示了这是一份全面的Java 2D编程教程,覆盖了从基础到高级的各种主题,并且提供了完整的源代码示例,对于学习和实践Java 2D技术非常有帮助。 在Java 2D...
### Java 2D绘图技术详解 #### 一、引言 随着计算机图形学的发展,图形用户界面(GUI)的设计变得越来越重要。Java作为一种广泛使用的编程语言,在图形处理方面也提供了丰富的API支持。其中,Java 2D API是Java...
1. `Graphics2D` 类:这是Java 2D绘图的核心类,继承自`Graphics`,扩展了更多的二维图形操作功能。通过`Graphics2D`对象,你可以绘制各种几何形状(如矩形、椭圆、线条)、路径、文本和图像。 2. `Shape` 接口:...
Java2D是Java平台标准版(Java SE)的一部分,为AWT(Abstract Window Toolkit)和Swing提供高级图形功能。 Java2D的基础包括以下几个关键知识点: 1. **主要类和方法**: - `javax.swing.JFrame`:这是Swing库中...
- **Graphics2D**:是Java 2D API的核心接口,扩展了Graphics接口,增加了对矢量图形、文本渲染和高级渲染操作的支持。 - **Shape**:表示几何形状,如矩形、椭圆、线条等,可以通过`Rectangle2D`、`Ellipse2D`、`...