|
Cytoscape 2.8.0 API | |||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
---|---|
Haltable | A hook for requesting that a running process be halted. |
Task | Represents a task that can be terminated prematurely by the same
entity that started the task - tasks are started with
Task.run() and tasks are terminated prematurely
[and asynchronously] with Task.halt() . |
TaskMonitor | Interface for monitoring the progress of a task. |
Cytoscape Task Framework.
Overview |
The task package is a convenient framework for building, running and visually monitoring long-term tasks within Cytoscape.
The main goal of the task package is to improve the perceived performance of Cytoscape:
Often the subjective speed of your application has little to do with how quickly it actually executes its code. To the user, an application that starts up rapidly, repaints quickly, and provides continuous feedback feels "snappier" than an application that just "hangs up" while it churns through its work. [1]
By using the task framework, core developers and plugin developers can provide continuous feedback to the end-user, and we can all make Cytoscape a "snappier" application.
Basic Definitions |
Task: A Task is any
long-running process that can be canceled by the end-user.
A long-running task may take several seconds or several
minutes to complete. For example, retrieving data from a remote database,
or running a layout algorithm, are all examples of tasks.
For the specific purposes of the task
framework, we define a task as any class which implements the
Task
interface.
JTask: JTask
is Swing dialog box
provided by the task framework. It mainly includes a progress bar for
monitoring tasks, but it can also be configured to show additional details,
such as total time elapsed, estimated time remaining, etc. In the event
that a task encounters an error and ends prematurely, the JTask dialog
box will also present a nicely formatted error message to the user.
Advantages of a Common Task Framework |
If you are a core developer or a plugin writer, you should consider using the task framework for any long-term processes that you build. You could, of course just build your own task framework and your own progress bar dialog box, but there are certain advantages to using the task framework:
How to Create a New Task (with Sample Code) |
To create a new task, your task code must impelement the
Task
interface. The interface defines
four methods:
run()
: executes the task.
halt():
requests that the task be halted.
getTitle():
returns a human readable description of
the task.
setTaskMonitor():
specifies a monitoring agent that will receive progress reports.
As the task proceeds, it can make various calls to the
TaskMonitor
.
For example, the task can report percentage of work completed or
report an error message to the end-user.
Creating a new task is best illustrated with an example. The code
below defines a simple task for counting from 0 to max
,
and is defined in SampleTask
:
SampleTask.java |
---|
package cytoscape.task.sample; import cytoscape.task.Task; import cytoscape.task.TaskMonitor; import java.io.IOException; /** * Sample Task, used to illustrate the Task Framework. * This tasks counts from 0 to maxValue. */ public class SampleTask implements Task { private static final int MIN_VALUE = 0; private int maxValue; private long countDelay; private TaskMonitor taskMonitor = null; private boolean interrupted = false; private int exceptionIndex = Integer.MAX_VALUE; /** * Constructor. * * @param max Max Count Value. * @param countDelay Delay between each count (in milliseconds). */ public SampleTask(int max, long countDelay) { this.maxValue = max; this.countDelay = countDelay; } /** * Constructor. * Provides a test of Exception Handling. * The Task will throw a NullPointerException when it reaches the * exceptionIndex value. * * @param max Max Count Value. * @param countDelay Delay between each count (in milliseconds). * @param exceptionIndex The Task will throw a NullPointerException * when it reaches the exceptionIndex * value. */ public SampleTask(int max, long countDelay, int exceptionIndex) { this.maxValue = max; this.countDelay = countDelay; this.exceptionIndex = exceptionIndex; } /** * Run the Task. */ public void run() { if (taskMonitor == null) { throw new IllegalStateException("Task Monitor is not set."); } try { // Count from 0 to maxValue with a countDelay // Counting from 0..100 with a 50 ms delay should take ~5 seconds // Make sure to check the interrupt flag. int i = MIN_VALUE; while (i <= maxValue && !interrupted) { // Calculate Percentage. This must be a value between 0..100. int percentComplete = (int) (((double) i / maxValue) * 100); // Estimate Time Remaining long totalTime = maxValue * countDelay; long timeElapsed = i * countDelay; long timeRemaining = totalTime - timeElapsed; // Update the Task Monitor. // This automatically updates the UI Component w/ progress bar. if (taskMonitor != null) { taskMonitor.setPercentCompleted(percentComplete); taskMonitor.setStatus("Counting: " + i); taskMonitor.setEstimatedTimeRemaining(timeRemaining); } // Illustrates how to Handle/Report Exceptions within a Task. // When this IOException is thrown, the task will stop // execution and report the error to the Task Monitor. // This causes the UI Component to automatically display // an error dialog box to the end-user. if (i == this.exceptionIndex) { throw new IOException("This is a Fake IO Exception"); } // Artificial Delay Thread.sleep(countDelay); i++; } } catch (InterruptedException e) { taskMonitor.setException(e, "Counting cancelled"); } catch (IOException e) { taskMonitor.setException(e, "Counting aborted by fake exception"); } } /** * Non-blocking call to interrupt the task. */ public void halt() { this.interrupted = true; } /** * Sets the Task Monitor. * * @param taskMonitor TaskMonitor Object. */ public void setTaskMonitor(TaskMonitor taskMonitor) { if (this.taskMonitor != null) { throw new IllegalStateException("Task Monitor is already set."); } this.taskMonitor = taskMonitor; } /** * Gets the Task Title. * * @return human readable task title. */ public String getTitle() { return new String("Counting Task"); } } |
Note: If your task cannot accurately report percentage of work complete, use TaskMonitor setPercentCompleted(-1). This will cause the JTask UI component to display the appropriate indeterminate progress bar. |
Tips for Creating Swing-Safe Tasks |
According to Sun:
"Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread." [2]
If your task must modify a UI component, you are advised to use one of the
javax.swing.SwingUtilities
:
invokeLater()
:
Requests that some code be executed in the
event-dispatching thread. This method returns immediately, without waiting
for the code to execute.
invokeAndWait()
:
Acts like invokeLater(), except that this method waits for the code to
execute. As a rule, you should use invokeLater() instead of this method.
How to Run a Task via the TaskManager (with Sample Code) |
Once you have created a Task, you can run it via the
TaskManager
utility class.
This class will automatically create a new thread for your task, start the
thread, and pop-open a JTask dialog box for monitoring the task.
Here is a complete example, taken from
RunBareBones
.
RunBareBones.java |
---|
package cytoscape.task.sample; import cytoscape.task.Task; import cytoscape.task.util.TaskManager; import cytoscape.task.ui.JTaskConfig; import cytoscape.task.ui.JTask; /** * Illustrates How to Execute a Sample Task via the TaskManager. */ public class RunBareBones { /** * Executes the Sample Task. * * @param args Command Line Arguments. */ public static void main(String[] args) { // Create a Sample Task Task task = new SampleTask (100, 100); // Configure JTask JTaskConfig config = new JTaskConfig(); // Show Cancel/Close Buttons config.displayUserButtons(true); // Execute Task via TaskManager // This automatically pops-open a JTask Dialog Box. // This method will block until the JTask Dialog Box is disposed. boolean success = TaskManager.executeTask(task, config); } } |
How to Customize the JTask Dialog Box (with Screen Shots) |
By default, the JTask
Dialog box will look
like this (as seen on Mac
OS X):
However, you can customize the look and feel of JTask via
JTaskConfig
. For example, here
is a fully customized JTask Dialog box. It now shows a status message,
time elapsed, and estimated time remaining. It also provides cancel/
close buttons.
Sample screenshots of error messages provided to users are provided below:
References |
[1]
Optimizing Perceived Speed, MSDN Network.
[2]
Threads and Swing, Sun Microsystems, Inc.
|
Cytoscape 2.8.0 API | |||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |