5、窗体绘图
5、1 简单的窗体绘图
在窗体上进行绘图有两种方式,一种是通过改写paint方法实现自定义绘图,paint方法中提供了可以在屏幕上绘图的图形设备接口类对象,另外一种方式是通过直接获取当前屏幕的图形设备接口类来进行。另外,也可以给窗体添加带有绘图的面板实现窗体绘图。
5、1、1 改写paint方法的绘图方式
paint方法在接受系统调用时,会获取当前屏幕的图形设备接口类对象的引用,以实现绘图,如:
import java.awt.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(200,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
}
public void paint(Graphics g)
{
setBackground(Color.yellow);
g.setColor(Color.red);
g.drawLine(0,0,100,100);
}
}
说明:
1)在Java窗体程序中,一般将水平轴称为X轴,垂直轴为Y轴,并且以屏幕左上角为(0,0)点,座标值是从左到右逐渐增大x值、从上到下逐渐增大y值
2)setBackground设置背景色,Graphics图形设备接口类对象的setColor方法设置前景色,drawLine为绘制直线,它的四个参数分别为起始点的x和y值和终止点的x和y值
5、1、2 直接获取当前屏幕图形设备接口类的绘图方式
这主要是利用getGraphics()方法来获取的,这种方式将可以更加灵活的实现绘图,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame implements ActionListener
{
Button b=new Button("Draw Line");
public MyFrame(String title)
{
super(title);
getContentPane().setLayout(new FlowLayout());
getContentPane().add(b);
b.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
Graphics g=getGraphics();
g.drawLine(0,0,100,100);
}
}
5、1、3 利用面板实现的窗体绘图方式
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(200,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
setBackground(Color.yellow);
g.setColor(Color.red);
g.drawLine(0,0,100,100);
}
}
下面的程序实现了用户控制下的绘图功能,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel implements ActionListener
{
Button b=new Button("Draw Line");
public MyPanel()
{
add(b);
b.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
Graphics g=getGraphics();
g.drawLine(0,0,100,100);
}
}
5、2 常用的绘图方法
Java可以利用当前屏幕的图形设备接口类对象来绘图,同时也可以将其转化成2D图形对象来进行更加高级的绘图。
5、2、1 绘制直线
使用drawLine方法,它的四个参数分别为起始点的x和y值和终止点的x和y值。
下面的程序为在整个窗体上绘制由直线组成的网格,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(200,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=0;i<=this.getSize().width;i+=10)
{
g.drawLine(i,0,i,this.getSize().height);
}
for(int i=0;i<=this.getSize().height;i+=10)
{
g.drawLine(0,i,this.getSize().width,i);
}
}
}
5、2、2 绘制矩形
使用drawRect方法可以绘制空心矩形边框,使用fillRect方法可以绘制实心矩形。它们的四个参数分别为左上角点的x和y值和整个矩形的长值(x轴值)和宽值(y轴值),如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(200,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=0;i<=300;i+=50)
{
g.drawLine(i,0,i,300);
g.drawLine(0,i,300,i);
}
g.setColor(Color.green);
g.drawRect(50,50,100,100);
g.setColor(Color.red);
g.fillRect(100,100,50,50);
}
}
5、2、3 绘制圆形
使用drawOval方法可以绘制空心圆形边框,使用fillOval方法可以绘制实心圆形。它们的四个参数分别为圆形外接矩形左上角点的x和y值和整个圆形外接矩形的长值(x轴值)和宽值(y轴值),如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=0;i<=300;i+=50)
{
g.drawLine(i,0,i,300);
g.drawLine(0,i,300,i);
}
g.setColor(new Color(255,255,0));
g.drawOval(50,50,100,100);
g.fillOval(150,150,100,100);
g.setColor(new Color(0,0,255));
g.fillOval(150,50,50,100);
}
}
5、2、4 绘制圆弧和扇形
使用drawArc方法可以绘制圆弧,使用fillArc方法可以绘制扇形。它们的六个参数的前四个分别为圆弧或者扇形所在圆的外接矩形左上角点的x和y值和整个圆形外接矩形的长值(x轴值)和宽值(y轴值),后两个参数为起始角度和跨过的角度,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=0;i<=300;i+=100)
{
g.drawLine(i,0,i,300);
g.drawLine(0,i,300,i);
}
g.setColor(Color.red);
g.drawArc(100,100,100,100,45,90);
g.fillArc(200,200,100,100,225,90);
}
}
一个利用扇形和圆形画出的太极图:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.white);
Rectangle c=getBounds();
int width=c.width*2/3;
int left=c.width*1/6;
int height=c.height*2/3;
int top=c.height*1/6;
g.setColor(Color.black);
g.fillArc(left,top,width,height,90,180);
g.setColor(Color.yellow);
g.fillArc(left,top,width,height,270,180);
g.setColor(Color.black);
g.fillArc(left*2,top*3,width/2,height/2,270,180);
g.setColor(Color.yellow);
g.fillOval(left*2,top,width/2,height/2);
g.setColor(Color.yellow);
g.fillOval(left*2+left*3/4,top*3+top*3/4,width/8,height/8);
g.setColor(Color.red);
g.fillOval(left*2+left*3/4,top+top*3/4,width/8,height/8);
}
}
5、2、5 绘制图形
使用drawImage方法可以绘制图形。它的四个参数分别为所绘制的图形对象、图形在屏幕上的左上角座标、所在容器类对象,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
Image m;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
m=new ImageIcon(getClass().getResource("pic.gif")).getImage();
g.drawImage(m,10,10,this);
}
}
说明:
装载图形成对象的方法也可以使用另外一个,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
Image m;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
m=Toolkit.getDefaultToolkit().getImage("pic.gif");
g.drawImage(m,10,10,this);
}
}
5、2、6 绘制文字
使用drawString方法可以绘制文字。它的三个参数分别为所绘制的字符串对象、字符串在屏幕上的左上角座标,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(200,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawString("Hello!",100,50);
}
}
也可以在显示文字时使用字体,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(200,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Font f=new Font("TimesRoman",Font.BOLD,72);
g.setFont(f);
g.drawString("Hello!",10,100);
}
}
5、3 动画的显示
5、3、1 一般的做法
简单的做法就是利用循环,周期性的向屏幕输出图形或者移动组件,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel implements ActionListener
{
int i=0;
Button b=new Button("Start!");
Canvas c=new Canvas();
public MyPanel()
{
c.setSize(50,50);
c.setBackground(Color.red);
add(b);
add(c);
b.addActionListener(this);
}
public void paint(Graphics g)
{
c.setLocation(i,100);
}
public void actionPerformed(ActionEvent e)
{
for(;i<150;i++)
{
for(int y=0;y<999999;y++);
repaint();
}
}
}
说明:
此程序的实际效果很差,只是在过了一段时间后直接显示结果的模样,而并没有显示中间的过程。如果想显示全部过程,应该使用多线程的处理方式,如:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel implements ActionListener,Runnable
{
int i=0;
Button b=new Button("Start!");
Canvas c=new Canvas();
Thread th=new Thread(this);
public MyPanel()
{
c.setSize(50,50);
c.setBackground(Color.red);
add(b);
add(c);
b.addActionListener(this);
}
public void run()
{
i=0;
for(;i<150;i++)
{
repaint();
try
{
th.sleep(50);//毫秒
}
catch(InterruptedException e)
{}
}
}
public void paint(Graphics g)
{
c.setLocation(i,100);
}
public void actionPerformed(ActionEvent e)
{
th.start();
}
}
说明:
多线程的程序可以有效的通过运行在不同线程中的代码,在程序计算和屏幕绘图两个方面进行执行时间的平衡分配,从而实现动画效果。
一个可以由用户控制的动画程序:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel implements ActionListener,Runnable
{
int i=0;
boolean flag=false;//新的stop方法
Button b1=new Button("Start!");
Button b2=new Button("Stop!");
Canvas c=new Canvas();
Thread th=new Thread(this);
public MyPanel()
{
c.setSize(50,50);
c.setBackground(Color.red);
add(b1);
add(b2);
add(c);
b1.addActionListener(this);
b2.addActionListener(this);
th.start();
}
public void run()
{
while(true)
{
while(flag)
{
repaint();
i++;
try
{
th.sleep(50);//毫秒
}
catch(InterruptedException e)
{}
}
}
}
public void paint(Graphics g)
{
c.setLocation(i,100);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==b1)
{
flag=true;
}
if(e.getSource()==b2)
{
flag=false;
}
}
}
一个利用多幅图像循环显示形成的动画程序:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class exec
{
public static void main(String args[])
{
MyFrame m=new MyFrame("OK");
m.setSize(300,400);
m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
m.setVisible(true);
}
}
class MyFrame extends JFrame
{
public MyFrame(String title)
{
super(title);
getContentPane().add(new MyPanel());
}
}
class MyPanel extends JPanel implements ActionListener,Runnable
{
int i=0;
boolean flag=false;//新的stop方法
Button b1=new Button("Start!");
Button b2=new Button("Stop!");
Image m[]=new Image[4];
Image nowm;
Thread th=new Thread(this);
public MyPanel()
{
add(b1);
add(b2);
b1.addActionListener(this);
b2.addActionListener(this);
m[0]=Toolkit.getDefaultToolkit().getImage("t1.gif");
m[1]=Toolkit.getDefaultToolkit().getImage("t2.gif");
m[2]=Toolkit.getDefaultToolkit().getImage("t3.gif");
m[3]=Toolkit.getDefaultToolkit().getImage("t4.gif");
th.start();
}
public void run()
{
while(true)
{
while(flag)
{
nowm=m[i++];
if(i>3)i=0;
repaint();
try
{
th.sleep(100);
}
catch(InterruptedException e)
{}
}
}
}
public void paint(Graphics g)
{
if(nowm!=null)g.drawImage(nowm,100,100,this);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==b1)
{
flag=true;
}
if(e.getSource()==b2)
{
flag=false;
}
}
public void update(Graphics g)
{
paint(g);//步骤1:直接跳过清屏,直接显示
}
}
[此贴子已经被作者于2010-12-12 08:02:44编辑过]