`
狼迹天涯
  • 浏览: 6405 次
  • 性别: Icon_minigender_2
文章分类
社区版块
存档分类
最新评论

线程的初步应用

    博客分类:
  • java
阅读更多
//线程初步应用——————————————————————————————————

 

   最近一段时间,我学习了有关线程的知识,今天来总结一下最近学到的知识。

我们的任务是要在窗体上绘制出一些能够互相碰撞的小球。这个功能的实现,需要用到线程相关知识。线程——进程中的某一个独立的运行单位。而多线程,是指几个线程同时进行,你在操作一个线程的时候,计算机自己运行其他的线程。(把多的任务交给计算机来做)。

在做的过程中分为了几部分

1、窗体的绘制

2、小球的绘制

3、按钮功能的实现

4、小球碰撞的实现

下面分别来介绍。

1、窗体的绘制,已经进行过多次了。就不再赘述。

2、小球的绘制

要将小球绘制在run方法中,因为我们要让小球自己去不停的运动,而我们要进行其他的操作。如果不将小球放于一个独立线程中,如果想要让小球一直运动,小球不停止,我们没有办法进行别的操作。

画小球不难,但是如何让其运动起来?在这里我们可以通过坐标的不断改变来移动小球。因此我们不断对一个已经绘制出来的小球进行擦除、移动、重绘的操作,就可以在窗体上形成不断移动的小球。让小球碰到窗体的边界反弹,则只需要加一个判断,当坐标到达边界时,使其改变正负即可。

3、按钮功能的实现

只需要在窗体上加几个按钮——“添加”、“暂停”、“恢复”,为其加上监听器即可。

“添加”的实现:重新启动一个小球的线程。

“暂停”的实现:遍历所有的小球,调用每一个小球的暂停方法。

“恢复”的实现:同暂停一样,遍历所有小球,调用每一个小球的恢复方法。

但是,在线程中,线程本身的暂停和恢复方法存在缺陷,即它无法确定在线程运行中的哪一步暂停。比如:现在这个小球的线程中,包含了小球的擦除、移动和重绘过程。我在点击“暂停”按钮的时候,无法确定它在哪一个过程暂停。如果在小球擦除后、重绘前暂停了,则会出现界面上小球消失的情况。

故,我们创建自己的暂停、恢复方法。(见代码)

4、小球碰撞的实现

要实现小球与小球之间的碰撞,我们需要在移动(改变坐标)的时候遍历每一个小球,判断其与当前小球的距离。当距离到达半径之和时,则需要改变方向。因此,需要用一个队列来保存每一个小球。在开启线程的时候,将小球保存在队列中。

 

代码如下:

 

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JFrame;

//继承线程类,重写run方法
public class Ball extends Thread{

	
	//定义必要的私有属性
	private JFrame jf;
	private Graphics g;
	private ArrayList<Ball>balls;
	//球的半径
	private int radius;
	//球的位置坐标
	private int x;
	private int y;
	//球的颜色
	private Color color;
	//球运动的方向
	private int directX=1;
	private int directY=1;
	private int speedX=1;
	private int speedY=1;
	
	//因为系统自带的线程运行和暂停的方法有缺陷,故定义自己的方法
	//线程运行状态标记,赋初始值
	private boolean pauseFlag=false;
	//线程停止标记,赋初始值
	private boolean stopFlag=false;
	
	
	//在构造函数中传入界面,得到画布
	public Ball(JFrame jf,ArrayList<Ball> balls) {
		this.jf=jf;
		this.balls=balls;
		g=jf.getGraphics();
		
		//随机初始化参数
		Random random=new Random();
		
		//球的大小,通过改变半径的大小
		radius=random.nextInt(20)+15;
		//球的运动速度,通过改变运动增量来改变
		speedX=random.nextInt(5)+1;
		speedY=random.nextInt(5)+1;
		//球的颜色,通过改变三原色(0——255)
		color=new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255));
		
	}
	
	//重写run方法
	public void run(){
		
		while(true){
			try {
				sleep(40);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			//判断,如果没有暂停,则继续
			if(pauseFlag){
				continue;
			}
			
			//小球运动起来的步骤为:清除、运动、画,为了使代码更直观,设置三个外方法,再分别调用
			clear();
			
			//如果停止线程运行则结束run方法
			if(stopFlag){
				break;
			}
			
			move();
			
			draw();
			
		}
		
	}

	public void clear() {
		//在小球运动前用背景颜色把以前的球覆盖掉
//		g.setColor(jf.getBackground());
//		g.fillOval(x, y, radius, radius);
		
		fillCircle(x,y,radius+2,jf.getBackground());
	}
	
	public void move() {
		
		//接收原位置坐标
		int oldX=x;
		int oldY=y;
		
		if(directX==1){
			x+=speedX;
		}else{
			x-=speedX;
		}
		
		if(directY==1){
			y+=speedY;
		}else{
			y-=speedY;
		}
		
		//碰到边界改变方向
		if(x<radius){
			directX=Math.abs(directX);
		}
		if(x>jf.getWidth()-radius){
			directX=-Math.abs(directX);
		}
		if(y<radius){
			directY=Math.abs(directY);
		}
		if(y>jf.getHeight()-radius){
			directY=-Math.abs(directY);
		}
		
		//遍历所有小球,判断碰撞
		for(int i=0;i<balls.size();i++){
			
			Ball ball=balls.get(i);
			//判断是否是自己
			if(ball==this){
				continue;
			}
			
			//进行距离的判断
			//两个球在X方向的距离
			int xx=Math.abs(x-ball.x);
			//两个球在Y方向的距离
			int yy=Math.abs(y-ball.y);
			//两个球圆心的距离
			int len=(int) Math.sqrt(xx*xx+yy*yy);
			
			//判断是否撞上
			//当圆心距离小于两球半径之和时,撞上
			if(len<=radius+ball.radius){
				
				//判断是否改变方向和速度
				if(directX!=ball.directX){
					//改变方向
					directX=-directX;
					ball.directX=-ball.directX;
					
					//交换速度
					int tempspeed=speedX;
					speedX=ball.speedX;
					ball.speedX=tempspeed;
				}
				
				if(directY!=ball.directY){
					//改变方向
					directY=-directY;
					ball.directY=-ball.directY;
					
					//交换速度
					int tempspeed=speedY;
					speedY=ball.speedY;
					ball.speedY=tempspeed;
				}
				
				if(directX==ball.directX && directY==ball.directY){
					
					//如果为追击问题。则交换速度,方向不变
					
					int tempspeedX=speedX;
					speedX=ball.speedX;
					ball.speedX=tempspeedX;
					
					int tempspeedY=speedY;
					speedY=ball.speedY;
					ball.speedY=tempspeedY;
					
				}
				//解除粘连效果?????????
				x=oldX;
				y=oldY;
				
				
				
			}
		}
		
	}
	
	//要做出一个立体球的效果,需要多次画球,进行颜色以及大小的改变
	private Color getColor(int inc){
		
		int red=color.getRed();
		int green=color.getGreen();
		int blue=color.getBlue();
		
		red+=inc;
		green+=inc;
		blue+=inc;
		
		//判断颜色是否超出一定范围
		if(red>255){
			red=255;
		}
		if(green>255){
			green=255;
		}
		if(blue>255){
			blue=255;
		}
		
		return new Color(red, green, blue);
	}
	
	//因为使用原来的覆盖方法是画椭圆,清楚不干净,会留下一条“尾巴”,故设置自己的清楚方法
	private void fillCircle(int x,int y,int r,Color c){
		Graphics2D gg = (Graphics2D)g;
		//通过该方法的设置,使图形去除锯齿状,可以得到多么细腻的图形——会出现频闪的情况
		gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
		gg.setColor(c);
		gg.fillOval(x-r, y-r, 2*r, 2*r);//画圆的方法?????
		
	}
	
	
	
	public void draw() {
		//在新的位置画小球
//		g.setColor(color);
//		g.fillOval(x, y, radius, radius);
		
		//为了不破坏原变量,这里定义一个临时变量
		int r=radius;
		
		//也可以让光点偏移一些,更漂亮
		int xx=x;
		
		for(int i=0;r>13 && xx>=radius/2;i++){
			Color c=getColor(i*8);
			
			
			fillCircle(xx-1,y,r,c);
			r--;
			xx=xx-1;

		
		}
		
	}
	
	
	//线程暂停和恢复的方法
	public void pause(){
		pauseFlag=true;
	}
	public void restart(){
		pauseFlag=false;
	}
}

 

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Game {

	//定义必要的变量
	private JFrame jf;
	private Graphics g;
	private Color color;
	
	//设置一个队列,保存所有的小球
	private ArrayList<Ball> list=new ArrayList<Ball>();
	
	//主函数
	public static void main(String args[]){
		new Game().initUI();
	}
	
	
	public void initUI(){
		//设置界面
		final JFrame jf=new JFrame();
		jf.setSize(400,400);
		jf.setDefaultCloseOperation(3);
		jf.setLocation(300,100);
		
		//设置一个布局
		jf.setLayout(new FlowLayout());
		
		//设置三个按钮,功能分别为添加、暂停、恢复线程。
		JButton btn1=new JButton("添加");
		JButton btn2=new JButton("暂停");
		JButton btn3=new JButton("恢复");
		
		jf.add(btn1);
		jf.add(btn2);
		jf.add(btn3);
		
		//设置时间监听器
		ActionListener l=new ActionListener(){

			
			public void actionPerformed(ActionEvent e) {
				
				//根据按钮上的文字来判断执行什么样的命令
				//先获取按钮上的文字
				String cmd=e.getActionCommand();
				
				//判断
				if("添加".equals(cmd)){
					//新建一个线程对象
					Ball bl=new Ball(jf,list);
					//启动线程
					bl.start();

					//把球保存在队列中
					list.add(bl);
					
				}
				
				if("暂停".equals(cmd)){
					//暂停线程,线程中有自己的暂停方法
					//遍历所有的小球,调用每一个小球的暂停方法
					for(int i=0;i<list.size();i++){
						
						Ball bl=list.get(i);
						//bl.suspend();//不建议使用
						//因为该方法不确定在线程中的哪一步暂停,不可控性,可以编写自己的暂停方法
						
						//自己的暂停方法
						bl.pause();
						
					}
				}
				
				if("恢复".equals(cmd)){
					//恢复线程的运行,线程中有自己的回复方法
					//同暂停一样,遍历所有小球,调用每一个小球的恢复方法
					for(int i=0;i<list.size();i++){
						
						Ball bl=list.get(i);
						//bl.resume();//不建议使用,原因同暂停方法一样
						
						//自己的恢复方法
						bl.restart();
					}
					
				}
				
				
			}
			
		};
		
		//在按钮上添加监听器
		btn1.addActionListener(l);
		btn2.addActionListener(l);
		btn3.addActionListener(l);
		
		//界面可视化
		jf.setVisible(true);
	}
	
}

   

 

  

遇到的问题:

1、我想在编写这类代码的时候,遇到最多的问题就是:我绘制的东西,为什么在界面上显示不出来。

我想,最有可能是你并没有传入相应的画布。

2、我在第一次画出运动的小球时,出现了小球频繁闪动的情况,

这有可能是休眠时间的原因,通过修改sleep的参数可以缓解频闪的情况。

 

代码的优化:

1、可以在类中设置一些私有属性作为变量,方便代码的修改。

2、在run方法中编写小球的擦除、移动、画的方法代码时,会使整个代码显得凌乱,可以将其设置为类中的方法,再在run方法中调用即可。

3、通过分形的思想,让小球显得更立体。

 

<!--EndFragment-->

分享到:
评论

相关推荐

    用C#实现的unity线程初步

    C#线程学习如同在Java中一样,在c#中写一个多线程应用是非常简单的,本章将介绍如何在c#种开发多线程程序。在.net中线程是由System.Threading 名字空间所定义的。所以你必须包含这个名字空间。

    Linux多线程 C语言编程关于多线程

    统中才引入多线程机制,如今,由于自身的许多优点,多线程编程已经得到了广泛的应用。 本文我们将介绍在Linux 下编写多进程和多线程程序的一些初步知识。 1 引言 对于没有接触过 Unix/Linux 操作系统的人来说,fork ...

    线程应用,主要展示初学者同步线程的认识与介绍

    附件为视频案例。主要对初学者展示了同步线程的认识 案例介绍了兔子与乌龟赛跑的同步线程,比较形象的介绍了大家对线程的初步理解

    LINUX多线程编程

    多线程程序设计的概念早在六十年代就被提出,但直到八十年代...统中才引入多线程机制,如今,由于自身的许多优点,多线程编程已经得到了广泛的应用。 本文我们将介绍在Linux 下编写多进程和多线程程序的一些初步知识。

    《Delphi 深度编程及其项目应用开发》PDF书及代码

    基础篇结合示例论述了Delphi的深度编程技术,其中包括9章,分别为:理解Windows消息、进程与线程、自定义组件的编写、文件操作、创建DLL应用程序、两层数据库应用程序、多层数据库应用程序、Socket编程、串口编程;...

    Linux下的多进程编程初步

    多线程程序设计的概念早在六十年代就被提出,但直到八十年代中期,Unix系统中才引入多线程机制,如今,由于自身的许多优点,多线程编程已经得到了广泛的应用。本文我们将介绍在Linux下编写多进程和多线程程序的一些...

    Android高级应用开发.z11-Android高级应用开发.z01

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z17

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z18

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z19

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z15

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z16

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z13

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z12

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z11

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z10

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z09

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z08

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z06

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

    Android高级应用开发教学视频-Android高级应用开发.z05

    Stage3_Lesson2Android的多线程与异步任务 Stage3_Lesson3高级商业界面开发 Stage3_Lesson4Android多媒体的世界 Stage3_Lesson5NDK初步 Stage3_Lesson6电话与短信应用 Stage4_Lesson1项目沟通的语言是UML Stage4_...

Global site tag (gtag.js) - Google Analytics