Eclipse

[펌] [ SWT ] Standard Widget Toolkit

_침묵_ 2005. 1. 20. 04:17

:: Section One ::

 

url :http://eclipsewiki.swiki.net/2

 

 

SWT/JFace

 
SWT/JFace

What are SWT and JFace?

 

The Standard Widget Toolkit (SWT) is a component of Eclipse that is designed to provide efficient, portable access to the user-interface facilities of the operating systems on which it is implemented. SWT does not depend on AWT or JFC (Swing). SWT does not depend on other parts of Eclipse and can be used within Eclipse or by itself in other applications.

SWT는 운영체제의 사용자 인터페이스 요소들에 대한 효율적이고 이식성있는 접속을 제공하기 위해서 고안된 이클립스의 컴포넌트이다. SWT 는 AWT 나 JFC(Swing) 에 의존하지 않는다. 또한 이클립스의 다른 부분에 의존하지 않고 이클립스 내에서 사용되거나 또는 다른 애플리케이션에서 단독으로 사용될 수 있다.

JFace is a GUI framework built on top of SWT that provides extended support for dialogs and wizards. In addition to SWT, JFace depends on a small set of base Eclipse plugins which can be extracted from Eclipse for use in standalone applications.
JFace 는 대화창이나 마법사기능을 확장해서 지원하는 SWT 의 위에 지어진 GUI framework 이다.SWT 외에도 JFace 는 단일 애플리케이션에서 사용되기 위해서 이클립스로부터 얻을 수 있는 일군의 플러그인들에 의존한다.

 

자세한 내용은http://eclipsewiki.swiki.net/2  에서 직접 확인 가능함.

 

 

 

:: Section Two ::

 

url :http://www-106.ibm.com/developerworks/opensource/library/os-ecgui1/

pdf :ftp://www6.software.ibm.com/software/developer/library/os-ecgui1.pdf 

 

Using the Eclipse GUI outside the Eclipse

Workbench, Part 1:Using JFace and SWT in

stand-alone mode

 

 

Building a simple file explorer application

"간단한 파일탐색 프로그램 만들기"

Level: Intermediate(중급용)

Adrian Van Emmenis(van@vanemmenis.com)
Independent consultant
23 January 2003

Although the Eclipse GUI components (JFace and SWT) are often used inside the Eclipse Workbench, they were designed as self-contained frameworks in their own right. Even outside the Eclipse Workbench, JFace's pluggable design still allows you to develop sophisticated GUIs with surprisingly little code. In this series of three articles, A. O. Van Emmenis shows how to build just such a stand-alone application. Part 1 starts with a "Hello, World" example and builds, step by step, into a (very) simple file explorer. He introduces some of the major JFace classes (and a few SWT widgets), along with some tips, tricks, and design issues.

이클립스 GUI 컴포넌트(JFace and SWT)들이 종종 이클립스 안에서 사용되지만 이것들은 GUI 컴포넌트들을 모두 독립적으로 포함하고 있는 프레임워크로서 디자인되었다. 이클립스 외부에서도 끼웠다 뺐다 할 수 있는 Face 의 설계를 통해서 놀라울 정도로 적은양의 코드로 정교한 GUI 를 개발할 수 있다. 세편의 기사 시리즈를 통해서 A.O.Van Emmenis 가 단독 애플리케이션을 만드는 법을 보여준다. Part 1 에서는 "Hello, World" 라는 예제로부터 시작해서 각종 팁과 요령, 그리고 설계 관점과 함께 단계적으로 (졸라) 간단한 파일 탐색기를 만들어 나간다.

Introduction
The open source Eclipse project is one of the most interesting recent developments in the Java world. Eclipse describes itself as "a kind of universal tool platform -- an open extensible IDE for anything and nothing in particular". For an introduction to Eclipse, see thedeveloperWorksarticle "Getting started with the Eclipse Platform".

오픈 소스 이클립스 프로젝트는 자바계(Java 界)에서 가장 흥미진진한 최근의 개발들 중 하나이다. 이클립스는 "일종의 통합 개발 플랫폼"으로서 일컬어지는데, 모든 개발에 대해서 개방적이고 확장적인 IDE 이고 특별히 제한을 두고 있지 않다.

Two of its major components are a graphical library called SWT and a matching utility framework called JFace. I'll concentrate on these components in this article. The Eclipse Technical Overview on the Eclipse Web site (seeResourceslater in this article) describes them like this:

