플러그인 프로젝트 선택프로젝트 이름 및 플러그인실행대상 선택기본 자바 실행버전(좀 낮게), UI 제공, RCP응용프로그램 작성여부 YesRCP 기본 템플릿 선택(3.x로 시작)패키지 기본설정RCP 기본템플릿 실행(plugin.xml선택, 개요탭에 Eclipse응용프로그램 실행)
ㅁ 기본구조 확인
기본적으로 RCP프로젝트를 생성하면 아래와 같은 기본 클래스들이 생긴다. 이 클래스들은 RCP프로그램에서 각자의 역할이 있으며, 구성하고있는 역할을 알고 있어면 훗날 개발을 진행할 때 진행이 수월하다.
Application
RCP프로그램의 main routine으로 동작 및 프로그램의 컨트롤러 역할을 한다. 또한 Workbench와 다른 Workbench Advisor라고 불리는 다른 클래스들을 연결시키는 역할한다. 이때 Workbench는 프로그램 하나를 말한다. Workbench는 Worbench Window을 포괄하는 개념이며, 예를 들어 새로운 이클립스창이 띄워졌을때 New window를 하면 하나의 창이 더 띄워진다. 이때 각각의 창은 Workbench Window이고, 2개가 존재한다. 하지만 Workbench는 창이 늘어나도 하나로 존재하게된다.
WorkbenchAdvisor
Workbench의 lifecycle에 대해 명시하고 있다. default perspective와 같은 중요한 파라미터들을 Workbench에 제공한다. 가장 중요한 점은 WorkbenchAdvisor의 메소드들은 오버라이드가 될 수 없다.
WorbenchWindowAdvisor
상태 line, 툴바. 제목. 윈도우 사이즈 등 커스터마이즈 하길 원하는 것들이 들어간다.
Perspective
view, editor, menu들의 위치와 사이즈를 갖고있음 적어도 하나의 perspective는 가지고 있어야 한다.
View
화면을 담당하는 부분이다. 곧, 뷰어들을 생성하고 초기화를 진행한다. 화면을 Viewer의 컨트롤에 요청하는 setFocus()와 모든 구성 요소들을 활성화하는 CreatePartControl(Composite) 함수가 반드시 필요하다. 이 두 함수는 처음 실행될때 호출된다. setFocus() createPartControl(Composite)는 시키기 위해 선언하는 곳이다
10가지의 플러그인 중 큰 몇가지만 설명하고자 한다.
UI Workbench: UI Workbench는 editor, view, perspective 등을 포함하고 있다.
SWT: 운영체제의 네이티브 윈도우 환경과 긴밀하게 통합된 다양한 컴포넌트와 플랫폼 독립적인 API를 제공한다. 즉, 윈도우에서 정의한 위젯에 대한 접근을 제공한다.
JFACE: 범용 UI 개념을 위한 구조와 편의기능을 제공한다. SWT를 이용하여 사용자 인터페이스를 개발할 때 해야하는 많은 공통 작업들을 간단하게 해 주는 컴포넌트와 헬퍼 유틸리티 세트를 제공 데이터 뷰, 위저드, 다이얼로그 컴포넌트 등을 제공하기 위해 SWT를 확장하는 많은 유틸리티 클래스들을 포함하고 있다.
RUNTIME: 플러그인과 페이지 로딩 및 초기화 간에 확장 포인트 모델 기반의 느슨한 결합을 정의하고 있다.
OSGi: 이클립스에서 플러그인의 발견 및 애플리케이션의 재시작 없이 플러그인을 로딩 및 언로딩하는 것을 포함하여 플러그인의 라이프사이클 관리등을 위한 프레임워크이다.
드레그 와 드롭은 일상에서 많이 사용하고 있다. 근데 개발툴에서는 많이 사용하지 않았지만 앞으로 개발툴도 이러한 기능으로 소스코딩양을 줄여주는것이 좋을것 같다.
이기능은 사용하려면 드래그 하는 곳과 드롭하는 곳에 상호작용 및 순서가 필요하다.
드래그소스->드롭타깃->드롭효과->트랜스
먼저 드레그 클래스 계층도를 살펴보자
ㅁ 드레그 소스
드레그 소스에는 여러가지 형태가 있을수 있다
가령 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();
}
}
구현시 처리되는동영상을 참고하세요
Drag 처리
ㅁ 드롭 타겟
다음은 드롭소스를 예제로 생성해 보았다 반대로 드레그는 이클립스에 자바소스에서 드롭은 개발된 소스에서 받는걸로 예제를 처리했다.
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();
}
}
여기도 동영상을 보면 어떻게 구현했는지를 알수 있다.
Drop
ㅁ 사용자 포멧 드레그 엔 드롭
개발하다보면 사용자 포멧에 데이터를 드레그 엔 드롭을 하고 싶을때가 있다
▶ MySimpleDragAndDrop에서 화면구성 및Drag소스를MyType으로Table에TableItem 객체로 구성
<Context>
<Resource
maxWait="-1"
maxIdle="10"
maxActive="20"
username="[아이디]"
password="[패스워드]"
url="jdbc:mysql://[ip]:3307/work"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
auth="Container"
name="jdbc/MyBoard1"/>
<!--
auth : 컨테이너를 자원 관리자로 기술
name : JDBC이름, 변경 가능
driverClassName : JDBC 드라이버
type : 웹에서 이 리소스를 사용할 때 DataSource로 리턴됨
username : 접속계정
password : 접속할 계정 비밀번호
loginTimeout : 연결 끊어지는 시간
maxActive : 최대 연결 가능한 Connection수 (기본 20개)
maxIdle : Connection pool 유지를 위해 최대 대기 connection 숫자
maxWait : 사용 가능한 커넥션이 없을 때 커넥션 회수를 기다리는 시간 (1000 = 1초)
testOnBorrow : db에 test를 해볼 것인지
-->
</Context>
<%@ page import="javax.naming.*, javax.sql.*, java.sql.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
Connection con = null;
PreparedStatement stmt = null;
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
//resource명과 res-ref-name과 일치하는 이름
DataSource ds = (DataSource) envCtx.lookup("jdbc/MyBoard1");
con = ds.getConnection();
String msg = "disconnection";
if (con != null) {
msg = "connection";
}
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>
Results =
<%=msg%></h2>
</body>
</html>
▶ 자바사용
package com.board.dicws.lib;
import java.sql.Connection;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DBConnection {
public static Connection getConnection() throws SQLException, NamingException, ClassNotFoundException {
Context initCtx = new InitialContext();
// initCtx의 lookup메서드를 이용해서 "java:comp/env" 에 해당하는 객체를 찾아서 evnCtx에 삽입
Context envCtx = (Context) initCtx.lookup("java:comp/env");
// envCtx의 lookup메서드를 이용해서 "jdbc/MyBoard1"에 해당하는 객체를 찾아서 ds에 삽입
DataSource ds = (DataSource) envCtx.lookup("jdbc/MyBoard1");
// getConnection메서드를 이용해서 커넥션 풀로 부터 커넥션 객체를 얻어내어 conn변수에 저장
Connection conn = ds.getConnection();
return conn;
/*
* 위의 코드를 아래와 같이 줄여서 작성 가능하다. Context context = new InitialContext(); DataSource
* dataSource = (DataSource) context.lookup("java:comp/env/jdbc/oracle");
* Connection con = dataSource.getConnection();
*
*/
}
}
2) server.xml과 context.xml을 이용한 연결
1-1) DBCP 정보설정
server.xml 편집 : GlobalNamingResources 테그에 Resource 추가
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
<Resource
maxWait="-1"
maxIdle="10"
maxActive="20"
username="[아이디]"
password="[패스워드]"
url="jdbc:mysql://[ip]:3307/work"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
auth="Container"
name="jdbc/MyBoard1"/>
<!--
auth : 컨테이너를 자원 관리자로 기술
name : JDBC이름, 변경 가능
driverClassName : JDBC 드라이버
type : 웹에서 이 리소스를 사용할 때 DataSource로 리턴됨
username : 접속계정
password : 접속할 계정 비밀번호
loginTimeout : 연결 끊어지는 시간
maxActive : 최대 연결 가능한 Connection수 (기본 20개)
maxIdle : Connection pool 유지를 위해 최대 대기 connection 숫자
maxWait : 사용 가능한 커넥션이 없을 때 커넥션 회수를 기다리는 시간 (1000 = 1초)
testOnBorrow : db에 test를 해볼 것인지
-->
</GlobalNamingResources>
사이트에서 일하다보면 엑셀로 무수히 많은 엑셀자료를 만들기는 하는데 이걸 참조해서 개발하는 개발자는 너무많은 자료에 치여사는경우가 많다 그래서 생각한것이 하나의 만들어놓은 엑셀에서 관련되어 있는 엑셀을 query를 실행하여 조회하는 메크로를 작성해보았다
전에 Database를 사용하기 위해서는 ODBC드라이버가 있어야된다고 했는데 ODBC드라이버를 확인해보자
1) ODBC설치 확인(기본으로 OFFICE를 설치하면 설치된는것을 알수 있다)
2) 참조에 Microsoft ActiveX DataObject 2.8 Library를 추가 : ADODB 객체를 사용하려구
3) 일단 엑셀을 sql로 조회하기 위한 엑셀을 하나 준비한다
4) 엑셀을 DataBase처럼 Connection을 실행해서 잘 연결되는지 확인해보자
특이하게 Provider를 사용하여 쓰고 뒤에 Properties가 더 붙는다
Public dbcon As ADODB.Connection
Public dbcon As ADODB.Connection
Public Sub ExcelCon() '=>실행시 문제가 없는지 확인
Dim strCon As String '연결String
Dim driver, dsrc
dsrc = "D:\엑셀DB테스트.xlsx" '파일명
'엑셀파일을 DataBase처럼 연결
strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & dsrc & ";Extended Properties=Excel 12.0;"
Set dbcon = New ADODB.Connection
dbcon.Open strCon '연결
End Sub
5) 연결이 잘되었으면 RecordSet으로 받아 엑셀에 출력을 해보자
Public Sub getExcelEtcSel()
Dim rs, sql, colCnt, wRow, i
ExcelCon
sql = "select * from [Sheet2$] " '->조건없이 전부 조회
Debug.Print sql
'Set rs = CreateObject("ADODB.RecordSet")
Set rs = New ADODB.Recordset
rs.Open sql, dbcon
wRow = ActiveSheet.Range("B4") '작성시작 row
colCnt = rs.Fields.Count
'컬럼에 head를 시작에 달아줌
For i = 0 To colCnt - 1
ActiveSheet.Cells(wRow, i + 1) = rs.Fields(i).Name
Next
setHeaderStyle wRow 'header 스타일 적용
wRow = wRow + 1
If rs.EOF = False Then
Do While rs.EOF = False
For i = 0 To colCnt - 1
ActiveSheet.Cells(wRow, i + 1) = rs(rs.Fields(i).Name) '레코드셋에 이름으로 매핑하여 표시
Next
wRow = wRow + 1
rs.MoveNext
Loop
End If
End Sub
6) 엑셀에 특정영역중에 query를 사용할경우와 컬럼명을 기술할때 일반 query와 상이함
sql = "select [컬럼1],[컬럼2] from [Sheet2$A2:G5] "
- 시트전체조회시 [시트명$]
- 시트에일부영역시 [Sheet2$A2:G5] -> sheet2에 A2:G5 영역중 조회
- 컬럼은 위처럼 중괄호를 해야되고 중복된 컬럼명이 있으면 임의로 넘버링을 붙임
단독적으로 쓸일은 많지는 않았다 그보다 현재 많은 정보들이 있다보니 각종 소스들에 대해서 목록으로 처리해야될일이 많아졌다 생각 되어진다.
프로젝트에서 말하자면 현황파악
제일먼저 특정경로에 소스를 가져왔을때 해당 소스하위까지 포함하여 폴더에 목록을 엑셀로 작성해보자
1) 엑셀시트 화면 구성
B1에는 검색하려는 기본경로 기입
B2에는 기존 목록을 삭제하고 다시 작성할건지 여부
B3에는 전체작성된 건수를 엑셀함수를 써서 기입=COUNT(A9:A1048576)
2) 소스작성
먼저 파일을 사용하기 위해 참조를 하자
직접 CreationObject를 사용하여도 되지만 ctrl+space로 자동완성기능을 사용하기 위하여
참조를 통하여 객체를 넣는 작업을 한다
다음은 엑셀 코딩을 하자
Option Explicit '명시적으로 항상 어떤변수를 사용했는지 확인하는게 신상에좋다
Dim wRow '파일을 엑셀시트에 저장하기 위해 선언==> 말하자면 전역변수선언
Public Sub getFileList() '==>실행하는 함수
Dim rc
wRow = 9 '기본은 9부터
If ActiveSheet.Range("B2") = "Y" Then '삭제여부를 보고 삭제작업
rc = MsgBox("삭제해도 될까요?", vbYesNo, "삭제경고")
If rc = vbYes Then
Rows(wRow & ":" & wRow).Select
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Delete Shift:=xlUp
Else
Exit Sub
End If
'타이틀을 작성한다
ActiveSheet.Cells(wRow, 1) = "NO"
ActiveSheet.Cells(wRow, 2) = "파일명"
ActiveSheet.Cells(wRow, 3) = "경로"
ActiveSheet.Cells(wRow, 4) = "타입"
ActiveSheet.Cells(wRow, 5) = "Size"
ActiveSheet.Cells(wRow, 6) = "비고"
'이건별도 나만에 함수로 생략 setHeaderStyle wRow 'header 스타일 적용
wRow = wRow + 1
Else
wRow = ActiveSheet.Range("B3") + 10 '삭제를 안하고 추가하는경우 헤더포함하여 다음써야될행
End If
'b1에 입력된 기본 경로하위 폴더 및 파일목록을 작성시작
FolderFile ActiveSheet.Range("B1")
End Sub
Function FolderFile(fn As String)
Dim fs As FileSystemObject
Set fs = New FileSystemObject
Dim foldeer As Folder
Dim fileinfo
Dim Filnavn() As String
Set foldeer = fs.GetFolder(fn)
'해당폴더에 파일이 있는경우
For Each fileinfo In foldeer.Files
ActiveSheet.Cells(wRow, 1) = wRow - 9 '기본자릿수
ActiveSheet.Cells(wRow, 2) = fileinfo.Name '파일명
ActiveSheet.Cells(wRow, 3) = Mid(fileinfo.path, 1, Len(fileinfo.path) - Len(fileinfo.Name)) 'path에 파일명까지 같이 들어오므로 파일명 길이만큼 잘라path만입력
ActiveSheet.Cells(wRow, 4) = fileinfo.Type
ActiveSheet.Cells(wRow, 5) = fileinfo.Size
wRow = wRow + 1 '작성후 다음위치 + 1
Debug.Print "F " & fileinfo
Next
For Each Folder In foldeer.SubFolders 'sub폴더가 있는경우
Debug.Print "D " & Folder
FolderFile (Folder) '재귀함수로 자신을 다시 부름
Next
End Function
파일처리 목록완성 예시
3) 하이퍼링크를 활용하여 클릭시 자동열리게 하자
요즘은 하도 참조하는 문서가 많아 헷갈리는경우가 많다 저같은경우 목록을 작성하고
뒤에 비고란에 확인한 내용 및 주요 참고내용등을 적어놓고 다시 열때는 클리하여 자동열기를 주로 사용하고 있다