站内搜索: 请输入搜索关键词
当前页面: 图书首页 > SWT: The Standard Widget Toolkit

22.2 Implementation Notes - SWT: The Standard Widget Toolkit

Previous Section  < Day Day Up >  Next Section

22.2 Implementation Notes

22.2.1 Flexible Layout

The FileExplorer shell uses FormLayout to arrange its children. Initially, the table, the tree, and the sash between them are attached to the tool bar at the top and the status label at the bottom. The View menu allows you to hide the tool bar or status label. This is accomplished by changing the attachment of the table, tree, and sash to be relative to the edge of the shell, then hiding the tool bar or label. For example, here is the code that toggles the visibility of the tool bar.






if (toolItem.getSelection ()) {

    FormData treeData = (FormData) tree.getLayoutData ();

    treeData.top = new FormAttachment (toolBar);

    FormData sashData = (FormData) sash.getLayoutData ();

    sashData.top = new FormAttachment (toolBar);

    FormData tableData = (FormData) table.getLayoutData ();

    tableData.top = new FormAttachment (toolBar);

} else {

    FormData treeData = (FormData) tree.getLayoutData ();

    treeData.top = new FormAttachment (0);

    FormData sashData = (FormData) sash.getLayoutData ();

    sashData.top = new FormAttachment (0);

    FormData tableData = (FormData) table.getLayoutData ();

    tableData.top = new FormAttachment (0);

}

toolBar.setVisible (toolItem.getSelection ());

shell.layout ();


Notice that the selected state of the item is queried to decide whether the tool bar should be shown or hidden. Notice also the explicit call to layout() to cause the appearance to change.

22.2.2 Drag-and-Drop

In SWT, drag-and-drop (we say "D&D") support is implemented using native drag-and-drop facilities. The package that implements this support is org.eclipse.swt.dnd. D&D support is implemented in an application by creating a DragSource for the control that items will be dragged from and a DragTarget for the control they will be dragged to. The example creates a DragSource and a DragTarget for both the table and the tree, allowing items to be moved by dragging them to either control.

Where things start to get interesting, however, is that because the D&D support uses the native facilities, you can also drag files between FileExplorer and the native file browsers on platforms that support this.

Taking the Transfer

To be able to drag files between FileExplorer and native applications, FileExplorer needs to warn the platform that the thing that is being dragged represents a file. In SWT, setting the transfer of the DragSource (using setTransfer()) to an instance of org.eclipse.swt.dnd.FileTransfer does this.[1] Similarly, setting the transfer of a DropTarget to a FileTransfer indicates that the target can accept files from other platform applications.

Subclasses of class org.eclipse.swt.dnd.Transfer describe the format of the item that is being dragged. The predefined transfer types, which map to native types on most platforms, are TextTransfer (plain text), RTFTransfer (rich text), Image-Transfer (images), and FileTransfer (files). You can also define new types of transfers.


[1] Actually, the transfer is set to an array of transfers. This allows multiple versions of the same objects to be dragged from a DragSource or received at a DropTarget. For example, an application might include both text and RTF versions of a text selection.

In the FileExplorer source, the DragSource and DragTarget instances are created by the following methods.

createDragSource(Control control) Associates a DragSource for a FileTransfer with the given control. DragSourceListener is added to the DragSource.

createDropTarget(Control control) Associates a DropTarget for a FileTransfer with the given control. DropTargetListener is added to the DropTarget.

Looking at these methods should provide a good start toward working with the drag-and-drop support.

22.2.3 Application Launching

Most modern operating systems provide support for mapping between identifiers for content types (such as MIME types or file extensions) and the native applications that are capable of manipulating content of those types. In SWT, this application launching support is implemented by the Program class in the package org.eclipse.swt.program. An instance of class Program represents a specific external program that is capable of handling one or more content types. Static methods in class Program are provided that return the available programs and the content types for which there are mappings. The simplest way to use this support is to launch the content file.

launch(String fileName) This static Program method attempts to find an external program that is capable of handling the file named by the argument and, if one is found, causes it to be started by the operating system, with the file name passed to it as an argument. If a compatible program can be successfully started, this method returns true. If a program cannot be found or if one is found but fails to start, false is returned. As a special case, if the file name describes a file that can itself be executed by the operating system (for example, an .EXE file on Microsoft Windows), the file is launched directly.

The FileExplorer example launches the selected file when the table receives a DefaultSelection event. The handler for this is implemented in the following method.

tableDefaultSelected(TableItem[ ] items) For each item that represents a directory, the matching entry in the tree is expanded (or collapsed if it was already expanded). For items that represent files, the file is launched.

