`
javahacker2
  • 浏览: 43864 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Swing Worker应用举例

 
阅读更多

在开发Java Swing应用程序的过程中,有两个原则是必须要牢记的:
    1.耗时的操作(例如从数据库查询大量数据,读取URI资源等)一定不能运行在EDT(事件派发线程)上,否则会导致Swing用户界面失去响应。
    2.只能在EDT线程上对Swing Components进行访问。
    基于上面两点原因,在一个Java Swing程序中,要想使用户界面响应灵敏,至少应该有两个线程;一个线程用来执行耗时操作,EDT线程用来执行所有与Swing Components的交互,例如更新文本,重绘图形等等。这就要求两个线程之间要相互通讯,给程序的开发带来了不少的难度,Swing Worker的出现从根本上解决了这个问题,使程序员快速开发反应灵敏的的Swing程序成为可能。SwingWoker被设计应用在此种场景下,你有一个耗时操作需要运行在后台,在该操作完成或部分完成时,你要利用操作返回的结果去更新用户界面。
    让我们假想有这样一个应用场景,我有一个保存联系人的文件,我需要从中读取并解析出所有联系人的信息,并及时更新在一个JTable中;假设这个文件非常的大,解析出所有联系人的信息需要花费几分钟的时间,如果不能很好的协调这个任务和EDT线程,则很有可能会造成用户在几分钟时间里得不到结果,而Swing界面处于无响应状态。在这种情况下,SwingWorker就是一个绝佳的选择。我们首先看一下SwingWorker的定义:
    public abstract class SwingWorker<T,V> extends Object implements RunnableFuture<T>
显然,这时一个抽象的模板类,在应用的时候,我们需要继承SwingWorker并实例化模板参数。那么,这两个模板类型究竟是什么意思呢,T参数代表的是你的耗时任务执行完成时返回的结果类型,V代表的是你的耗时任务部分完成时返回的结果类型。在我们的场景中,假设任务完成时我们需要一个List<BeanContact>(BeanContact是一个保存联系人信息的JavaBean),每当从文件中解析出一个联系人信息时,我们会新建一个BeanContact并需要更新到JTable中。那么我们的T就是List<BeanContact>,而V就是BeanContact,则应该定义如下的类:
     public class LoadContactsTask extends SwingWorker<List<BeanContact>, BeanContact> {
            

     @Override
    protected List<BeanContact> doInBackground() throws Exception {

        //To do the task and return the result
    }


     }
    从上面可以看到,我们还必须覆盖SwingWorker的doInBackground方法,该方法执行我们的耗时操作,并且返回模板实例化时的T类型结果。下面是具体的代码实现:
     

    @Override
    protected List<BeanContact> doInBackground() throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader("c:/contacts.cff"));
        String line = null;
        while ((line = reader.readLine()) != null) {
            String[] strContacts = line.split(",");
            BeanContact contact = new BeanContact();
            contact.setName(strContacts[0]);
            contact.setSex(strContacts[1]);
            contact.setPhone(strContacts[2]);
            contact.setEmail(strContacts[3]);

            lineCnt++;
            publish(contact);/*********/
           contacts.add(contact);
           
            Thread.sleep(100);
        }
        return contacts;
    }

     该方法很简单,就是从文件中读取一个联系人的记录并且新建一个BeanContact实例添加到结果集中。我们需要注意的是其中的publish方法,该方法用来发布部分执行结果,每读取一个联系人信息,我们就用该方法把新建的BeanContact发布出去。我们需要知道的是,在publish若干个结果后(可能是一个或多个,由SwingWorker类实现)SwingWorker类的process方法会被自动回调,而我们可以在其中去更新用户界面,SwingWorker保证process方法中所有操作都运行在EDT线程中。下面是我们的具体实现:
    @Override
    protected void process(List<BeanContact> chunks) {
        if (progressHandle != null) {
            progressHandle.processInProgress(chunks, lineCnt * 100 / 10000);
        }
    }

    我们的实现中,process中会调用IProgressHandle(自定义的一个接口,用来更新用户界面,详见后面代码)的processInProgress方法来更新用户界面,大家会注意到process方法的参数是一个List<BeanContact>,为什么不是一个BeanContact呢,答案就是我们在上面讲过的,有可能publish若干次后才调用process方法。
    与此类似,在doInBackground完成后,SwingWorker会自动调用done方法,下面是我们的实现:
    @Override
    protected void done() {
        if (progressHandle != null) {
            progressHandle.processComplete(contacts);
        }
    }
    客户端如何来使用用SwingWork呢,很简单,只需要新建一个实例并且调用它的execute方法即可,他会自动调用doInBackground方法来完成操作;以下是完整的代码实现:
    
    

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package swingworkertest;

/**
 *
 * @author Administrator
 */
public class BeanContact {
    private String name=null;
    private String sex=null;
    private String phone=null;
    private String email=null;

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the sex
     */
    public String getSex() {
        return sex;
    }

    /**
     * @param sex the sex to set
     */
    public void setSex(String sex) {
        this.sex = sex;
    }

    /**
     * @return the phone
     */
    public String getPhone() {
        return phone;
    }

    /**
     * @param phone the phone to set
     */
    public void setPhone(String phone) {
        this.phone = phone;
    }

    /**
     * @return the email
     */
    public String getEmail() {
        return email;
    }

    /**
     * @param email the email to set
     */
    public void setEmail(String email) {
        this.email = email;
    }
   
}

 

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * Contacts.java
 *
 * Created on 2011-6-25, 10:40:13
 */
package swingworkertest;

import javax.swing.JFileChooser;

/**
 *
 * @author Administrator
 */
public class Contacts extends javax.swing.JFrame {

    /** Creates new form Contacts */
    public Contacts() {
        initComponents();
        handle = new DefaultProgressHandle();
        handle.setTable(jTable1);
        handle.setProgressBar(jProgressBar1);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                         
    private void initComponents() {

        jButton1 = new javax.swing.JButton();
        jTextField1 = new javax.swing.JTextField();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();
        jButton2 = new javax.swing.JButton();
        jProgressBar1 = new javax.swing.JProgressBar();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jButton1.setText("浏览");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jTextField1.setEditable(false);

        jTable1.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {
                "姓名", "性别", "电话", "电子邮件"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }
        });
        jScrollPane1.setViewportView(jTable1);

        jButton2.setText("加载联系人");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 557, Short.MAX_VALUE)
                    .addComponent(jProgressBar1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 557, Short.MAX_VALUE)
                    .addComponent(jButton2, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 557, Short.MAX_VALUE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jButton1, javax.swing.GroupLayout.DEFAULT_SIZE, 97, Short.MAX_VALUE)
                        .addGap(18, 18, 18)
                        .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 442, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButton1)
                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jButton2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {jButton1, jButton2, jTextField1});

        pack();
    }// </editor-fold>                       

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                        

        ContactsFileFilter filter = new ContactsFileFilter();
       
        JFileChooser chooser = new JFileChooser();
        chooser.setFileFilter(filter);
        int returnVal = chooser.showOpenDialog(null);
        if(returnVal == JFileChooser.APPROVE_OPTION){
            jTextField1.setText(chooser.getSelectedFile().getAbsolutePath());
        }
    }                                       

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                        
        // TODO add your handling code here:
        LoadContactsTask task = new LoadContactsTask(jTextField1.getText());
        task.setProgressHandle(handle);
        task.execute();
    }                                       

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                Contacts contacts = new Contacts();
                contacts.setTitle("Contacts");;
                contacts.setVisible(true);
            }
        });
    }
    DefaultProgressHandle handle = null;
    // Variables declaration - do not modify                    
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JProgressBar jProgressBar1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    private javax.swing.JTextField jTextField1;
    // End of variables declaration                  
}

 

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package swingworkertest;

import java.io.File;
import javax.swing.filechooser.FileFilter;

/**
 *
 * @author Administrator
 */
public class ContactsFileFilter extends FileFilter{

    public boolean accept(File pathname) {
        if(pathname.isDirectory()){
            return true;
        }else{
            return pathname.getName().endsWith(".cff");
        }
    }

    @Override
    public String getDescription() {
        return "Text Files";
    }
   
}

 

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package swingworkertest;

import java.util.List;
import javax.swing.JProgressBar;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

/**
 *
 * @author Administrator
 */
public class DefaultProgressHandle implements IProgressHandle {

    private JTable table = null;
    private JProgressBar progressBar = null;

    public void processInProgress(List<BeanContact> contacts, int progress) {
        DefaultTableModel model = (DefaultTableModel) table.getModel();
        for (BeanContact contact : contacts) {
            String[] strArray = {contact.getName(), contact.getSex(), contact.getPhone(), contact.getEmail()};
            model.addRow(strArray);
        }
        progressBar.setValue(progress);
    }

    public void processComplete(List<BeanContact> contacts) {
        progressBar.setValue(progressBar.getMaximum());
    }

    /**
     * @param table the table to set
     */
    public void setTable(JTable table) {
        this.table = table;
    }

    /**
     * @param progressBar the progressBar to set
     */
    public void setProgressBar(JProgressBar progressBar) {
        this.progressBar = progressBar;
    }
}

 

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package swingworkertest;

import java.util.List;

/**
 *
 * @author Administrator
 */
public interface IProgressHandle {
    public abstract void processInProgress(List<BeanContact> contacts,int progress);
    public abstract void processComplete(List<BeanContact> contacts);
}

 

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package swingworkertest;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingWorker;

/**
 *
 * @author Administrator
 */
public class LoadContactsTask extends SwingWorker<List<BeanContact>, BeanContact> {

    private String fileName = null;
    private IProgressHandle progressHandle = null;
    private List<BeanContact> contacts = null;
    private int lineCnt = 0;

    public LoadContactsTask(String fileName) {
        this.fileName = fileName;
        contacts = new ArrayList<BeanContact>();
    }

    @Override
    protected List<BeanContact> doInBackground() throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader("c:/contacts.cff"));
        String line = null;
        while ((line = reader.readLine()) != null) {
            String[] strContacts = line.split(",");
            BeanContact contact = new BeanContact();
            contact.setName(strContacts[0]);
            contact.setSex(strContacts[1]);
            contact.setPhone(strContacts[2]);
            contact.setEmail(strContacts[3]);

            lineCnt++;
            publish(contact);
            contacts.add(contact);
           
            Thread.sleep(100);
        }
        return contacts;
    }

    /**
     * @param progressHandle the progressHandle to set
     */
    public void setProgressHandle(IProgressHandle progressHandle) {
        this.progressHandle = progressHandle;
    }

    @Override
    protected void process(List<BeanContact> chunks) {
        if (progressHandle != null) {
            progressHandle.processInProgress(chunks, lineCnt * 100 / 10000);
        }
    }

    @Override
    protected void done() {
        if (progressHandle != null) {
            progressHandle.processComplete(contacts);
        }
    }
}

 

分享到:
评论

相关推荐

    Java swing 完全完整实例

    这个实例集可能会涵盖上述所有知识点,甚至包括高级主题如Swing worker线程用于在后台执行任务,避免阻塞UI,以及JTable和JTree等用于显示表格和树状数据的组件。通过深入学习这些实例,开发者可以提升自己在Java ...

    Java+Swing图形界面开发与案例详解》实例代码

    5. **Swing入门-第七讲源码**:可能涉及Swing的高级特性,如Swing Worker,用于在后台线程执行耗时任务,避免阻塞UI。此外,也可能讲解组件的状态管理,如JCheckBox、JRadioButton和ButtonGroup。 6. **Swing入门-...

    Swing教程Swing教程下载

    7. **Swing worker线程**:Swing不是线程安全的,因此在进行耗时操作时,如网络请求或数据库操作,应使用SwingWorker来避免阻塞事件调度线程,保持用户界面的响应性。 8. **国际化与本地化**:Swing支持多语言应用...

    java swing 学习教程

    7. **Swing worker线程** - 为了防止UI线程阻塞,Swing引入了SwingWorker,用于在后台线程执行耗时任务,然后将结果传递回主线程更新界面。 8. **对话框(Dialogs)** - JOptionPane 提供了标准的对话框,如消息...

    java swing

    11. **Swing worker线程**: - Swing不是线程安全的,因此需要使用SwingWorker来执行耗时任务,避免阻塞用户界面。 通过学习以上知识点,并结合提供的源码,你将能够创建一个完整的Java Swing应用,包括具有选项卡...

    Java进度条程序

    在这个特定的示例中,`TestSwingWorker`可能是一个使用了Swing Worker类的程序,这是Java Swing库提供的一个工具,用于在后台执行耗时任务并同时更新UI。 Swing Worker是Java Swing中用于在后台线程执行计算并在...

    Swing线程的深入理解和SwingWorker基础知识介绍

    在本文中,我们将深入探讨Swing线程的理解和SwingWorker基础知识,并通过实例代码演示如何正确地使用Swing线程来解决常见的问题。 Swing线程的理解 Swing线程是Java中一个特殊的线程,用于处理图形用户界面的事件...

    Java Swing CRUD.zip

    总之,Java Swing CRUD应用是Java桌面开发中常见的实践,它涵盖了基础的数据库操作和GUI设计,是学习Java GUI编程和数据库连接的重要实例。通过熟练掌握这些知识,开发者能够创建功能完备的桌面数据管理应用。

    swing不确定进度条

    在Java编程环境中,Swing库提供了...以上是关于"Swing不确定进度条"的知识点介绍,希望对你理解如何在Java Swing应用程序中使用不确定进度条有所帮助。在实际开发中,可以根据具体需求进行调整和优化,提升用户体验。

    Java_2_GUI_Fundamentals_with_Swing.rar_Fundamentals_java gui

    Java图形用户界面(GUI)是Java编程...这个教程会通过实例讲解这些概念,帮助你从基础开始,逐步掌握使用Swing创建高效、易用的Java GUI应用的技能。通过深入学习和实践,你可以构建出满足各种业务需求的桌面应用程序。

    基于java swing开发的桌面GUI程序-快递管理系统

    10. **Swing worker线程**:在GUI程序中,为了避免阻塞主线程(事件调度线程),可以使用SwingWorker进行耗时操作,如数据库查询或网络通信。 11. **国际化与本地化**:对于一个全面的管理系统,可能会考虑支持多...

    swing 下载文件时的进度条

    - 创建一个后台线程(`SwingWorker`实例),负责从URL读取数据并写入本地文件。 - 在读取过程中,定期计算已下载的字节数与总字节数的比例,更新进度条的值。 - 当下载完成时,通知用户并关闭相关流。 6. **事件...

    swing自定义 button

    `JButton`是`AbstractButton`类的实例,可以通过传递字符串或图标作为按钮的显示文本或图像来创建。例如: ```java JButton button = new JButton("点击我"); ``` ### 2. 添加事件监听器 为了响应按钮的点击事件...

    Java图像编程实例库

    通过这个"Java图像编程实例库",开发者不仅可以学习到基础的GUI编程技巧,还能深入理解Java2D和Swing等技术,为开发出富有视觉吸引力的应用程序打下坚实的基础。对于初学者来说,通过实践这些实例,可以快速上手并...

    基于Java+Swing实现管道工人游戏(源码+Lw+视频齐全).rar

    总的来说,基于Java+Swing实现的管道工人游戏是一个集教育与娱乐于一体的作品,它展示了Java语言在桌面应用开发中的强大能力,同时也提供了一个实践和学习Java编程的实例。无论是对Java初学者还是有经验的开发者,都...

    Java编程特效100例

    11. **Swing Worker和JavaFX Task**:为了在界面操作中避免阻塞主线程,可以使用Swing Worker(针对Swing)或JavaFX Task(针对JavaFX)。例子可能展示了如何在后台执行耗时任务,并更新界面状态。 12. **数据绑定*...

    Java 2程序设计技能百练

    高级界面篇则关注更高级的界面技巧,如自定义组件的创建、国际化和本地化支持、以及Swing的高级特性,如JTable、JTree和JList的使用,以及Swing worker线程,用于在后台执行耗时任务,保持界面的响应性。 数据库...

    Java编程

    8. **Swing Worker**:使用此类来实现后台线程处理,避免阻塞用户界面,提高应用性能。 9. **外观和感觉(LookAndFeel)**:定制或改变应用程序的视觉风格,使其适应不同操作系统或用户偏好。 10. **JTable和JTree**...

    Java的Swing编程中使用SwingWorker线程模式及顶层容器

    SwingWorker是Swing提供的一种机制,用于在后台线程(也称为工作线程或worker threads)中执行耗时任务,而不阻塞EDT。它允许在后台线程执行计算,同时在主线程更新UI,保持界面的响应性。SwingWorker支持两种类型...

Global site tag (gtag.js) - Google Analytics