주요한 두개의 컴포넌트는 그래픽 라이브러리인 SWT 와 이에 잘 어울리는 유틸리티 프레임워크인 JFace 이다.

  • SWTis a widget set and graphics library integrated with the native window system but with an OS-independent API.SWT 는 native window system 과 통합되면서 os 로부터 독립적인 API 들로 구성된 부품세트들과 그래픽 라이브러리이다.
  • JFaceis a UI toolkit implemented using SWT that simplifies common UI programming tasks. JFace is window-system-independent in both its API and implementation, and is designed to work with SWT without hiding it..JFace 는 공통적인 UI 프로그래밍 작업들을 단순화한 SWT 를 사용해서 구현된 UI 툴킷이다. JFace 는 API 와 그 구현이 모두 window 시스템에 독립적이고 이것을 감추지 않고 SWT 와 작동하도록 설계되었다.

Figure 1 shows the relationships between Eclipse, JFace, and SWT.

.그림 1은 이클립스와 JFace , 그리고 SWT 의 관계를 보여준다.

 

Figure 1. Eclipse Workbench, JFace, and SWT

사용자 삽입 이미지

 

Most of the articles published about JFace and SWT (so far) have discussed them from the point of view of using them in the context of the larger Eclipse framework. In this article I am going to take a different approach. I will show how you can use JFace and SWT in a standalone Java program.

.JFace와 SWT 에 대해서 출판된 대부분의 기사들은 (적어도 지금까지) 더 커다란 이클립스 프레임워크 안에서 이들을 이용하는 관점에서 이들을 다루어왔다. 하지만 이 기사에서는 좀 다른 접근 방식을 취하려고 한다. 이 기사에서 나는 여러분에게 독립적인 자바 프로그램에서 JFace와 SWT 를 이용하는 방법을 보여줄 것이다.

 

The example I have chosen is a file explorer. We won't actually implement very much real functionality, but we will visit enough of the GUI for you to see how a fully featured program might be built.

.내가 선택한 예제는 파일 탐색기이다. 그렇지만 실제로 매우 실감나게 파일 탐색기를 구현하지는 않고 충분한 GUI를 살펴보면서 여러분이 제대로 된 프로그램이 만들어지는 방법을 이해하도록 할 것이다.

 

Installation notes


You can download thesource code for the examplesin this article, but take my system setup into account:.이 기사에서source code for the examples 를다운 받을 수 있지만, 나의 시스템 설정을 고려하기 바란다.

  • Windows 2000
  • Eclipse, stable build M3 (November 15, 2002)
  • Eclipse installed in C:\eclipse-2.1.0

I will leave you to do any swizzling of names and file separators in what follows, so that the programs work correctly on your system..???????????????????????????????????????

 

Build/run instructions

You need these jar files on your class path:.다음의 jar 파일들이 클래스 패스이 있어야 한다.

C:\eclipse-2.1.0\plugins\org.eclipse.jface_2.1.0\jface.jar
C:\eclipse-2.1.0\plugins\org.eclipse.runtime_2.1.0\runtime.jar
C:\eclipse-2.1.0\plugins\org.eclipse.swt.win32_2.1.0\ws\win32\swt.jar
C:\eclipse-2.1.0\plugins\org.eclipse.ui.workbench_2.1.0\workbench.jar
C:\eclipse-2.1.0\plugins\org.eclipse.core.runtime_2.1.0\runtime.jar

Ensure that the Java VM picks up the correct shared libraries for the GUI you are using at runtime by running it with the following argument:

.Java VM 이 다음의 argument 와 함께 시작됨으로써 실행시에 당신이 사용하고 있는 GUI 에 대한 올바른 공유 라이브러리를 주워간다는 것을 기억하자.

 

-Djava.library.path=C:\eclipse-2.1.0\plugins\org.eclipse.swt.win32_2.1.0\os\win32\x86\

 

Finally, so that the examples can find the gif files containing the icons, run the programs from the folder that contains theiconsfolder.

.마지막으로 예제가 아이콘을 포함하는 gif 파일들을 찾을 수 있도록 아이콘 폴더를 포함하는 폴더로에서 프로그램을 실행하도록 하자.

 

Hello, World

