드레그 와 드롭은 일상에서 많이 사용하고 있다. 근데 개발툴에서는 많이 사용하지 않았지만 앞으로 개발툴도 이러한 기능으로 소스코딩양을 줄여주는것이 좋을것 같다.
이기능은 사용하려면 드래그 하는 곳과 드롭하는 곳에 상호작용 및 순서가 필요하다.
드래그소스->드롭타깃->드롭효과 ->트랜스
먼저 드레그 클래스 계층도를 살펴보자

ㅁ 드레그 소스
드레그 소스에는 여러가지 형태가 있을수 있다
가령 text, file, 워드와 같이 특정 문자에 색이나 강조등의 효과를 가지고 있는 RTP 형식 문서등이 있다.
여기서는 해당소스가 명칭을 TextTransfer, FileTransfer,HTML Transfer,RTF Transfer 라 하고 각각
instance를 생성 전달하게 된다.
여기서 간단한 예제로 Label에 소스를 드레그해서 이클립스 java editer에 드롭하면 move되는 소스를 참고 하여보자
package swt.drag_drop;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
public class DragSourceTest {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setText("SWT DragSource Test");
// 레이블 위젯을 드래그 원본(Drag Source)으로 활성화 한다.
final Label label = new Label(shell, SWT.BORDER);
label.setText("text to be transferred");
int operations = DND.DROP_MOVE | DND.DROP_COPY;
DragSource source = new DragSource(label, operations);
// 텍스트 포맷 내에 데이터를 제공한다.
Transfer[] types = new Transfer[]{TextTransfer.getInstance()};
source.setTransfer(types);
source.addDragListener(new DragSourceListener() {
public void dragStart(DragSourceEvent event) {
// 레이블 내에 실제 텍스트가 있을 경우에만, 드래그를 시작한다.
if (label.getText().length() == 0) {
event.doit = false;
}
}
public void dragSetData(DragSourceEvent event) {
// 요청된 타입의 데이터를 제공한다.
if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
event.data = label.getText();
}
}
public void dragFinished(DragSourceEvent event) {
// 만약, 데이터의 이동(MOVE) 작업이 수행되었다면,
// 드래그 원본인 레이블 위젯에서 이동한 데이터를 제거한다.
if (event.detail == DND.DROP_MOVE) {
label.setText("");
}
}
});
shell.setSize(640, 480);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
구현시 처리되는 동영상을 참고하세요
ㅁ 드롭 타겟
다음은 드롭소스를 예제로 생성해 보았다 반대로 드레그는 이클립스에 자바소스에서 드롭은 개발된 소스에서 받는걸로 예제를 처리했다.
package swt.drag_drop;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class DropTargetCopyTextFileTest {
private static void open(Text text, String filename) {
File file = new File(filename);
try {
text.setText("");
FileReader reader = new FileReader(file);
BufferedReader in = new BufferedReader(reader);
String str = null;
while ((str = in.readLine()) != null) {
text.append(str + "\n");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setText("SWT DropTarget Test");
final Text text = new Text(shell, SWT.BORDER | SWT.MULTI);
int operations = DND.DROP_DEFAULT | DND.DROP_COPY | DND.DROP_MOVE;
DropTarget target = new DropTarget(text, operations);
target.setTransfer(new Transfer[]{FileTransfer.getInstance(),
TextTransfer.getInstance()});
target.addDropListener(new DropTargetAdapter() {
FileTransfer fileTransfer = FileTransfer.getInstance();
TextTransfer textTransfer = TextTransfer.getInstance();
public void dragEnter(DropTargetEvent e) {
System.out.println("[dragEnter] e : " + e);
TransferData data[] = e.dataTypes;
for (int i = 0; i < data.length; i++) {
System.out.println("[dragEnter] data[" + i + "] : "
+ data[i]);
}
if (e.detail == DND.DROP_DEFAULT) {
e.detail = DND.DROP_COPY;
}
}
public void dragOperationChanged(DropTargetEvent e) {
if (e.detail == DND.DROP_DEFAULT) {
e.detail = DND.DROP_COPY;
}
}
public void drop(DropTargetEvent e) {
System.out.println("[drop] e : " + e);
if (fileTransfer.isSupportedType(e.currentDataType)) {
String[] files = (String[]) e.data;
if (files != null && files.length > 0) {
open(text, files[0]); // 파일을 연다
}
}
if (textTransfer.isSupportedType(e.currentDataType)) {
String str = (String) e.data;
if (str != null) {
text.setText(str); // 텍스트를 커서 위치에 삽입
}
}
}
});
// shell.setLocation(display.getBounds().width - 320,
// display.getBounds().height - 240);
shell.setSize(320, 240);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
여기도 동영상을 보면 어떻게 구현했는지를 알수 있다.
ㅁ 사용자 포멧 드레그 엔 드롭
개발하다보면 사용자 포멧에 데이터를 드레그 엔 드롭을 하고 싶을때가 있다
▶ MySimpleDragAndDrop에서 화면구성 및 Drag 소스를 MyType으로 Table에 TableItem 객체로 구성
▶ DragSource, DragSource의 TransferType을 MyTypeTransfer 인스턴스로 선언
▶ addDragListener에서 이벤트가 발생시 event.data에 MyTyp객체로 넘겨줌
▶ DropTarget에서도 TransferType을 MyTypeTransfer 인스턴스 선언
▶ addDropListener에서 이벤트 발생시 evnet.data를 Mytype변환하여 사용
※ MyTypeTransfer는 인스턴스로 ByteArrayTransfer 상속받아 byte로 짤라 전달
ㅁ 3가지 소스사용
MyType.java(사용자Drag&Drop선언), MyTypeTransfer.java(인스턴스), MySimpleDragAndDrop(main)
▶ MyType.java : 내가 Drag & Drop할 객체
package swt.drag_drop;
public class MyType {
public String fileName;
public long fileLength;
public long lastModified;
}
▶ MySimpleDragAndDrop.java : 화면구성 및 이벤트 선언
package swt.drag_drop;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSource;
import org.eclipse.swt.dnd.DragSourceAdapter;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
public class MySimpleDragAndDrop {
//시작
public static void main(String[] args) {
//화면구성
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
//왼쪽에 테이블: LIST는 setData가 없어 TableItem의 setData를 사용함
final Table tblDrgSrc = new Table(shell, SWT.BORDER | SWT.WRAP | SWT.MULTI);
//아이템1 : abc.txt 파일명에 크기 lastModified라는 속성을 하나의 사용자 객체를 만들어 add
TableItem item1 = new TableItem(tblDrgSrc,SWT.NONE);
MyType myType1 = new MyType();
myType1.fileName = "C:\\abc.txt";
myType1.fileLength = 1000;
myType1.lastModified = 12312313;
item1.setText(myType1.fileName);
item1.setData(myType1);
//아이템2 : abc.txt 파일명에 크기 lastModified라는 속성을 하나의 사용자 객체를 만들어 add
TableItem item2 = new TableItem(tblDrgSrc,SWT.NONE);
MyType myType2 = new MyType();
myType2.fileName = "C:\\xyz.txt";
myType2.fileLength = 500;
myType2.lastModified = 12312323;
item2.setText(myType2.fileName);
item2.setData(myType2);
//두번째는 Drop할 객체로 Lable 선언
final Label label2 = new Label(shell, SWT.BORDER | SWT.WRAP);
label2.setText("Drop Target for MyData[]");
//Drag Transfer 선언 : MyTransfer 인스턴스를 넘김선언
DragSource source = new DragSource(tblDrgSrc, DND.DROP_COPY);
source.setTransfer(new Transfer[] { MyTypeTransfer.getInstance() });
//Drag 이벤트를 선언 Transfer로는 내가만든 MyTransfer라는 객체로 넘어감
source.addDragListener(new DragSourceAdapter() {
public void dragSetData(DragSourceEvent event) {
int arr = tblDrgSrc.getSelectionCount();
int cnt = 0;
MyType[] myType = new MyType[arr];
//Drag시 내가 만든 객체 myType이란속성에 Object를 event.data로 넘김
for(TableItem SelItem :tblDrgSrc.getSelection()) {
myType[cnt] = (MyType)SelItem.getData();
cnt++;
}
event.data = myType;
System.out.println("drageSetData");
}
});
//Drop Target 선언 : MyTransfer 인스턴스를 받으려 선언
DropTarget target = new DropTarget(label2, DND.DROP_COPY | DND.DROP_DEFAULT);
target.setTransfer(new Transfer[] { MyTypeTransfer.getInstance() });
//Drop 이벤트로 받은경우 Data Object를 받아 MyType으로 변환하여 그중에 이름을 가져옴
target.addDropListener(new DropTargetAdapter() {
public void dragEnter(DropTargetEvent event) {
if (event.detail == DND.DROP_DEFAULT) {
event.detail = DND.DROP_COPY;
}
}
public void dragOperationChanged(DropTargetEvent event) {
if (event.detail == DND.DROP_DEFAULT) {
event.detail = DND.DROP_COPY;
}
}
public void drop(DropTargetEvent event) {
if (event.data != null) {
MyType[] myTypes = (MyType[]) event.data;
if (myTypes != null) {
String string = "";
for (int i = 0; i < myTypes.length; i++) {
string += myTypes[i].fileName + " ";
}
label2.setText(string);
}
}
}
});
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
static class MyTransfer extends ByteArrayTransfer {
//인스턴스 객체를 생성하기 위해 Name과 ID가 필요함
private static final String MYTYPENAME = "name_for_my_type";
private static final int MYTYPEID = registerType(MYTYPENAME);
private static MyTransfer _instance = new MyTransfer();
public static MyTransfer getInstance() {
return _instance;
}
//Drag소스를 Buffer전환하여 원 소스에 넘김
public void javaToNative(Object object, TransferData transferData) {
if (!checkMyType(object) || !isSupportedType(transferData)) {
DND.error(DND.ERROR_INVALID_DATA);
}
MyType[] myTypes = (MyType[]) object;
try {
// write data to a byte array and then ask super to convert to
// pMedium
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream writeOut = new DataOutputStream(out);
for (int i = 0, length = myTypes.length; i < length; i++) {
byte[] buffer = myTypes[i].fileName.getBytes();
writeOut.writeInt(buffer.length);
writeOut.write(buffer);
writeOut.writeLong(myTypes[i].fileLength);
writeOut.writeLong(myTypes[i].lastModified);
}
byte[] buffer = out.toByteArray();
writeOut.close();
super.javaToNative(buffer, transferData);
} catch (IOException e) {
}
}
//Drop시 받은것을소스를 Buffer전환하여 원 소스에 넘김
public Object nativeToJava(TransferData transferData) {
if (isSupportedType(transferData)) {
byte[] buffer = (byte[]) super.nativeToJava(transferData);
if (buffer == null)
return null;
MyType[] myData = new MyType[0];
try {
ByteArrayInputStream in = new ByteArrayInputStream(buffer);
DataInputStream readIn = new DataInputStream(in);
while (readIn.available() > 20) {
MyType datum = new MyType();
int size = readIn.readInt();
byte[] name = new byte[size];
readIn.read(name);
datum.fileName = new String(name);
datum.fileLength = readIn.readLong();
datum.lastModified = readIn.readLong();
MyType[] newMyData = new MyType[myData.length + 1];
System.arraycopy(myData, 0, newMyData, 0, myData.length);
newMyData[myData.length] = datum;
myData = newMyData;
}
readIn.close();
} catch (IOException ex) {
return null;
}
return myData;
}
return null;
}
//기본생성자
protected String[] getTypeNames() {
return new String[] { MYTYPENAME };
}
//기본생성자
protected int[] getTypeIds() {
return new int[] { MYTYPEID };
}
boolean checkMyType(Object object) {
if (object == null || !(object instanceof MyType[]) || ((MyType[]) object).length == 0) {
return false;
}
MyType[] myTypes = (MyType[]) object;
for (int i = 0; i < myTypes.length; i++) {
if (myTypes[i] == null || myTypes[i].fileName == null || myTypes[i].fileName.length() == 0) {
return false;
}
}
return true;
}
protected boolean validate(Object object) {
return checkMyType(object);
}
}
}
▶ MyTypeTransfer.java : 인스턴스 구성
package swt.drag_drop;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TransferData;
public class MyTypeTransfer extends ByteArrayTransfer {
//인스턴스 객체를 생성하기 위해 Name과 ID가 필요함
private static final String MYTYPE_NAME = "my_type_name";
private static final int MYTYPE_ID = registerType(MYTYPE_NAME);
private static MyTypeTransfer INSTANCE = new MyTypeTransfer();
public static MyTypeTransfer getInstance() {
return INSTANCE;
}
//Drag소스를 Buffer전환하여 원 소스에 넘김
public void javaToNative(Object object, TransferData transferData) {
if (!checkMyType(object) || !isSupportedType(transferData)) {
DND.error(DND.ERROR_INVALID_DATA);
}
System.out.println("test1 javaToNative:"+transferData);
//if (isSupportedType(transferData)) {
MyType[] myTypes = (MyType[]) object;
try {
// write data to a byte array and then ask super to convert to
// pMedium
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bout);
for (int i = 0, length = myTypes.length; i < length; i++) {
byte[] buffer = myTypes[i].fileName.getBytes();
out.writeInt(buffer.length);
out.write(buffer);
out.writeLong(myTypes[i].fileLength);
out.writeLong(myTypes[i].lastModified);
}
byte[] buffer = bout.toByteArray();
out.close();
super.javaToNative(buffer, transferData);
} catch (IOException e) {
e.printStackTrace();
}
//}
}
//Drop시 받은것을소스를 Buffer전환하여 원 소스에 넘김
public Object nativeToJava(TransferData transferData) {
//System.out.println("test2"+transferData);
System.out.println("test2 nativeToJava:"+transferData);
if (isSupportedType(transferData)) {
byte[] buffer = (byte[]) super.nativeToJava(transferData);
if (buffer == null) {
return null;
}
MyType[] myData = new MyType[0];
try {
ByteArrayInputStream bin = new ByteArrayInputStream(buffer);
DataInputStream in = new DataInputStream(bin);
while (in.available() > 20) {
MyType datum = new MyType();
int size = in.readInt();
byte[] name = new byte[size];
in.read(name);
datum.fileName = new String(name);
datum.fileLength = in.readLong();
datum.lastModified = in.readLong();
MyType[] newMyData = new MyType[myData.length + 1];
System.arraycopy(myData, 0, newMyData, 0, myData.length);
newMyData[myData.length] = datum;
myData = newMyData;
}
in.close();
} catch (IOException e) {
e.printStackTrace();
return null;
}
return myData;
}
return null;
}
protected String[] getTypeNames() {
return new String[]{MYTYPE_NAME};
}
protected int[] getTypeIds() {
return new int[]{MYTYPE_ID};
}
boolean checkMyType(Object object) {
if (object == null || !(object instanceof MyType[]) || ((MyType[]) object).length == 0) {
return false;
}
MyType[] myTypes = (MyType[]) object;
for (int i = 0; i < myTypes.length; i++) {
if (myTypes[i] == null || myTypes[i].fileName == null || myTypes[i].fileName.length() == 0) {
return false;
}
}
return true;
}
protected boolean validate(Object object) {
return checkMyType(object);
}
}'학습관리 > RCP' 카테고리의 다른 글
| [SWT] Win32 OLE (0) | 2020.12.19 |
|---|---|
| [SWT] 클립보드 (0) | 2020.12.19 |
| [SWT] 다이얼로그 (0) | 2020.12.19 |
| [SWT] Layout (0) | 2020.12.19 |
| [SWT] 이벤트 (0) | 2020.12.19 |