題目:畫一個沿著正弦曲線移動的小球,顏色在移動中不斷變化
思路:
1.基于JFrame,兩個線程:分別負責背景及正弦曲線的重繪和小球的重繪
2.其中分別弄兩張圖片,使用圖像雙緩沖技術,先載入內存中,再進行繪制。使用到BufferedImage類
源代碼:
//SinBall - Lonsy
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
public class SinBall extends JFrame implements Runnable
{
private boolean endInit; //判斷窗口是否第一次paint完畢
private int x0, y0, x1, y1, x2, y2; //0為坐標軸原點的窗口坐標,1為臨時坐標,2為實時、球的坐標軸中的坐標
private double unit; //x軸單位大小
static int ballsize = 10; //球的直徑
static Color backcolor = new Color(255, 255, 255); //背景顏色
static Color linecolor = new Color(0, 0, 255); //坐標及正弦曲線的顏色
static int ballcolorrgb = 0x0; //球的初始顏色的rgb值,以十六進制表示
public int interval = 8; //球運行的速度,用兩次繪圖間的時間間隔表示
BufferedImage imgcoordinate; //坐標及背景的圖片
BufferedImage imgball; //球的圖片
Graphics2D gball; //imgball圖片的Graphics
public SinBall() { //構造函數
super("沿著正弦曲線移動的小球"); //設定窗口的標題
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //設定關閉按鈕的作用
//設定坐標軸原點的窗口坐標
this.x0 = 10;
this.y0 = this.getHeight() / 2 + 10;
//處理窗口的大小變化事件,重置坐標軸原點的坐標,重畫背景圖片等
addComponentListener(new ComponentAdapter(){
public void componentResized(ComponentEvent e){
SinBall obj = (SinBall)e.getComponent();
obj.x0 = 10;
obj.y0 = obj.getHeight() / 2 + 10;
createCoordinate();
obj.repaint();
}
});
//初始化其他需要初始化的值
endInit = false;
imgcoordinate = null;
imgball = null;
}
//方法,繪制背景圖片,保存到imgcoordinate中
public void createCoordinate() {
if (imgcoordinate != null)
{
imgcoordinate = null;
}
imgcoordinate = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g = imgcoordinate.createGraphics();
g.setColor(backcolor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(linecolor);
g.drawLine(0, y0, getWidth(), y0);
g.drawLine(x0, 0, x0, getHeight());
x1 = x0;
y1 = y0;
unit = (getWidth() - 20.0) / 360;
for(int i=0; i<=360; i++) {
x2 = (int)(x0 + i * unit);
y2 = y0 - (int)((y0 - 30) * Math.sin(i * Math.PI / 180.0));
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
}
x2 = x0;
y2 = y0;
}
//方法,繪制小球,保存到imgball中
public void createBall() {
imgball = new BufferedImage(ballsize, ballsize, BufferedImage.TYPE_3BYTE_BGR);
gball = imgball.createGraphics();
gball.setColor(backcolor);
gball.fillRect(0, 0, ballsize, ballsize);
gball.setColor(new Color(ballcolorrgb));
gball.fillOval(0, 0, ballsize, ballsize);
}
//重寫父類的paint事件,處理相關繪圖事宜
public void paint(Graphics g) {
if (imgcoordinate == null)
{
createCoordinate(); //若imgcoordinate為null,則重建
}
if (imgball == null)
{
createBall(); //若imgball為null,則重建
}
if (imgcoordinate != null)
{
g.drawImage(imgcoordinate, 0, 0, getWidth(), getHeight(), this); //imgcoordinate不為空,繪制
}
if (imgball != null)
{
g.drawImage(imgball, x2 - 5, y2 - 5, 10, 10, this); //imgball不為空,繪制
}
if (endInit == false) //判斷是否為第一次paint,若為真,則置endInit為空,并啟動新線程
{
endInit = true;
new Thread(this).start();
}
}
//實現接口Runnable的run事件,處理線程的相關繪圖動作安排
public void run() {
while(endInit) {
for(int i=0; i<=360; i++) { //活動一個正弦線
x2 = (int)(x0 + i * unit); //計算當前坐標
y2 = y0 - (int)((y0 - 30) * Math.sin(i * Math.PI / 180.0));
try
{
Thread.sleep(interval); //實現速度的調節
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
gball.setColor(new Color(16777215 / 360 + 360 * i + ballcolorrgb)); //改變球的顏色
gball.fillOval(0, 0, ballsize, ballsize);
repaint(); //調用paint方法,繪制當前實時圖像
}
}
}
//類的主函數,定義一個對象,并設置為可見
public static void main(String[] args) {
SinBall ball = new SinBall();
ball.setBounds(200, 200, 500, 300);
ball.setVisible(true);
}
}
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
public class SinBall extends JFrame implements Runnable
{
private boolean endInit; //判斷窗口是否第一次paint完畢
private int x0, y0, x1, y1, x2, y2; //0為坐標軸原點的窗口坐標,1為臨時坐標,2為實時、球的坐標軸中的坐標
private double unit; //x軸單位大小
static int ballsize = 10; //球的直徑
static Color backcolor = new Color(255, 255, 255); //背景顏色
static Color linecolor = new Color(0, 0, 255); //坐標及正弦曲線的顏色
static int ballcolorrgb = 0x0; //球的初始顏色的rgb值,以十六進制表示
public int interval = 8; //球運行的速度,用兩次繪圖間的時間間隔表示
BufferedImage imgcoordinate; //坐標及背景的圖片
BufferedImage imgball; //球的圖片
Graphics2D gball; //imgball圖片的Graphics
public SinBall() { //構造函數
super("沿著正弦曲線移動的小球"); //設定窗口的標題
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //設定關閉按鈕的作用
//設定坐標軸原點的窗口坐標
this.x0 = 10;
this.y0 = this.getHeight() / 2 + 10;
//處理窗口的大小變化事件,重置坐標軸原點的坐標,重畫背景圖片等
addComponentListener(new ComponentAdapter(){
public void componentResized(ComponentEvent e){
SinBall obj = (SinBall)e.getComponent();
obj.x0 = 10;
obj.y0 = obj.getHeight() / 2 + 10;
createCoordinate();
obj.repaint();
}
});
//初始化其他需要初始化的值
endInit = false;
imgcoordinate = null;
imgball = null;
}
//方法,繪制背景圖片,保存到imgcoordinate中
public void createCoordinate() {
if (imgcoordinate != null)
{
imgcoordinate = null;
}
imgcoordinate = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g = imgcoordinate.createGraphics();
g.setColor(backcolor);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(linecolor);
g.drawLine(0, y0, getWidth(), y0);
g.drawLine(x0, 0, x0, getHeight());
x1 = x0;
y1 = y0;
unit = (getWidth() - 20.0) / 360;
for(int i=0; i<=360; i++) {
x2 = (int)(x0 + i * unit);
y2 = y0 - (int)((y0 - 30) * Math.sin(i * Math.PI / 180.0));
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
}
x2 = x0;
y2 = y0;
}
//方法,繪制小球,保存到imgball中
public void createBall() {
imgball = new BufferedImage(ballsize, ballsize, BufferedImage.TYPE_3BYTE_BGR);
gball = imgball.createGraphics();
gball.setColor(backcolor);
gball.fillRect(0, 0, ballsize, ballsize);
gball.setColor(new Color(ballcolorrgb));
gball.fillOval(0, 0, ballsize, ballsize);
}
//重寫父類的paint事件,處理相關繪圖事宜
public void paint(Graphics g) {
if (imgcoordinate == null)
{
createCoordinate(); //若imgcoordinate為null,則重建
}
if (imgball == null)
{
createBall(); //若imgball為null,則重建
}
if (imgcoordinate != null)
{
g.drawImage(imgcoordinate, 0, 0, getWidth(), getHeight(), this); //imgcoordinate不為空,繪制
}
if (imgball != null)
{
g.drawImage(imgball, x2 - 5, y2 - 5, 10, 10, this); //imgball不為空,繪制
}
if (endInit == false) //判斷是否為第一次paint,若為真,則置endInit為空,并啟動新線程
{
endInit = true;
new Thread(this).start();
}
}
//實現接口Runnable的run事件,處理線程的相關繪圖動作安排
public void run() {
while(endInit) {
for(int i=0; i<=360; i++) { //活動一個正弦線
x2 = (int)(x0 + i * unit); //計算當前坐標
y2 = y0 - (int)((y0 - 30) * Math.sin(i * Math.PI / 180.0));
try
{
Thread.sleep(interval); //實現速度的調節
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
gball.setColor(new Color(16777215 / 360 + 360 * i + ballcolorrgb)); //改變球的顏色
gball.fillOval(0, 0, ballsize, ballsize);
repaint(); //調用paint方法,繪制當前實時圖像
}
}
}
//類的主函數,定義一個對象,并設置為可見
public static void main(String[] args) {
SinBall ball = new SinBall();
ball.setBounds(200, 200, 500, 300);
ball.setVisible(true);
}
}