Let's start with the simplest JFace program I can think of and build it up to the ubiquitous "Hello, World" program.

.초간단 JFace 프로그램부터 시작해보자.

 

Listing 1. Hello (version 1)

import org.eclipse.jface.window.*;
import org.eclipse.swt.widgets.*;
public class Hello {
public static void main(String[] args) {
ApplicationWindow w = new ApplicationWindow(null);
w.setBlockOnOpen(true);
w.open();
Display.getCurrent().dispose();
}
}

 

Here we have a class calledHellowhere the main method merely creates an ApplicationWindow, and then opens it. ThesetBlockOnOpen()makes theopen()block until the window is closed..메인 메소드가 단순히 Application Window 객체를 생성하고 이것을 열어보이는 Hello 라는 클래스를 얻게 된다. setBlockOnOpen() 메소드는 윈도우가 닫힐때까지 open() 메소드를 block 상태로 있게 한다.

After the window has closed, we get the current Display and dispose of it. This releases the resources used in the operating system (I'll discuss why it's always good practice to do this later).

 

When you run this program, you see a window that looks like Figure 2:

.이 프로그램을 실행하면 그림 2와 같은 창이 보인다.

 

Figure 2. Hello (version 2)
   

사용자 삽입 이미지

 

And that's it. It doesn't even say "Hello, World". Before we fix that, let's digress into JFace windows..이게 전부이다. 이 프로그램은 "Hello, World" 를 출력하지 않는다. 이것을 수정하기 전에 JFace 윈도우를 잠깐 살펴보자.

 

 

JFace application windows


A window is theJFaceclass for a top level window -- in other words, one that is managed by the OS window manager. A JFace window is not actually the GUI object for a top level window (SWT already provides one, called aShell). Instead, a JFace window is a helper object that knows about a corresponding SWT Shell object and provides code to help create/edit it, listen to its events, etc. Figure 3 shows the relationship between your code, JFace, and SWT.

윈도우는 최상위 윈도우로서 JFace 클래스이다. 다시 말해서 OS window manager 가 관리하는 것이란 뜻이다. JFace 윈도우는 실제 최상위 윈도우로서의 GUI 객체는 아니다.(SWT 가 이미 Shell 이라고 불리는 객체를 제공한다.) 대신에 JFace 윈도우는 helper 클래스인데 상응하는 SWT Shell 객체에 대해서 알고 있고 윈도우를 생성/수정하는 코드를 제공하며 윈도우 이벤트를 듣는다. 그림 3이 위의 코드조각과 JFace , SWT의 관계를 보여준다.

 

Figure 3. The relationship between your code, a JFace Window, and an SWT Shell
   

사용자 삽입 이미지

 

In fact, this model is the key to understanding how JFace works. It is not really a layer on top of SWT, and it doesn't try to hide SWT from you. Instead, JFace recognizes that there are several common patterns of use for SWT, and it provides utility code to help you program these patterns more easily.

.사실 이 모델은 JFace 가 작동하는 방식을 이해하는데 있어서 중요하다. JFace 는 SWT의 상위에 있는 layer 가 아니고 여러분들로부터 SWT를 가리지도 않는다. 대신에 JFace 는 SWT를 사용하는 몇가지 공통적인 패턴이 있음을 인식하고 여러분이 이러한 패턴을 쉽게 프로그래밍 할 수 있게 도와주는 유틸을 제공한다.

To do this, JFace either provides an object that you use or a class that you can subclass (and sometimes it provides both).

.그러한 일을 하기 위해서 JFace는 여러분이 사용하거나 서브클래스화한 객체를 제공한다.(때로는 둘 다를 제공한다.)

Although we just used anApplicationWindowdirectly, they are actually designed for you to subclass and fill in your specific behavior. They come ready-made with a menu bar, a tool bar, an area for you to insert your application-specific contents, and a status line -- all optional. Figure 4 shows these areas on the JFace File Explorer example itself.

.우리가 단순히 ApplicationWindow 를 직접 사용했지만 사실 여러분이 서브클래스를 만들어서 특정 행위를 기술해 넣도록 설계되어있다. 메뉴바, 툴바, 그리고 여러분이 구체적인 내용을 넣을 수 있는 공간과 상태표시줄을 갖추고 있고 이 모든게 임의로 선정할 수 있는 것들이다. 그림 4에서 JFace 파일 탐색 예제에서 보이는 이러한 영역들을 보여준다.

 

