科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道实例分析Java SE 6.0新增功能(2)

实例分析Java SE 6.0新增功能(2)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

Java 6.0标准版(Mustang)包含了大量使Java开发更为容易的特性。在本文中,我们将讨论通过部分新特性来帮助你实现如下功能:

作者:朱先忠编译 来源:IT专家网 2008年5月5日

关键字: 功能 分析 Java SE 6 java

  • 评论
  • 分享微博
  • 分享邮件
下面是一个选项卡面板示例源代码-它允许你从一个JTabbedPane中动态地添加和删除选项卡。注意,在这个例子中我们创建了一个Jpanel,它包含两个组件:一个位于面板左边(BorderLayout.WEST)的JLabel和一个位于面板右边(BorderLayout.EAST)的带有一个ImageIcon的按钮。这里所用的图形是一个10x10像素大小的gif文件-它包含了一个小X。为了确保按钮的尺寸小一些,我们把它的尺寸重置为图标的宽度和高度各自加上2个像素。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TabbedPaneExample implements ActionListener {
 private JFrame frame;
 private JTabbedPane tabbedPane;
 private JButton addTabButton;
 private ImageIcon closeXIcon;
 private Dimension closeButtonSize;
 private int tabCounter = 0;
 public TabbedPaneExample() {
  //创建选项卡面板
  tabbedPane = new JTabbedPane();
  //创建一个按钮-用户可用来添加一个选项卡到选项卡面板
  addTabButton = new JButton("Add Tab");
  addTabButton.addActionListener(this);
  //创建一个框架来包含这个选项卡面板
  frame = new JFrame();
  //创建一个图像图标'X'以实现在每一个选项卡上的关闭功能。加载的gif是一个10x10图形(非黑色部分是透明的)
  closeXIcon = new ImageIcon("C:/CloseX.gif");
  //创建一个Dimension用来调整close按钮的大小
  closeButtonSize = new Dimension(
   closeXIcon.getIconWidth()+2,
   closeXIcon.getIconHeight()+2);
   //所选项卡面板添加到图形中央,把"Add Tab"按钮置于南面。然后包装它,调整其大小并显示它。
  frame.add(tabbedPane, BorderLayout.CENTER);
  frame.add(addTabButton, BorderLayout.SOUTH);
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.pack();
  frame.setMinimumSize(new Dimension(300, 300));
  frame.setVisible(true);
 }
 public void actionPerformed(ActionEvent e) {
  final JPanel content = new JPanel();
  //创建一个描述该选项卡的面板并确保它是透明的
  JPanel tab = new JPanel();
  tab.setOpaque(false);
  //为该选项卡创建一个标签和一个Close按钮。一定要
  //把它的尺寸设置为几乎该图标的大小,并且
  //创建一个行为听取器-它将定位该选项卡并且从选项卡面板上删除它
  JLabel tabLabel = new JLabel("Tab " + (++tabCounter));
  JButton tabCloseButton = new JButton(closeXIcon);
  tabCloseButton.setPreferredSize(closeButtonSize);
  tabCloseButton.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent e) {
    int closeTabNumber = tabbedPane.indexOfComponent(content);
    tabbedPane.removeTabAt(closeTabNumber);
   }
  });
  tab.add(tabLabel, BorderLayout.WEST);
  tab.add(tabCloseButton, BorderLayout.EAST);
  //把该选项卡添加到选项卡面板。注意,
  //第一个参数(它正常是一个描述选项卡标题的String
  //),为null.
  tabbedPane.addTab(null, content);
  //不是在选项卡上使用String/Icon的结合,
  //而是使用我们的面板。
  tabbedPane.setTabComponentAt(tabbedPane.getTabCount()-1, tab);
 }
 public static void main(String[] args) {
  TabbedPaneExample main = new TabbedPaneExample();
 }
}

  结果显示于图1中。

  图1.一个把多个JComponent用作选项卡的JTabbedPane

  注意,Alexander Potochkin的博客中提供了另外一种不同的方法,它子类化JButton-重载paintComponent()并且画出它自己的("X")。如果你不想使用你的代码发布一个gif文件,那么使用这种更为复杂的方法是非常有用的。

