Using a Worker Thread to Relieve the Event Thread
使用工作线程来做事务操作
/*
* Created on 2005-7-17
*
* Java Thread Programming - Paul Hyde
* Copyright ? 1999 Sams Publishing
* Jonathan Q. Bo 学习笔记
*
*/
package org.tju.msnrl.jonathan.thread.chapter9;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* @author Jonathan Q. Bo from TJU MSNRL
*
* Email:jonathan.q.bo@gmail.com
* Blog:blog.csdn.net/jonathan_q_bo
* blog.yesky.net/jonathanundersun
*
* Enjoy Life with Sun!
*
*/
public class BalanceLookUp extends JPanel{
private JTextField accTF;
private JTextField pinTF;
private JButton searchB;
private JButton cancelB;
private JLabel balanceL;
private volatile Thread lookupThread;
public BalanceLookUp(){
buildGUI();//控制显示
hookupEvent();//添加事件处理
}
/** 添加控件 */
public void buildGUI(){
JLabel accountL = new JLabel("Account Label");
JLabel pinL = new JLabel("Pin");
accTF = new JTextField(12);
pinTF = new JTextField(4);
JPanel dataP = new JPanel();
dataP.setLayout(new FlowLayout(FlowLayout.CENTER));
dataP.add(accountL);
dataP.add(accTF);
dataP.add(pinL);
dataP.add(pinTF);
searchB = new JButton("search");
cancelB = new JButton("cancel");
cancelB.setEnabled(false);
JPanel buttonP = new JPanel();
buttonP.setLayout(new GridLayout(1,-1,5,5));
buttonP.add(searchB);
buttonP.add(cancelB);
JPanel outButtonP = new JPanel();
outButtonP.setLayout(new FlowLayout(FlowLayout.CENTER));
outButtonP.add(buttonP);
JLabel balancePrifLb = new JLabel("account balance");
this.balanceL = new JLabel("unknown balance");
JPanel balanceP = new JPanel();
balanceP.setLayout(new FlowLayout(FlowLayout.CENTER));
balanceP.add(balancePrifLb);
balanceP.add(balanceL);
JPanel northP = new JPanel();
northP.setLayout(new GridLayout(-1,1,5,5));
northP.add(dataP);
northP.add(outButtonP);
northP.add(balanceP);
setLayout(new BorderLayout());
add(northP);
}
/** 添加事件响应函数 */
public void hookupEvent(){
searchB.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e){
search();
}
}
);
cancelB.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e){
cancelSearch();
}
}
);
}
/** 处理查找操作 */
private void search(){
this.ensureEventThread();
searchB.setEnabled(false);
cancelB.setEnabled(true);
balanceL.setText("searching ... ");
String account = accTF.getText();
String pin = pinTF.getText();
/*新建一个线程处理,根据帐户和密码察看帐户余额*/
lookupAsyn(account,pin);
}
/**处理取消操作*/
private void cancelSearch(){
this.ensureEventThread();
cancelB.setEnabled(false);
searchB.setEnabled(true);
if(lookupThread != null){
lookupThread.interrupt();
}
}
/**新建线程处理察看操作*/
private void lookupAsyn(String acc,String pin){
final String accN = acc;
final String pinN = pin;
Runnable runA = new Runnable(){
public void run(){
String bal = lookupBalance(accN,pinN);
setBalanceSaftly(bal);
}
};
lookupThread = new Thread(runA);
lookupThread.start();
}
/** 安全的显示balance */
private void setBalanceSaftly(String bal){
final String balN = bal;
Runnable runA = new Runnable(){
public void run(){
try{
setBalance(balN);
}catch(Exception e){
e.printStackTrace();
}
}
};
/*放到消息队列,等待处理,返回*/
SwingUtilities.invokeLater(runA);
}
/** 显示balance */
private void setBalance(String bal){
this.ensureEventThread();
balanceL.setText(bal);
cancelB.setEnabled(false);
searchB.setEnabled(true);
}
/** 其实这两个参数没有用的啦 */
private String lookupBalance(String acc,String pin){
try{
Thread.sleep(5000);
return "1,234.5";
}catch(InterruptedException e){
return "search canceled";
}
}
/** 保证在消息线程中执行 */
private void ensureEventThread(){
if(SwingUtilities.isEventDispatchThread() == false)
throw new RuntimeException("only event thread can do this");
return;
}
public static void main(String[] args) {
BalanceLookUp blp = new BalanceLookUp();
JFrame f = new JFrame("Balance Lookup");
f.addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
f.setContentPane(blp);
f.setSize(400,150);
f.setVisible(true);
}
}
Scrolling Text in a Custom Component
动画效果:滚动字幕
/*
* Created on 2005-7-18
*
* Java Thread Programming - Paul Hyde
* Copyright ? 1999 Sams Publishing
* Jonathan Q. Bo 学习笔记
*
*/
package org.tju.msnrl.jonathan.thread.chapter9;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.image.*
;
/*
* Provides the Java 2D classes
* for defining and performing operations
* on objects
* related to two-dimensional geometry.
*/
/*提供二维几何操作*/
import java.awt.geom.*;
/**
* @author Jonathan Q. Bo from TJU MSNRL
*
* Email:jonathan.q.bo@gmail.com
* Blog:blog.csdn.net/jonathan_q_bo
* blog.yesky.net/jonathanundersun
*
* Enjoy Life with Sun!
*
*/
public class ScrollText extends JComponent {
private BufferedImage image;
private Dimension imageSize;
public volatile int currOffset;
private Thread localThread;
private volatile boolean noStopRequest;
public ScrollText(String text){
currOffset = 0;
buildImage(text);
this.setMaximumSize(this.imageSize);
this.setMinimumSize(this.imageSize);
this.setPreferredSize(this.imageSize);
this.setSize(this.imageSize);
this.noStopRequest = true;
Runnable runA = new Runnable(){
public void run(){
try{
runWork();
}catch(Exception e){
e.printStackTrace();
}
}
};
localThread = new Thread(runA,"ScrollText");
localThread.start();
}
public void paint(Graphics g){
g.setClip(0,0,this.imageSize.width,imageSize.height);
int localOffset = currOffset;
g.drawImage(this.image,-localOffset,0,this);
g.drawImage(this.image,imageSize.width - localOffset,0,this);
g.setColor(Color.BLACK);
g.drawRect(0,0,imageSize.width - 1,imageSize.height - 1);
}
public void stopThread(){
this.noStopRequest = false;
localThread.interrupt();
}
public boolean isAlive(){
return localThread.isAlive();
}
private void buildImage(String text){
RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
renderHints.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
BufferedImage scratchImage = new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB);
Graphics2D scratchG2 = scratchImage.createGraphics();
scratchG2.setRenderingHints(renderHints);
Font font = new Font("Serif",Font.BOLD | Font.ITALIC,24);
FontRenderContext frc = scratchG2.getFontRenderContext();
TextLayout tl = new TextLayout(text,font,frc);
Rectangle2D textBounds = tl.getBounds();
int textWidth = (int)Math.ceil(textBounds.getWidth());
int textHeight = (int)Math.ceil(textBounds.getHeight());
int horizPad = 10;
int verticPad = 6;
this.imageSize = new Dimension(textWidth + horizPad,textHeight + verticPad);
this.image = new BufferedImage(imageSize.width,imageSize.height,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
g2.setRenderingHints(renderHints);
int baselineOffset = (verticPad / 2) - (int)(textBounds.getY());
g2.setColor(Color.WHITE);
g2.fillRect(0,0,imageSize.width,imageSize.height);
g2.setColor(Color.BLUE);
tl.draw(g2,0,baselineOffset);
scratchG2.dispose();
scratchImage.flush();
g2.dispose();
}
private void runWork(){
while(noStopRequest){
try{
Thread.sleep(100);
currOffset = (currOffset + 1)%this.imageSize.width;
repaint();
}catch(InterruptedException e){
Thread.currentThread().interrupt();
System.out.println("interruptedException " + e.getMessage());
}
}
}
public static void main(String[] args) {
ScrollText st = new ScrollText("Java can do animation");
JPanel p = new JPanel(new FlowLayout());
p.add(st);
JFrame f = new JFrame("Scroll Text Demo");
f.setContentPane(p);
f.setSize(400,200);
f.setVisible(true);
}
}
Animating a Set of Images
动画效果:一个椭圆的动态缩放
/*
* Created on 2005-7-19
*
* Java Thread Programming - Paul Hyde
* Copyright ? 1999 Sams Publishing
* Jonathan Q. Bo 学习笔记
*
*/
package org.tju.msnrl.jonathan.thread.chapter9;
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
/**
* @author Jonathan Q. Bo from TJU MSNRL
*
* Email:jonathan.q.bo@gmail.com
* Blog:blog.csdn.net/jonathan_q_bo
* blog.yesky.net/jonathanundersun
*
* Enjoy Life with Sun!
*
*/
public class SlideShow extends JComponent {
private BufferedImage[] slide;//轮显的图形
private Dimension slideSize;//切片大小
private volatile int currSlide;//当前要显示的切片
private Thread internalThread;//新线程执行更新
private volatile boolean noStopRequested;//标识线程停止
public SlideShow(){
currSlide = 0;
/*设置控件大小*/
slideSize = new Dimension(50,50);
/*在缓存中作图*/
buildSlides();
/*设置为固定大小*/
setMinimumSize(slideSize);
setPreferredSize(slideSize);
setMaximumSize(slideSize);
setSize(slideSize);
noStopRequested = true;
Runnable r = new Runnable(){
public void run(){
try{
runWork();
}catch(Exception e){
e.printStackTrace();
}
}
};
/*自运行object*/
internalThread = new Thread(r,"SlidwShow");
internalThread.start();
}
public void paint(Graphics g){
/*绘制当前slide*/
g.drawImage(slide[currSlide],0,0,this);
}
private void buildSlides(){
RenderingHints renderHints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
renderHints.put(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
slide = new BufferedImage[20];
Color rectColor = new Color(100,160,250);
Color circleColor = new Color(250,250,150);
/*画出每一个slide*/
for(int i = 0; i < slide.length; i++){
slide[i] = new BufferedImage(
slideSize.width,
slideSize.height,
BufferedImage.TYPE_INT_RGB);
/*获得Graphics控制*/
Graphics2D g2 = slide[i].createGraphics();
/*设置renderhint*/
g2.setRenderingHints(renderHints);
/*填充矩形*/
g2.setColor(rectColor);
g2.fillRect(0,0,slideSize.width,slideSize.height);
/*画椭圆,5到45之间*/
g2.setColor(circleColor);
int diameter = 0;
if(i < (slide.length/2)){
diameter = 5 + (8*i);
}else{
diameter = 5 + (8*(slide.length - i));
}
int inset = (slideSize.width - diameter)/2;
g2.fillOval(inset,inset,diameter,diameter);
/*画矩形外框*/
g2.setColor(Color.BLACK);
g2.drawRect(0,0,slideSize.width - 1, slideSize.height - 1);
/*释放资源*/
g2.dispose();
}
}
private void runWork(){
while(noStopRequested){
try{
Thread.sleep(100);
/*轮换图片*/
currSlide = (currSlide + 1)%slide.length;
/*更新显示*/
repaint();
}catch(InterruptedException e){
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
}
public void stopRequest(){
noStopRequested = false;
internalThread.interrupt();
}
public static void main(String[] args){
SlideShow ss = new SlideShow();
JPanel p = new JPanel(new FlowLayout());
p.add(ss);
JFrame f = new JFrame("SlideShow Demo");
f.setContentPane(p);
f.setSize(250,150);
f.setVisible(true);
}
}
Displaying Elapsed Time on a JLabel
动画效果:在一个JLabel中显示逝去的时间
/*
* Created on 2005-7-19
*
* Java Thread Programming - Paul Hyde
* Copyright ? 1999 Sams Publishing
* Jonathan Q. Bo 学习笔记
*
*/
package org.tju.msnrl.jonathan.thread.chapter9;
import javax.swing.*;
import java.awt.*;
import java.text.*;
import java.lang.reflect.*;
/**
* @author Jonathan Q. Bo from TJU MSNRL
*
* Email:jonathan.q.bo@gmail.com
* Blog:blog.csdn.net/jonathan_q_bo
* blog.yesky.net/jonathanundersun
*
* Enjoy Life with Sun!
*
*/
public class DigitalTimer extends JLabel {
private volatile String timeText;
private Thread internalThread;
private volatile boolean noStopRequested;
public DigitalTimer(){
this.setBorder(BorderFactory.createLineBorder(Color.BLACK));
this.setHorizontalAlignment(SwingConstants.RIGHT);
this.setFont(new Font("SansSerif",Font.BOLD,16));
/*用来确定控件大小*/
this.setText("00000.0");
this.setMinimumSize(getPreferredSize());
this.setPreferredSize(this.getPreferredSize());
this.setSize(this.getPreferredSize());
timeText = "0.0";
this.setText(timeText);
noStopRequested = true;
Runnable r = new Runnable(){
public void run(){
try{
runWork();
}catch(Exception e){
e.printStackTrace();
}
}
};
/*自运行object*/
internalThread = new Thread(r,"DigitalTimer");
internalThread.start();
}
private void runWork(){
long startTime = System.currentTimeMillis();//开始时间
int tenths = 0;//线程执行的次数
long normalSleepTime = 100;//正常时间间隔
long nextSleepTime = 100;//下一次时间间隔
DecimalFormat fmt = new DecimalFormat("0.0");
/*更新label显示*/
Runnable updateText = new Runnable(){
public void run(){
setText(timeText);
}
};
while(noStopRequested){
try{
/*对实时性要求高*/
Thread.sleep(nextSleepTime);
/*while执行次数加*/
tenths++;
long currTime = System.currentTimeMillis();//当前时间
long elapsedTime = currTime - startTime;//实际已经过去的时间
/*下一次线程休息时间在应该间隔时间上调整,实际逝去时间和应该逝去时间的查值*/
nextSleepTime = normalSleepTime + ((tenths * 100) - elapsedTime);
/*如果为负,则设为0*/
if(nextSleepTime < 0)
nextSleepTime = 0;
/*通知显示*/
timeText = fmt.format(elapsedTime/1000.0);
SwingUtilities.invokeAndWait(updateText);
}catch(InterruptedException e1){
e1.printStackTrace();
/*停止运行*/
return;
}catch(InvocationTargetException e2){
e2.printStackTrace();
}
}
}
public static void main(String[] args){
DigitalTimer dt = new DigitalTimer();
JPanel p = new JPanel(new FlowLayout());
p.add(dt);
JFrame f = new JFrame("DigitalTimer Demo");
f.setContentPane(p);
f.setSize(250,100);
f.setVisible(true);
}
}