Figure 4. The parts of an application window

사용자 삽입 이미지

Let's refine Hello to make it a subclass ofApplicationWindow. The changed lines are highlighted in Listing 2.

.이제 Hello 소스코드를 다듬어서 ApplicationWindow의 서브클래스로 만들어 보자. 변경된 라인은 리스트 2에 보여진다.

 

Listing 2. Hello (version 2)

import org.eclipse.jface.window.*;
import org.eclipse.swt.widgets.*;
public class Hello extends ApplicationWindow {
public Hello() { super(null); }
public static void main(String[] args) {
Hello w = new Hello();
w.setBlockOnOpen(true);
w.open();
Display.getCurrent().dispose();
}
}

 

The constructor that you write must invoke the superclass constructor (as usual). Let's ignore the argument to that constructor for now..써넣은 생성자 코드는 부모클래스의 생성자를 호출해야한다. 지금은 일단 생성자의 argument 를 무시하자.

Running this doesn't give us anything different from the previous program. The default is not to give us any decorations..이 프로그램을 실행해도 이전의 것에 다른게 없다. 기본적으로 설정된 상태는 아무런 것도 보여주지 않는 것이기 때문이다.

Our program is going to create a button with the text "Hello, World". This button is going to appear in the contents area. To do this, we must implement theControl.우리의 프로그램은 "Hellow, World"라는 텍스트가 쓰여진 버튼을 생성할 것이고 이 버튼은 contents 영역에 보여질 것이다. 이를 위해서 Control 을 구현해야만 한다.

 

    createContents(Composite parent)method.

 

ApplicationWindowwill call this after all the other widgets have been created but before the window is displayed on the screen..다른 모든 부품들이 생성되고 윈도우가 실제로 스크린에 보여지기 전에 ApplicationWindow는 이 메소드를 호출할 것이다.

The argument parent is the composite widget that represents the contents area.

The idea is that you create a composite widget, add it to parent, then add your widgets, and return the composite widget that you created. Figure 5 shows the instance hierarchy.

.매개변수 parent 는 contents 영역을 표현하는 복합 부품이다. 여러분이 복합부품(composite widget)을 생성하고 parent 에 붙여넣고나서 부품들을 붙여넣고 만들어낸 복합 부품을 리턴한다는 개념이다. 그림 5에서 인스턴스 계층을 보여준다.

 

Figure 5. The instance hierarchy of an Application Window


   

사용자 삽입 이미지

 

Our contents are going to be fairly simple for now: a single button under parent, as shown in Listing 3..우리의 프로그램 내용은 지금까지는 꽤 간단하다. Listing 3 에서 보이듯이 parent 아래에 하나의 버튼만 있는 것이다.

 

Listing 3. Hello (version 3)

import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
public class Hello extends ApplicationWindow {
public Hello() { super(null); }
protected Control createContents(Composite parent) {
Button b = new Button(parent, SWT.PUSH);
b.setText("Hello World"); return b;
}
public static void main(String[] args) {
Hello w = new Hello();
w.setBlockOnOpen(true);
w.open();
Display.getCurrent().dispose();
}
}

 

The result is Figure 6..그림 6이 위 코드의 결과다.

 

Figure 6. Hello (version 3)


   

사용자 삽입 이미지

 

And there we are. Our first "Hello, World" program in JFace: a window containing a single button..자 나왔다. 하나의 버튼을 포함하는 JFace  윈도우,  우리의 첫번째 "Hello, World" 프로그램이다.Now let's move on to the file explorer. First, we'll create the tree viewer that will display the folder hierarchy..이제 파일 탐색기로 옮겨가보자. 먼저 폴더 계층을 보여줄 tree viewer 를 생성할 것이다.

 

Using a TreeViewer

 

Just as with theApplicationWindow, aTreeVieweris not the actual SWT widget, nor does it try to hide the SWT widget from you. It uses an SWT tree widget to display the items, and it uses a number of other objects to help it, too.

.ApplicationWindow 에서처럼 TreeViewer도 실제 SWT 부품이 아니고 SWT 부품을 감추지도 않는다. 이것은 아이템을 보여주기 위해서 SWT tree 부품을 사용하고 이를 도와줄 많은 다른 부품들을 사용한다.

