怎么正确的使用SWT进度条

来源:互联网 发布:手机接收验证码 php 编辑:程序博客网 时间:2024/04/29 07:12

怎么正确的使用SWT进度条

摘要
使用进度条监视器并不像看起来的那么简单,在使用时很容易犯错。这取决于各种因素,像底层实现,显示方式,是否被设定固定数目的工作条目,是否使用了SubProgressMonitor 嵌套,等等。结果可能是完全没问题,也可能是 让人挠头,或者彻底不可用。

本文将指导怎样有效的使用进度条监视器。

使用进度条监视器

在许多简单的惯例中,有一条是“只知道所知道的,并且仅限于此”。这就是说,不能假设完全了解你所不知道的事情。就像,你不能想当然的认为进度条监视器就是你在IDE中看到的那些图片样子的东西。

IProgressMonitor

通常,所有的进度条操作都是通过IProgressMonitor接口.进度条监视器具有4中状态,通过接口只可以测到一种状态(当监视器被取消时)。状态的改变是通过如下方法的作用: beginTask(), done() and setCanceled().
  • PRISTINE
    IProgressMonitor实例被初始化之后,方法beginTask() 被调用之前的状态。
  • IN_USE
    方法beginTask()被调用之后的状态,这里要注意 beginTask()只能被调用一次,
  • FINISHED
    done()被调用之后的状态, 它也只能调用一次,并且只能在 beginTask()之后调用。
  • CANCELED
    进度条被取消之后的状态。

要以以下的模式使用进度条:
monitor = ?  // 获取进度条实例,现在处于 pristine 状态
try
{
monitor.beginTask(?
// 执行工作任务
}
finally
{
monitor.done()
}
The 一定到保证 done() 最后被执行。

子任务用代理使用进度条监视器

beginTask()被调用不要多于一次,这种错误经常发生。进度条被传给子任务,子任务没有意识到进度条已经执行了beginTask(),还是按照规定的契约,执行beginTask()方法。除非子任务对此了解,否则传递进度条实例是十分错误的。一般情况下,接受到进度条实例的代码应该假设此实例自己会遵守beginTask()/done()契约。如果子任务也需要进度条,就应该使用SubProgressMonitor作为代理,封装传入的进度条实例。

如下为样例:
monitor = ?// 获取进度条实例

try
{
monitor.beginTask(?
// 执行任务
?BR>// 创建一个子任务
someThing.doWork(new SubProgressMonitor(monitor,?)
// // 创建右一个子任务
anotherThing.doWork(new SubProgressMonitor(monitor,?)
}
finally
{
monitor.done()
}
每一个doWork()调用得到一个新的SubProgressMonitor 实例。

管理条目个数

如果确实不知道确切的条目总数,不要随意猜测数字。如果猜大了,数字会走的很慢,然后突然到达100%;如果猜小了,那么会很快到达终点,并且永远停在那里。没有确切总数的话,填写 IProgressMonitor.UNKNOWN就可以了。

怎样调用 beginTask()worked()

通常你可以通过两种方式得出你究竟要处理多少条目:一是调用许多不同的方法来得到结果,二是在一个集合中为每一个实例调用同一个方法。每种方式你都可以知道总的条目数(方法的个数或集合的大小)。

你应该将按比例测量出你的总数。如果总数是3 (每个条目工作为worked(1)),你可以把比例定为1000,总数为3000, (每个条目工作为worked(1000) ). 当你要通过SubProgressMonitor将工作传递到子任务中,就要应用这种方式。因为子任务内部的总数和外部是不同的,也许比你定的总数大许多。你要给它们一些缓冲润滑的空间。这样可以避免进度条执行时视觉上的便扭。

样例:
monitor = ?// 取到进度条监视器
int total = 3 // 总数为3
try
{
monitor.beginTask(total)

// 条目1
this.doPart1()
monitor.worked(1)

// 条目 2
this.doPart2()
monitor.worked(1)

// 条目 3
this.doPart3()
monitor.worked(1)
}
finally
{
monitor.done()
}
这里没有必要按比例放大,也没有集合动态计算。

更详细的样例:
monitor = ?
int total = thingyList.size() * 3 + 2
try
{
monitor.beginTask(total)

// 条目 1
this.doBeforeAllThingies()
monitor.worked(1)

// 条目 2 to 倒数第二个
for (Thingy t : thingyList)
{
t.doThisFirst()
monitor.worked(1)
t.thenDoThat()
monitor.worked(1)
t.lastlyDoThis()
monitor.worked(1)
}

// 最后一条
this.doAfterAllThingies()
monitor.worked(1)
}
finally
{
monitor.done()
}

混合使用子任务

在使用子任务的时候,子任务的总数就是分配给它的比例数。
monitor = ?
int scale = 1000
int total = 3
try
{
monitor.beginTask(total * scale)

// item 1
this.doPart1()
monitor.worked(1 * scale)

// item 2
this.doPart2(new SubProgressMonitor(monitor, 1 * scale)) //分配一个条目
monitor.worked(1 * scale) // 这里是不需要的,因为任务的管理有子任务负责

// 条目 3
this.doPart3()
monitor.worked(1 * scale)
}
finally
{
monitor.done()
}
You worked().

Tip 不要将 IProgressMonitor.UNKNOWN 传给创建的 SubProgressMonitor()

子任务进度条的实现只是盲目的使用传入的总数进行计算,当它接受到的是一个负值(IProgressMonitor.UNKNOWN为-1) 它也是按照惯例来进行计算,所以你看到的结果是进度条往回走。 IProgressMonitor.UNKNOWN不能在子任务进度条中使用,但是在父进度条中使用没有这种问题。

取消

上面的例子中,都没有判断进度条是否被取消。在实际使用中,推荐要及时的进行判断。
monitor = ?
try
{
monitor.beginTask(thingyList.size())

for (Thingy t : thingyList)
{
if(monitor.isCanceled())
throw new OperationCanceledException();
t.doSomething()
monitor.worked(1)
}
}
finally
{
monitor.done()
}

The 空进度条

这样可以使调用者不用必须传入monitor,只要输入null 就可以了。
public void doIt(IProgressMonitor monitor)
{

if(monitor == null)
monitor = new NullProgressMonitor();

try
{
monitor.beginTask(thingyList.size())

for (Thingy t : thingyList)
{
if(monitor.isCanceled())
throw new OperationCanceledException();
t.doSomething()
monitor.worked(1)
}
}
finally
{
monitor.done()
}
}

结论

只要遵循这些规则,在使用进度条的时候就不会碰到麻烦。如果不信邪,想当然的用,迟早会出现奇怪的视觉显示,你的客户又要不停的抱怨了。
原创粉丝点击