The code to launch the file is trivial and looks like this.






String name = file.getAbsolutePath ();

if (!Program.launch (name)) {

    MessageBox dialog =

        new MessageBox (shell, SWT.ICON_ERROR | SWT.OK);

    dialog.setText (shell.getText ());

    dialog.setMessage (

        getMessage (

            "Could not launch \"{0}\".",

            new Object [] {name}));

    dialog.open ();

}


This is the simplest way to use the Program class. Class Program provides other capabilities that we have not included here, and it is worth looking at its API if you get a chance. For example, you can use the findProgram() method to return an instance of Program, then ask this program for an image to display. This would allow you, for example, to show a specific image for each type of file that is shown in the table.

22.2.4 Multithreading

The FileExplorer application uses multithreading to allow different file operations to run in parallel. These operations include deleting a file or hierarchy, copying a file or hierarchy, and filling the table in the background. These operations are described by a hierarchy of classes under the abstract class FileOperation.[2]

[2] FileOperation is not intended to be a general-purpose "operation" class, but you could implement a more general version if this were required.

FileOperation always runs in a separate thread. The user interface will wait until either the operation completes or the expectedTime (in FileOperation) has passed. The user interface then calls the isDone method to see whether the operation has completed. This allows us to support both operations that complete quickly (without notification in the user interface) and longer running operations that display a progress dialog.

Progress is reported to the user interface by calling the following method.

check(File file, boolean increment) Called by the FileOperation as it does work. The method should be called once with increment set to true each time a file is about to be processed, but it can be called an arbitrary number of times with increment set to false. The user interface uses this information and the aforementioned expectedTime value to display and update a progress dialog.

Look at the code for DeleteOperation to see a simple operation.

22.2.5 In-Place Editing

Native tables and trees sometimes provide built-in support for directly editing the contents of an item that they are displaying. This support is typically quite limited. Because this support was either not available or not sufficiently powerful across all platforms, the SWT implementers chose to provide a separate, platform-neutral, in-place editing mechanism, rather than attempt to manifest the native capabilities.[3] The classes that provide this capability are found in the org.eclipse.swt.custom package. The class ControlEditor has subclasses TreeEditor and TableEditor[4] that allow an arbitrary control to be laid out "on top of" a field in a tree or table. Application code can use this to build an in-place editor by doing the following.

[3] This decision may be revisited in the future. Some platforms dictate a certain look for in-place editing.

[4] And class TableTreeEditor, which provides these capabilities for org.eclipse.swt.custom.TableTree instances.

  1. Creating an editor for the field to be edited.

  2. Setting the editor control to be one that is appropriate for the editing task. This could be a text, a combo, a button to launch a separate editing window, or even a custom, application-specific control (such as a "color picker").

  3. Setting the value that is displayed by the control to the value in the field.

  4. Running an event loop until a new value has been entered.

  5. Setting the new value back into the field.

Depending on the application, you may also have to disable accelerators for the application menu and tool bar to prevent unexpected behavior.

In the FileExplorer example, renaming of files and directories is implemented using in-place editing. The code that does this is found in the following.

rename(ControlEditor editor, Composite composite, Item item, Rectangle bounds) Given an editor for the item, a composite (either Table or Tree), the item to be edited, and the initial bounds for the editor, use the editor to rename the item.

This method is called from either rename(TreeItem item) or rename(TableItem item). These methods simply construct an instance of the appropriate editor class, then call the above method to do the work.

22.2.6 Other Design Notes

Here are some other areas of the code that are worth looking at.

Enabling the ToolBar Icons The paste icon in the tool bar needs to be enabled whenever there is something in the platform clipboard that can be pasted into the current directory in FileExplorer. Because the contents of the clipboard can be changed by other applications, the simplest way to do this is to poll the clipboard at regular intervals. In FileExplorer, the createToolBarTimer() method does this by setting up a timerExec to check the clipboard contents every 250 milliseconds. This pattern is quite common (it is used by the Microsoft Office applications, for example) and does not cause significant overhead as long as the polling frequency is not too high.

Updating Tree and Table Each time the above polling loop runs, if an operation is in progress, Table and Tree are checked to see whether they need to be updated. This has the effect of incrementally filling in the table and tree as the operation is running.

Retargeting the Menus Several actions, such as Rename in the Edit menu, always apply to the selected file or directory. To implement this behavior, the slot toolBarTarget is set to either Tree or Table whenever they are given focus. See the method FileExplorer.getSelectedItems().

    Previous Section  < Day Day Up >  Next Section