Unlike theApplicationWindow, JFaceTreeVieweris not intended to be subclassed.

The idea is that aTreeViewerknows about the root element of the tree that it is going to display. You have to tell it what that object is, of course:

.ApplicationWindow 와는 다르게 JFace TreeViewer 는 서브클래스로 만들어 사용할 목적으로 고안된 것은 아니다. TreeViewer 는 스크린에 출력할 tree 의 루트 요소를 알고 있다는 것이다. 물론 그 객체가 무엇인지는 여러분이 알려줘야 한다.

 

       TreeViewer: void setInput(Object rootElement)

 

To get started, it asks that root element for its children and then displays them. Then, as the user expands one of the children, the tree viewer asks that node for its children and so on. Actually, that's not quite true. TheTreeViewerdoesn't talk to the domain objects directly -- instead it uses another object called aContentProvider, and this object uses your domain objects as in Figure 7.

.출력을 위해서 TreeViewer 는 자식요소의 root 요소를 요청하고 그것들을 화면에 보여준다. 그리고나서 사용자가 자식요소 중 하나를 확장하면 tree viewer 는 그 요소의 자식요소를 요청하는 식으로 나아간다. 하지만 실제로는 그렇지 않다.TreeViewer 가 직접적으로도메인 객체와 대화를 나누지 않는다. 그대신에 ContentProvider 라고 불리는 별도의 객체를 사용하고 이 객체가 그림 7에 보이는 것처럼 여러분의 도메인 객체를 사용하는 것이다.



역자 주 :

도메인 객체 (Domain Object)
TreeViewer는 무언가를 트리의 형태로 보여주는 객체이다. 그 보여주는 대상이 여러가지가 될 수 있는데 여기서는 특별히 파일 구조를 트리형태로 보여주고 있다. 이때 보여주는 대상이 되는 파일 구조를 도메인이라고 볼 수 있다. TreeViewer 는 파일이라는 도메인 위에서 파일 구조를 나름대로 Visual 하게 보여주고 있다. 여기에서 Domain Object 라고 한것은 바로 그런 의미이다.(신문, 소설, 시, 희곡 등의 도메인은 한국어를 기반으로 쓰여진다. 이들은 한국어라는 언어를 기준으로 쓰여지기 때문에 한국어를 도메인이라고 할 수 있다.)


 

 

Figure 7. TreeViewer, ContentProvider, and domain objects

사용자 삽입 이미지

You have to implement theContentProvider, of course. For aTreeViewer, your class must implement theITreeContentProviderinterface.

.여러분은 ContentProvider 를 구현해야 한다. TreeViewer 에 대해서는 ITreeContentProvider 인터페이스를 구현한 클래스가 있어야 한다.

 

Implementing a TreeContentProvider

 

There are six methods to implement. We can actually get away with only implementing three of them, so, in the spirit of instant gratification, let's just consider those for now.

This is how the tree viewer asks the content provider for the top-level elements directly beneath the root element:

.TreeContentProvider 에는 구현할 메소드가 여섯개 있다. 우리는 실제로 ................... 이런 방식으로 tree viewer 가 root 요소 바로 밑의 최상위 요소를 위한 content provider 를 직접적으로 요청한다.

 

    ITreeContentProvider: public Object[] getElements(Object element)

 

and then, whenever it needs the children of a particular element, it uses this:

그리고 나서 특정 요소의 자식요소들이 필요할때마다 다음의 코드를 이용한다.

 

    ITreeContentProvider: public Object[] getChildren(Object element)

 

In order to figure out if a node has any children (and then put that little plus sign next to it), the tree viewer could just ask for the children of the node, and then it could ask how many there are. Just in case your code knows of a quicker way to do this, there is another method that you must implement:

노드가 자식을 가지고 있는지를 알기 위해서 tree viewer 는 노드의 자식을 필요로 할 수 있고 자식이 몇개 있는지를 물어볼 수 있다. 여러분의 코드에서 더 빠른 방법을 알고 있다고 한다면 여러분이 구현해야할 또다른 메소드가 있다.

 

        public boolean hasChildren(Object element)

 

As you can see, the content provider doesn't hold a reference to any domain objects. It is the tree viewer that holds on to them itself and passes them as arguments to each method in the content provider.