四、 SwingWorker现在包含到Mustang中

  大多数Swing程序员知道,无论什么时候编写事件驱动的代码,例如当一个按钮按下时调用ActionListener,都需要快速处理事件。你永远不需要花费比你必须处理事件驱动的线程更多的时间,否则,你的Swing GUI将成为不可响应并且不能有效地重绘它自己。在事件调度线程中实现一项较大的任务经常意味着你要从事件调度线程中"剔除"一个独立工作者线程并且让该线程运行于后台。这样以来,当使用Swing编写一个多线程的应用程序时,程序员需要牢记下面两条规则:

  •   · 如果把耗时的任务安排到一个调度线程中,那么这有可能导致应用程序具有不可响应性。因此,这样的任务应该用一个工作者线程来专门实现。
  •   · 对Swing组件的更新应该仅安排给一个事件调度线程来完成。

  因为这意味着,至少有两个线程在同时运行,因此创建一个处理线程间通讯的类是很有帮助的。有一个消息是,最新的Mustang发行版本中加入了对SwingWorker类(它是前一段时间Swing程序员使用的一种流行的解决方案)的支持。

  下面是来自于Javadoc的SwingWorker的正式声明。

public abstract class SwingWorker<T,V> extends Object
implements RunnableFuture<T>

  注意,这里的声明包含了两个泛型类型变量:T和V。如果你还不熟悉泛型类型变量的话,那么你可以先读一下有关泛型的基础知识,这是在J2SE 5.0中引入的一种特性。下面是定义:

  •   · T:由这个SwingWorker的doInBackground()和get()方法返回的结果类型
  •   · V:被这个SwingWorker的publish()和process()方法用来执行中间结果的类型

  一会之后,我们再讨论这些方法。然而,首先,让我们介绍一下SwingWorker中所使用的线程架构。这里援引Javadoc的描述:在一个SwingWorker的生命周期中共包含三个线程:

  •   · 当前线程:execute()方法。它调度SwingWorker在一个工作者线程上的执行并且立即返回。你可以使用两个get()方法之一来等待SwingWorker完成。
  •   · 工作者线程:这个线程上调用doInBackground()方法。这正是所有后台活动发生的地方。为了通知PropertyChangeListeners关于绑定属性的变化,你可以使用firePropertyChange和getPropertyChangeSupport()方法。默认情况下,有两个绑定属性可用-state和progress。
  •   · 事件调度线程:所有的Swing相关的活动都发生在这种线程中。SwingWorker调用process()和done()方法并且通知这个线程上的任何PropertyChangeListeners。

  典型地,你在其上实例化SwingWorker子类的当前线程是事件调度线程。这个SwingWorker通常响应下列一些事件:

  •   1. execute()方法被调用或运行于这个事件调度线程上。
  •   2. SwingWorker通知任何PropertyChangeListeners其状态已经变为SwingWorker.StateValue.STARTED。
  •   3. doInBackground()方法在工作者线程上执行。
  •   4. 一旦doInBackground()方法完成,即在当前线程上执行done()方法。
  •   5. SwingWorker通知任何PropertyChangeListeners其状态已经变为SwingWorker.StateValue.DONE。

  当在doInBackground()方法中时,你可以设置一个整型的progress属性-它使用下列方法指示工作者线程的当前进度:

  protected void setProgress(int progress);

  一旦调用这个方法,SwingWorker就向所有的已经登记的听者激发一个属性事件来通知它们已经得到更新的进度值。

  你可以设置或添加工作者线程的最后结果-通过使用下面两个方法之一:

protected void process(V... chunks);
protected void publish(V... chunks);

  第二个方法,publish(),将使用一些中间类型V的一些可变个数的对象并且把它们发送到process()方法中进行处理。典型情况下,你将从doInBackground()线程中调用process()方法。这个process()方法应该总是被重载以接收输入的V参数并且把这些中间对象以某种形式连接成一个T类型。当然,至于process()方法如何实现这一任务要依赖于参数类型-它在你的SwingWorker子类中指定。

  同时,在当前线程中,你可以调用两个get()方法之一来检索工作者线程的结果。第一个get()方法,在工作者线程完成其任务之前将会无限地阻塞。第二个方法在检索已经被处理的结果宽之前将阻塞一段指定的时间。

public T get();
public T get(long timeout,TimeUnit unit);

  如果你希望取消这个工作者线程,那么在它完成执行之前,你可以从当前线程中调用cancel()方法。

  public final boolean cancel(boolean mayInterruptIfRunning)

  这里的mayInterruptIfRunning参数指定,在试图停止这项任务时是否执行该任务的线程应该被中断。注意,调用cancel()方法将失败-如果该任务已经完成,如果该任务已经被取消或如果它因某些理由可能无法被取消。然而,如果该方法调用返回true并且当调用cancel()方法时这项任务还没有开始,那么SwingWorker永远不应该执行。

  五、 结论

  尽管本文中介绍的这些特征基本上相互独立,但是它们的确代表Mustang开发团队希望满足Java开发社区提出的一小部分实现请求。特别是,当创建Swing应用程序时,学习使用SwingWorker类是必须的-它可以把程序员从复杂的GUI线程问题中解脱出来。记住,和往常一样,这些特征在最终成为Java SE 6的最后发行版本之前要征得JSR 270专家组的同意。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章