本程序基于下面教材的例程修改
尉哲明,冀素琴,郭珉. 基于Java的综合课程设计. 北京: 清华大学出版社, 2014(12).
案例:两按钮反向运动——使用Runnable接口
案例问题描述
创建一个GUI程序,当单击“开始”按钮,界面中的两个按钮开始朝相反方向运动,单击“停止”按钮,两按钮同时停止运动。要求通过Thread类的子类来实现多线程,再现两按钮反向运动的情景。
案例练习题目
(1)为该应用程序增加一个功能,用户可以控制按钮移动的速度(让用户可以控制按钮两次移动之间的时间间隔)。
//12_2_1
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class MoveButtonWindow extends JFrame implements ActionListener,Runnable
{
JButton startButton,stopButton,exitButton;
JButton rightButton,leftButton;
Thread left,right;
boolean boo=true;
JButton accelerationButton,decelerationButton;
int time=200;
public MoveButtonWindow()
{
setTitle("测试多线程主窗口");
JPanel centerPanel=new JPanel();
JPanel controlPanel=new JPanel();
add(centerPanel,BorderLayout.CENTER );
add(controlPanel,BorderLayout.SOUTH );
startButton=new JButton("开始/继续");
startButton.addActionListener(this);
stopButton=new JButton("停止");
stopButton.addActionListener(this);
exitButton=new JButton("退出");
exitButton.addActionListener(this);
accelerationButton=new JButton("加速");
accelerationButton.addActionListener(this);
decelerationButton=new JButton("减速");
decelerationButton.addActionListener(this);
controlPanel.add(this.startButton );
controlPanel.add(this.stopButton );
controlPanel.add(this.exitButton );
controlPanel.add(this.accelerationButton);
controlPanel.add(this.decelerationButton);
centerPanel.setLayout(null);
centerPanel.setBackground(Color.white );
rightButton=new JButton("向右移动");
rightButton.setBackground(Color.yellow );
rightButton.setBounds(0, 5, 100, 30);
leftButton=new JButton("向左移动");
leftButton.setBackground(Color.red );
leftButton.setBounds(385,90,100,30);
centerPanel.add(rightButton);
centerPanel.add(leftButton);
right=new Thread(this);
left=new Thread(this);
setBounds(100,100,500,200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
this.setResizable(false);
setVisible(true);
validate();
}
@Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==this.startButton )
{
if(!right.isAlive())
{
right=new Thread(this);
}
if(!left.isAlive())
{
left=new Thread(this);
}
boo=true;
right.start();
left.start();
}
else if(e.getSource()==this.stopButton)
{
boo=false;
}
else if(e.getSource()==this.exitButton)
{
boo=false;
System.exit(0);
}
else if(e.getSource()==this.accelerationButton)
{
time=time-20;
}
else if(e.getSource()==this.decelerationButton)
{
time=time+20;
}
}
public static void main(String[] args)
{
new MoveButtonWindow();
}
@Override
public void run()
{
while(true)
{
if(Thread.currentThread()==right)
{
int x=this.rightButton.getBounds().x;
x=x+5;
if(x>400)
{
x=5;
}
rightButton.setLocation(x, 5);
try
{
Thread.sleep(time);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}// end of if(Thread.currentThread()==right)
else if(Thread.currentThread()==left)
{
int x=leftButton.getBounds().x;
x=x-5;
if(x<0)
{
x=385;
}
leftButton.setLocation(x, 90);
try
{
Thread.sleep(time);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}// end of else if(Thread.currentThread()==left)
if(!boo)
{
return;
}
}//end of while(true)
}
}
(2)请设计一个使用Runnable接口实现多线程的程序,实现让两个人其中一个人报1~100的平方,另一个人报1~100的立方。
//12_2_2
public class TwelveTwoTwo implements Runnable
{
//top报1~100的平方,bottom报1~100的立方
Thread top,bottom;
int topNum=1;
int bottomNum=1;
String Result;
public TwelveTwoTwo()
{
top=new Thread(this);
top.start();
bottom=new Thread(this);
bottom.start();
}
public void run()
{
while(true)
{
//报1~100的平方
if(Thread.currentThread()==top)
{
int result=topNum*topNum;
System.out.println("top给出的数字为:"+result);
topNum++;
try
{
Thread.sleep(2000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
//报1~100的立方
else if(Thread.currentThread()==bottom)
{
int result=bottomNum*bottomNum*bottomNum;
System.out.println("bottom给出的数字为:"+result);
bottomNum++;
try
{
Thread.sleep(2000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}//else if(Thread.currentThread()==bottom)
}
}
public static void main(String[] args)
{
new TwelveTwoTwo();
}
}
(3)请设计一个使用Runnable接口实现多线程的程序,用两个小球模拟物理中的自由落体运动和平抛运动。
//12_2_3
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
@SuppressWarnings("serial")
public class TwelveTwoThree extends JFrame implements Runnable
{
MyOval topOval,bottomOval;
Color topColor,bottomColor;
Thread top,bottom;
boolean boo=true;
public TwelveTwoThree()
{
setTitle("12_2_3");
topColor=new Color(250,50,50);
topOval=new MyOval(100,50,20,20,topColor,true);
topOval.setV(0);
bottomColor=new Color(200,50,50);
bottomOval=new MyOval(100,50,20,20,bottomColor,false);
bottomOval.setV(30);
top=new Thread(this);
bottom=new Thread(this);
top.start();
bottom.start();
setBounds(100,100,600,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g)
{
super.paint(g);
topOval.draw(g);
bottomOval.draw(g);
}
@Override
public void run()
{
while(true)
{
if(Thread.currentThread()==top)
{
int x=topOval.getX();
int y=topOval.getY();
int t=topOval.getTime();
int v=topOval.getV();
t=topOval.getTim()+t;
y=(int)(4.9*t*t)+50;
x=v*t+100;
try
{
Thread.sleep(800);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
topOval.setX(x);
topOval.setY(y);
topOval.setTim(t);
repaint();
if(topOval.getY()>600)
boo=false;
else if(topOval.getX()>600)
boo=false;
}// end of if(Thread.currentThread()==top)
else if(Thread.currentThread()==bottom)
{
int x=bottomOval.getX();
int y=bottomOval.getY();
int t=bottomOval.getTime();
int v=bottomOval.getV();
t=bottomOval.getTim()+t;
y=(int)(4.9*t*t)+50;
x=v*t+100;
try
{
Thread.sleep(800);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
bottomOval.setX(x);
bottomOval.setY(y);
bottomOval.setTim(t);
repaint();
if(bottomOval.getY()>600)
boo=false;
else if(bottomOval.getX()>600)
boo=false;
}// end of if(Thread.currentThread()==bottom)
if(!boo)
return;
}//end of while(true)
}
public static void main(String[] args)
{
new TwelveTwoThree();
}
}
//12_2_3
import java.awt.Color;
import java.awt.Graphics;
public class MyOval
{
private int x,y,width,height;
private Color color;
private Boolean flag;
private int time=1; //间隔时长
private int tim=0; //总时长
private int v=0; //水平速度
public MyOval()
{
this.x=0;
this.y=0;
this.width=0;
this.height=0;
this.color=Color.white;
this.flag=true;
}
public MyOval(int x,int y,int width,int height,Color color,Boolean flag)
{
this.x=x;
this.y=y;
this.width=width;
this.height=height;
this.color=color;
this.flag=flag;
}
public void draw(Graphics g)
{
g.setColor(color);
if(flag)
g.fillOval(x,y,width,height);
else
g.drawOval(x,y,width,height);
}
public int getX()
{
return x;
}
public void setX(int x)
{
this.x=x;
}
public int getY()
{
return y;
}
public void setY(int y)
{
this.y=y;
}
public int getTime()
{
return time;
}
public int getTim()
{
return tim;
}
public void setTim(int tim)
{
this.tim=tim;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public Boolean getFlag()
{
return flag;
}
public int getV()
{
return v;
}
public void setV(int v)
{
this.v=v;
}
}
(4)请设计一个使用Runnable接口实现多线程的程序,用两个小球模拟物理中的正弦函数和余弦函数曲线进行运动。
//12_2_4
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
@SuppressWarnings("serial")
public class TwelveTwoFour extends JFrame implements Runnable
{
MyOval topOval,bottomOval;
Color topColor,bottomColor;
Thread top,bottom;
boolean boo=true;
public TwelveTwoFour()
{
setTitle("12_2_4");
topColor=new Color(250,50,50);
topOval=new MyOval(50,290,20,20,topColor,true);
bottomColor=new Color(200,50,50);
bottomOval=new MyOval(50,290,20,20,bottomColor,false);
bottomOval.setIne(1);
top=new Thread(this);
bottom=new Thread(this);
top.start();
bottom.start();
setBounds(100,100,600,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g)
{
super.paint(g);
topOval.draw(g);
bottomOval.draw(g);
g.drawLine(0,300,600,300);
}
@Override
public void run()
{
while(true)
{
if(Thread.currentThread()==top)
{
double d=topOval.getDegree();
double radian = Math.toRadians(d);
int x=(int)(d+50);
d=d+5;
int y=(int)(290-Math.sin(radian)*100);
try
{
Thread.sleep(400);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
topOval.setX(x);
topOval.setY(y);
topOval.setDegree(d);
repaint();
if(topOval.getX()>600)
boo=false;
}// end of if(Thread.currentThread()==top)
else if(Thread.currentThread()==bottom)
{
double d=bottomOval.getDegree();
double radian = Math.toRadians(d);
int x=(int)(d+50);
d=d+5;
int y=(int)(290-Math.cos(radian)*100);
try
{
Thread.sleep(400);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
bottomOval.setX(x);
bottomOval.setY(y);
bottomOval.setDegree(d);
repaint();
if(bottomOval.getX()>600)
boo=false;
}// end of if(Thread.currentThread()==bottom)
if(!boo)
return;
}//end of while(true)
}
public static void main(String[] args)
{
new TwelveTwoFour();
}
}
//12_2_4
import java.awt.Color;
import java.awt.Graphics;
public class MyOval
{
private int x,y,width,height;
private Color color;
private Boolean flag;
private int time=1; //间隔时长
private int tim=0; //总时长
private int v=0; //水平速度
private double degree=0; //角度
private int ine=0; //零为正弦,一为余弦
public MyOval()
{
this.x=0;
this.y=0;
this.width=0;
this.height=0;
this.color=Color.white;
this.flag=true;
}
public MyOval(int x,int y,int width,int height,Color color,Boolean flag)
{
this.x=x;
this.y=y;
this.width=width;
this.height=height;
this.color=color;
this.flag=flag;
}
public void draw(Graphics g)
{
g.setColor(color);
if(flag)
g.fillOval(x,y,width,height);
else
g.drawOval(x,y,width,height);
}
public int getX()
{
return x;
}
public void setX(int x)
{
this.x=x;
}
public int getY()
{
return y;
}
public void setY(int y)
{
this.y=y;
}
public int getTime()
{
return time;
}
public int getTim()
{
return tim;
}
public void setTim(int tim)
{
this.tim=tim;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public Boolean getFlag()
{
return flag;
}
public int getV()
{
return v;
}
public void setV(int v)
{
this.v=v;
}
public double getDegree()
{
return degree;
}
public void setDegree(double degree)
{
this.degree=degree;
}
public int getIne()
{
return ine;
}
public void setIne(int ine)
{
this.ine=ine;
}
}
(5)请设计一个使用Runnable接口实现多线程的程序,实现猜数字游戏。一个线程负责随机给出一个1~100之间的正整数,另一个线程负责猜数字。
//12_2_5
/*
* @author https://beishan.blog.csdn.net/?type=blog
* @source https://beishan.blog.csdn.net/article/details/112393313?spm=1001.2014.3001.5502
*/
import java.util.Random;
public class TwelveTwoFive implements Runnable
{
Thread top,bottom;
int topN;
int bottomMin=0,bottomMax=100,bottomN;
String Result;
public TwelveTwoFive()
{
top=new Thread(this);
top.start();
bottom=new Thread(this);
bottom.start();
}
public void run()
{
if(Thread.currentThread()==top)
{
//获取1~100的随机数
Random random=new Random();
topN=random.nextInt(100);
System.out.println("top给出的数字为:"+topN);
}
else if(Thread.currentThread()==bottom)
{
while(true)
{
try
{
Thread.sleep(2000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
Random ran=new Random();
//当前猜的数字(最大值和最小值之间的数)
bottomN=bottomMin+ran.nextInt(bottomMax-bottomMin);
//调用给出整数的线程 的猜数字方法guessnum,
Result=guessnum(bottomN);
if(Result.equals("猜小了"))
{
bottomMin=bottomN;
System.out.println("线程二猜的数字是:"+bottomN+"---猜小了");
}
else if(Result.equals("猜大了"))
{
bottomMax=bottomN;
System.out.println("线程二猜的数字是:"+bottomN+"---猜大了");
}
else
{
System.out.println("线程二猜的数字是:"+bottomN+"---猜对了,结果是"+bottomN);
System.exit(0);
}
}//end of while(true)
}//else if(Thread.currentThread()==bottom)
}
//猜数字
public String guessnum(int m)
{
if(m<topN)
{
return "猜小了";
}
else if(m>topN)
{
return "猜大了";
}
else return "猜对了";
}
//获取比较结果
public String getGuess()
{
return Result;
}
public static void main(String[] args)
{
new TwelveTwoFive();
}
}