보다 시피 content provider 는 도메인 객체들에 대한 참조를 전혀 갖고 있지 않다. 참조를 갖고 있는 것은 tree viewer 이고 tree viewer 가 cotent provider 에 있는 각각의 메소드에 매개변수로서 그 참조를 건네준다.

In our case, a node is aFileobject. To get the children, we uselistFiles(). We must remember to check forlistFiles()returning null and turn that into an empty array.

To get the top-level elements, just underneath the root element, we can just reuse thegetChildren()method.

우리의 경우, 노드는 File 객체이다. 이것의 자식을 얻기 위해서 listFiles() 메소드를 이용한다. listFiles() 가 null 을 반환하는지를 확인해서 그렇다면 비어있는 배열로 그것을 바꾸는 것을 기억해야 한다.

ThegetParent()method is used to implement thereveal(Object element)method, which makes the tree viewer scroll its SWT tree widget in order to display a particular node in the tree. The question is: if that node is not actually being displayed at the moment, where should it be displayed? JFace looks at its parent and then the parent's parent, etc. until it reaches a node that is displayed and it then tracks down again until the target node is displayed.

getParent() 메소드는 reveal(Object element) 메소드를 구현하는데 사용되는데 reveal 메소드는 트리에 있는 특정 노드를 보여주기 위해서 tree viewer 가 SWT tree 부품을 스크롤하게 한다.

ThehasChildren()method just does the obvious (unoptimized) thing, and we end up with the code in Listing 4.

Listing 4. FileTreeContentProvider (version 1)

import java.io.*;
import java.util.*;
import org.eclipse.jface.viewers.*;
public class FileTreeContentProvider implements ITreeContentProvider {
public Object[] getChildren(Object element) {
Object[] kids = ((File) element).listFiles();
return kids == null ? new Object[0] : kids;
}
public Object[] getElements(Object element) {
return getChildren(element);
}
public boolean hasChildren(Object element) {
return getChildren(element).length > 0;
}
public Object getParent(Object element) {
return ((File)element).getParent();
}
public void dispose() { }
public void inputChanged(Viewer viewer,
Object old_input,
Object new_input){}
}

 

Implementing the top-level Explorer class

We'll take our Hello, World program, change its name, and then, in thecreateContents()method, instead of creating a button, we create aTreeViewer, set its content provider to our file tree content provider, and then set the input to a folder. In this case, the folder I have chosen is the top-level folder in the C: drive.

Note that we are required to return the SWT widget fromcreateContents(). As we mentioned above, the JFace Tree Viewer is not the SWT widget, so we can't return that. We need to get the actual widget from the tree viewer. We do this usinggetTree().

Our main window class should now look like this:

 

Listing 5. Explorer (version 1)

import java.io.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
public class Explorer extends ApplicationWindow {
public Explorer() { super(null); }
protected Control createContents(Composite parent){
TreeViewer tv = new TreeViewer(parent);
tv.setContentProvider(new FileTreeContentProvider());
tv.setInput(new File("C:\\"));
return tv.getTree();
}
public static void main(String[] args) {
Explorer w = new Explorer();
w.setBlockOnOpen(true);
w.open();
Display.getCurrent().dispose();
}
}

 

Run this program, and you will see something like Figure 8.

 

Figure 8. Explorer (version 1)

사용자 삽입 이미지

 

Leaving aside the boilerplate code, we had to add only 9 lines of code to our Hello, World program to achieve this.

As you might guess, the files are being displayed using thetoString()method onFile, which is not really what we want. To change this, we need to provide a label provider.

 

Implementing a label provider

Just as there is a content provider object that gets the children of the tree nodes, when it comes to actually displaying the nodes, the tree viewer has another helper object: the label provider. As before, we need to set it:

public void setLabelProvider(IBaseLabelProvider labelProvider)

and we need to implement the method to return the text to display for each element:

public String getText(Object element)

If we add the label provider to the diagram for the tree viewer, we get Figure 9.

 

Figure 9. Tree Viewer showing content provider and label provider

사용자 삽입 이미지

 

There is an interface we could implement,ILabelProvider, but it's easier to subclass the default implementation,LabelProvider. (This class is the one used if we don't set the label provider explicitly).

What we want to do ingetText()is to return the last part of the file name - the relative file name rather than the absolute file name thattoString()uses by default. Listing 6 shows the code.

Listing 6. FileTreeLabelProvider (version 1)

import java.io.*;
import org.eclipse.jface.viewers.*;
public class FileTreeLabelProvider extends LabelProvider {
public String getText(Object element){
return ((File) element).getName();
}
}

 

And we have to remember to make the tree viewer use this label provider, as shown in Listing 7.

 

Listing 7. Explorer (version 2)

import java.io.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
public class Explorer extends ApplicationWindow {
public Explorer() { super(null); }
protected Control createContents(Composite parent){
TreeViewer tv = new TreeViewer(parent);
tv.setContentProvider(new FileTreeContentProvider());
tv.setLabelProvider(new FileTreeLabelProvider());
tv.setInput(new File("C:\\"));
return tv.getTree();
}
public static void main(String[] args){
Explorer w = new Explorer();
w.setBlockOnOpen(true);
w.open();
Display.getCurrent().dispose();
}
}

 

When we run the program this time, we get a cleaner looking result, as shown in Figure 10.

 

Figure 10. Explorer (version 2)

사용자 삽입 이미지

 

What we want to do now is to move the tree viewer to the left and put a table view on the right showing a list of the files in the folder that we have selected in the tree viewer.

 

Using a table viewer

To handle tables, JFace has aTableViewer. Just like theTreeViewer, it has an input (a root object), a content provider, and a label provider. It's simpler than the tree viewer since it doesn't need to deal with trees. Figure 11 shows the content provider and label provider.

 

Figure 11. Table viewer showing content provider and label provider

사용자 삽입 이미지

 

The method to set the input object is the same as before:

TableViewer: void setInput(Object rootElement)

 

Implementing the file table viewer content provider

Let's look at the content provider. This time, the root element is simpler than the tree viewer root element. The table viewer merely expects that the root object has a number of children, so the only interesting method to implement is the one that gets the children:

public Object[] getElements(Object rootElement)

The interface we need to implement isIStructuredContentProvider.

The root object will be a folder; its children will be the files/folders that it contains. So our file table content provider class looks like Listing 8.

 

Listing 8. FileTableContentProvider (version 1)

import java.io.*;
import org.eclipse.jface.viewers.*;
public class FileTableContentProvider implements IStructuredContentProvider{
public Object[] getElements(Object element) {
Object[] kids = null;
kids = ((File) element).listFiles();
return kids == null ? new Object[0] : kids;
}
public void dispose(){ }
public void inputChanged(Viewer viewer,
Object old_object,
Object new_object) { }
}

 

So now we have two viewers: the tree viewer and the table viewer. To arrange them next to each other, we create an SWT SashForm widget. This widget separates its children with a border that the user can adjust. We then add the tree and the table to the sash form (Figure 12).

 

Figure 12. The sash form contains the tree viewer and the table viewer
  

사용자 삽입 이미지

 

The next thing we need to do is to make the table viewer look at each folder that the user selects in the tree viewer. To do this we must listen for events.

 

Listening for events

When the user selects an item in the tree viewer, the tree viewer fires an event, theSelectionChangedEvent. We need to listen for that event, and when it fires, we need to set the input for the table to be the currently selected file in the tree viewer.

To listen for the selection changed events that come from the tree viewer, we use this:

public void addSelectionChangedListener(ISelectionChangedListener listener)

When the user selects/deselects a node in the tree viewer, the selection changed listener gets called with this:

public void selectionChanged(SelectionChangedEvent event)

To implement this listener class, we'll code an anonymous class in the main Explorer Window. In theselectionChanged()method, we will need to get hold of the object that has just been selected and make this the input for the table viewer. Putting it all together, we get Listing 9.

 

Listing 9. Explorer (version 3)

import java.io.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.widgets.*;
public class Explorer extends ApplicationWindow{
public Explorer() { super(null); }
protected Control createContents(Composite parent) {
SashForm sash_form = new SashForm(parent, SWT.HORIZONTAL | SWT.NULL);
TreeViewer tv = new TreeViewer(sash_form);
tv.setContentProvider(new FileTreeContentProvider());
tv.setLabelProvider(new FileTreeLabelProvider());
tv.setInput(new File("C:\\"));
final TableViewer tbv=new TableViewer(sash_form, SWT.BORDER);
tbv.setContentProvider(new FileTableContentProvider());
tv.addSelectionChangedListener(new ISelectionChangedListener(){
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection =
(IStructuredSelection) event.getSelection();
Object selected_file = selection.getFirstElement();
tbv.setInput(selected_file);
}
});
return sash_form;
}
public static void main(String[] args) {
Explorer w = new Explorer();
w.setBlockOnOpen(true);
w.open();
Display.getCurrent().dispose();
}
}

 

If we run this program, we get something like Figure 13.

 

Figure 13. Explorer (version 3)

사용자 삽입 이미지

 

Just as with the tree viewer, if you don't explicitly set the label provider on the table viewer, it uses the default label provider. This is what has happened here -- and if you remember, the default behavior is to display the string that is returned by the element'stoString()method, which happens to be the absolute file name.

Let's implement our own table label provider.

 

Implementing a file table label provider

Only one method to worry about for now:

public String getColumnText(Object element, int column)

There are two arguments: the element to get the label for, and the column index (starting at 0).

The implementation for this is simple enough -- if we ignore the column index argument, as shown in Listing 10.

Listing 10. FileTableLabelProvider (version 1)

import java.io.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.graphics.*;
public class FileTableLabelProvider implements ITableLabelProvider {
public String getColumnText(Object obj,int i){
return ((File) obj).getName();
}
public void addListener(ILabelProviderListener ilabelproviderlistener){}
public void dispose(){ }
public boolean isLabelProperty(Object obj, String s) {
return false; }
public void removeListener(ILabelProviderListener ilabelproviderlistener){}
public Image getColumnImage(Object arg0, int arg1) { return null; } }

 

To configure the table to have one column with a header labeled "Name", we must extract the table widget from the table viewer, create a table column widget as a child of the table, and set some properties for it, as shown in Listing 11.

 

Listing 11. Explorer (version 4)

import java.io.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.widgets.*;
public class Explorer extends ApplicationWindow {
public Explorer() { super(null); }
protected Control createContents(Composite parent){
SashForm sash_form = new SashForm(parent, SWT.HORIZONTAL | SWT.NULL);
TreeViewer tv = new TreeViewer(sash_form);
tv.setContentProvider(new FileTreeContentProvider());
tv.setLabelProvider(new FileTreeLabelProvider());
tv.setInput(new File("C:\\"));
final TableViewer tbv = new TableViewer(sash_form, SWT.BORDER);
tbv.setContentProvider(new FileTableContentProvider());
tbv.setLabelProvider(new FileTableLabelProvider());
TableColumn column=new TableColumn(tbv.getTable(),SWT.LEFT);
column.setText("Name");
column.setWidth(200);
tbv.getTable().setHeaderVisible(true);
tv.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection =
(IStructuredSelection) event.getSelection();
Object selected_file = selection.getFirstElement();
tbv.setInput(selected_file);
}
});
return sash_form;
}
public static void main(String[] args) {
Explorer w = new Explorer();
w.setBlockOnOpen(true);
w.open();
Display.getCurrent().dispose();
}
}

 

Having done this, we should get a result like Figure 14.

 

Figure 14. Explorer (version 4)

사용자 삽입 이미지

 

Conclusion

We have worked through quite a lot of JFace in a very short time. We have used an application window and two viewers (Tree and Table) and implemented their content and label providers. We have used SWT widgets: Button, SashForm, Table, TableColumn, and implemented an event listener.

There are few ragged edges here, though. We ignored some of the methods in the content/label providers, the tree viewer is displaying files as well as folders, there are no icons being displayed, and there is no sign of a menu bar, tool bar, status line, or any pop-up menus.

In the next article, we'll tidy up the content/label providers and use sorting and filtering on the viewers. We'll add a status line to the window, add icons to both viewers, and learn about the JFace image registry.

Resources

About the author
사용자 삽입 이미지
A. O. Van Emmenis is an independent consultant, specializing in Java/J2EE training and consulting, based in Cambridge, UK. Van has worked in the software industry for 20 years or so. He first started working with objects using Smalltalk in the CAD industry and now works mainly in Java. He is particularly interested in Agile methods and GUI design. You can contact Van atvan@vanemmenis.com.

'Eclipse' 카테고리의 다른 글

[펌] Ant란?  (0) 2005.03.06
[펌] ANT (하): Ant 무엇에 쓰는 물건인고?  (0) 2005.03.06
[펌] [ SWT ] SWT와 Swing 의 GUI 구조.  (0) 2005.01.20