Drag & Drop의 구현
스윙에서의 Drag & Drop 을 구현해 보자. 과정이 꽤 복잡하고 기능상에 약간의 제약은 있으나 한번 구현해 볼 만한 예제라고 생각을 한다. 소스코드는 자바소프트에서 발췌했음을 알아두길 바란다. 중간중간에 풍선도움말을 두겠으니 단풍잎에 마우스를 갖다대면 도움말이 뜨니 참고하길 바란다.
| Drag & Drop 을 구현하는 것은 비교적 쉽다. 그렇지만 가장 난해한 것은 모든 과정에 대해서 이해하는 것이다. 다음의 순서를 먼저 익혀두길 바란다. [ DnD Source Download] 1. Drag source 에 대한 참조를 가진다. - DragSource.getDefaultSource() 나 new DragSource() 를 통해서. 2. Drag gesture recognizer 를 생성한다. - DragSource.createDafaultGestureRecognizer() 3. Drop target 를 생성한다. - 하나의 컴포넌트와 Drop target listener 를 명세한다. 4. Transferable 로 옮겨질 수 있는 데이타를 wrap 한다. 5. Drag 를 초기화한다. - DragSource.startDrag() 6. DropTargetLisenter, DragSource 인터페이스를 구현함으로써 Drop 를 핸들링한다. Drag & Drop (이하 D&D) 는 하나의 datasource 와 여러개의 droptarget 에 - 흔히 콤포넌트와 연관되어져 있다 - 와 연관되어 이뤄진다. 다음에 나열된 클래스와 인터페이스는 D&D 에서 사용되는 것을 정리한 것이다. 대부분의 것들은 java.awt.dnd 패키지에 있고, 오직 하나 Transferable 은 java.awt.datatransfer 패키지에 있다. DragGestureRecognizer : 컴포넌트에서 drag 를 수행할려고 할때 이벤트를 발사한다. DragSource 는 startDrag() 메소드로 초기화작업을 수행하고, createDragGestureRecognizer() 나 createDafaultDragGestureRecognizer() 를 이용하여 DragGestureRecognizer 를 생성하게 되는 것이다. DropTarget 은 하나의 컴포넌트와 Listener 객체와 연관되어 있어서 drop target event 가 발생할때 listener 객체가 통보를 받게 된다. DragGestureListener 는 recognizer 에 의해 drag gesture 를 통보받는데 전형적인 반응예는 DragSource.startDrag() 메소들르 호출하게 되었을 경우이다. DragSourceListener 는 drag 가 초기화된 후 dragsource 에서 일어나게 된다. 다소 나열적인 설명이었지만 어느 정도 감을 잡기 위해서 중복 설명했다. D&D 하는 과정과 메소드호출, 클래스와 인터페이스의 API 를 꼼꼼하게 살펴보면 이해할 수 있으리라 생각한다. 가장 기본적인 D&D 를 하기 위해서는 반드시 DragSource, DropTarget, DragGestureRecognizer, Transferable 이 반드시 생성이 되어야 하고, Listener 가 구현되어야 한다는 것을 명심하길 바란다. 그러나 실제 구현은 몇가지 객체를 생성하고 데이타를 Wrapping 하고 핸들링하는 것을 빼면 나머지 동작은 프로그래머 재량에 상관없이 자체적으로 구현이 된다. |
| 여기서도 두가지 방법이 있을 수가 있는데 한가지 방법으로는 Swing Component 를 상속해 객체를 만들어 그것을 DragSource, DropTarget 으로 만들어 사용하는 방법과 제 3의 콤포넌트를 생성해 두가지를 수행하는 방법이 있다. 첫번째 방법으로 수행을 하면 반드시 객체만이 D&D 특성을 가질수가 있고, 표준 Component 는 그런 특성을 공유할 수 없음을 명심하길 바란다. 가령 JList 를 상속한 ListDragSource 객체를 만들어서 D&D 를 추가해 사용한다면 ListDragSource 만이 그런 동작을 할 수 있다는 것을 의미한다. 아래에 있는 그림은 이 프로그램을 실행시켰을때 볼 수 있는 화면이다. 왼쪽은 DragSource 로 JTree 를 이용해 구현했고, 오른쪽은 DropTarget 은 JTextPane 을 이용해 구현했음을 보길 바란다. 이것은 .txt 와 .java 로만 한정되어 있기 때문에 다른 확장자를 가진 파일을 D&D 했을 경우에는 에러창을 발견하게 될 것이다. 그리고 .txt 와 .java 파일은 그 내용을 JTextPane 에서 볼 수 있을 것이다. 오른쪽의 파일을 D&D 수행할 수가 있다 확장자가 .txt 와 .java 가 아닐 경우에 볼 수 있는 경고창이다. 위의 프로그램은 얼마든지 응용해서 확장할 수 있다고 생각한다. 다른 파일도 볼 수 있게끔 할 수 있고, image 도 가능하리라 생각한다. 다음 장에서는 소스코드 분석에 들어가도록 하겠다. 먼저 해당 API 를 꼼꼼히 살펴본 다음에 코드분석에 임하길 바란다. |
이번 장에서는 소스분석과 함께 설명을 하겠다. 단풍잎 부분에 API 에 대한 설명을 첨가하겠다.
DragTree.java 소스이다. 이전 장에서 본 JTree 부분의 DragSource 를 정의한 부분이다. import java.awt.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.tree.*; import java.io.*; class DragTree extends JTree implements DragGestureListener, DragSourceListener { public DragTree() { DragSource dragSource = DragSource.getDefaultDragSource(); // static 메소드인 위 메소드로 DragSource 에 대한 참조를 얻는다. 그리고, 위 참조객체를 이용해 DragGestureRecognizer 를 생성하게 되는 것이다. dragSource.createDefaultDragGestureRecognizer( this, // component where drag originates DnDConstants.ACTION_COPY_OR_MOVE, // actions this); // drag gesture recognizer
|
| Test.java 소스이다. main() 와 기본 인터페이스가 설정돼 있다. 아래의 코드를 살펴보면 알겠지만 Test 생성자는 drop target 을 생성해낸다. 즉 TextPane 을 drop target component 로 생성하는 것이다. 실제 drop 이 일어났을때 Test.drop() 메소드가 호출이 된다. drop 과 연관된 transferable 은 String 으로써 데이타를 제공해주며 drop 을 받아들인 후에 readFile() 메소드가 호출이 돼 file 의 내용을 TextPane 으로 로딩을 하게 된다. Drop 이 완료된 후 e.dropComplete(true) 가 호출이 돼 실제 drop 이 완료되게 된다. import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; import java.awt.*; import java.awt.event.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import java.io.*; public class Test extends JFrame implements DropTargetListener { private JTextPane textPane = new JTextPane(); public Test() { super("Drag and Drop With Swing"); new DropTarget(textPane,DnDConstants.ACTION_COPY_OR_MOVE,this); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,createTreePanel(),createTextPanel()); splitPane.setDividerLocation(250); splitPane.setOneTouchExpandable(true); getContentPane().add(splitPane, BorderLayout.CENTER); } public static void main(String args[]) { Test test = new Test(); test.setBounds(300,300,850,350); test.setVisible(true); test.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); test.addWindowListener(new WindowAdapter() { public void windowClosed(WindowEvent e) { System.exit(0); } }); } private JPanel createTreePanel() { JPanel treePanel = new JPanel(); DragTree tree = new DragTree(); treePanel.setLayout(new BorderLayout()); treePanel.add(new JScrollPane(tree), BorderLayout.CENTER); treePanel.setBorder(BorderFactory.createTitledBorder( "Drag source for filenames")); return treePanel; } private JPanel createTextPanel() { JPanel textPanel = new JPanel(); textPanel.setLayout(new BorderLayout()); textPanel.add(new JScrollPane(textPane),BorderLayout.CENTER); textPanel.setMinimumSize(new Dimension(375,0)); textPanel.setBorder(BorderFactory.createTitledBorder( "Drop target for filenames")); return textPanel; } private void readFile(final String filename) { EditorKit kit = textPane.getEditorKit(); Document document = textPane.getDocument(); try { document.remove(0,document.getLength()); kit.read(new FileReader(filename), document, 0); } catch(Exception ex) { ex.printStackTrace(); } } public void drop(DropTargetDropEvent e) { try { DataFlavor stringFlavor = DataFlavor.stringFlavor; Transferable tr = e.getTransferable();
출처:http://www.javastudy.co.kr/docs/b612/swing/draganddrop.html |
JAVA를 이용하여 응용프로그램을 만들던 중 소스가 없을경우, 혹 잃어버린경우
이전에 컴파일 해놓은 .class 파일을 역컴파일 해서 소스를 볼수있다.
Jad 라는 JAVA Decompiler 라는 툴이며 이클립스 사용자들은
플러그인 추가로 이클립스 에서 볼수있는 방법이다.
대표적인 자바 디컴파일러인 jad와 이클립스 플러그 jadclipse를 설치하자.
당연하게도 활용방법은
1. 잃어버린 .java 소스파일을 .class 파일로부터 복원
2. API에 대한 소스레벨 탑색이다.
특별한 설정은 필요치 않다.
두개의 압축파일을 다운받으면 된다.
1. jad 다운
사이트 : http://www.kpdus.com/jad.html
파일(window용 파일) : http://www.kpdus.com/jad/winnt/jadnt158.zip
2. jadclipse 다운
사이트 : http://jadclipse.sourceforge.net/wiki/index.php/Main_Page#Download
파일(eclipse3.2.0) : http://prdownloads.sourceforge.net/jadclipse/jadclipse_3.2.0.jar?download
파일(eclipse3.2.4) : http://prdownloads.sourceforge.net/jadclipse/net.sf.jadclipse_3.2.4.jar?download
3. 설치방법
적당한 디렉토리에 압축을 푼다.
jad 파일을 eclipse 루트 디렉토리에 복사한다.
jadclipse 는 eclipse의 plugin 디렉토리에 통채로 복사한다.
4. 환경설정
이클립스 실행후
창/환경설정/일반/편집기/파일연관 으로 이동
JadClipse Class File Viewer를 선택하고 기본값을 클릭한다.
창/환경설정/Java/JadClipse 로 이동
Reuse code buffer 체크
창/환경설정/Java/JadClipse/Misc 로 이동
Convert Unicode string into ANSI strings 체크
=> 한글 깨짐 문제 해결
Explanation &
Example
Hierarchical query를 구현할 때 ORDER BY 절을 사용하는 것은
Oracle 7.1 버젼부터 가능한 것이었다.
그러나, 순서대로 ordering되지 않고 특정 컬럼(emp table의
ename)을
기준으로 ordering하기를 원한다면 <Bulletin:10373>처럼 procedure를
작성하여야만 하였다.
그러나, Oracle 9i 에서는 ORDER BY 절 대신에 ORDER SIBLINGS BY 절을
사용할 수 있어 user-defined stored procedure를 만들 필요가 없게 되었다.
1) Ordering 하기 전의 emp table의 Hierarchical query
SQL> @a
ename EMPNO MGR
JOB
------------------------- ------ ------ ---------------
KING 7839 PRESIDENT
JONES
7566 7839 MANAGER
SCOTT 7788 7566
ANALYST
ADAMS 7876 7788 CLERK
FORD 7902 7566 ANALYST
SMITH 7369 7902
CLERK
BLAKE 7698 7839 MANAGER
ALLEN 7499 7698 SALESMAN
WARD 7521 7698
SALESMAN
MARTIN 7654 7698 SALESMAN
TURNER 7844 7698 SALESMAN
ename EMPNO MGR
JOB
------------------------- ------ ------ ---------------
JAMES 7900 7698 CLERK
CLARK 7782 7839
MANAGER
MILLER 7934 7782 CLERK
14 rows selected.
Ordering 하기 전의 a.sql 은 다음과 같다.
col ename format a25
col empno format
99999
col mgr format 99999
col job format a15
select rpad(' ',
LEVEL*5) || ename "ename", empno, mgr, job
from emp
start with
job='PRESIDENT'
connect by prior empno=mgr;
/
2) 9i의 new feature인 Hierarchical query를 사용하여
Ordering한 경우
SQL> @new_a
ename EMPNO MGR
JOB
------------------------- ------ ------ ---------------
KING 7839 PRESIDENT
BLAKE
7698 7839 MANAGER
ALLEN 7499 7698
SALESMAN
JAMES 7900 7698 CLERK
MARTIN 7654 7698 SALESMAN
TURNER 7844 7698
SALESMAN
WARD 7521 7698 SALESMAN
CLARK 7782 7839 MANAGER
MILLER 7934 7782
CLERK
JONES 7566 7839 MANAGER
FORD 7902 7566 ANALYST
ename EMPNO MGR
JOB
------------------------- ------ ------
---------------
SMITH 7369 7902
CLERK
SCOTT 7788 7566 ANALYST
ADAMS 7876 7788 CLERK
14 rows selected.
Ordering하기 위해 사용한 new_a.sql 은 다음과 같다.
col ename format a25
col empno format
99999
col mgr format 99999
col job format a15
select rpad(' ',
LEVEL*5) || ename "ename", empno, mgr, job
from emp
start with
job='PRESIDENT'
connect by prior empno=mgr
order siblings by
ename;
/
HIERARCHICAL QUERY DATA의 SORT와
ORDERING
ORACLE 6에서의 HIERARCHICAL QUERY에서는 SORT를 하기 위한 ORDER BY 절을
사용
할 수 없었다. 그러나, ORACLE 7.1이상 VERSION에서는 USER-DEFINED STORED
PROCEDURE를
이용하여 HIERARCHY 순서로 출력되면서 ORDERING할 수 있게 되었다.
세계의 지역에 관한 자료를 예로 보자.
CREATE TABLE UNIVERSE
( PARENT
VARCHAR2(30) REFERENCES UNIVERSE,
NAME VARCHAR2(30) PRIMARY KEY );
REM SOME TEST DATA
INSERT INTO UNIVERSE VALUES (
NULL, 'WORLD' ) ;
INSERT INTO UNIVERSE VALUES ( 'WORLD', 'EUROPE' ) ;
INSERT INTO UNIVERSE VALUES ( 'EUROPE', 'ENGLAND' ) ;
INSERT
INTO UNIVERSE VALUES ( 'EUROPE', 'THE NETHERLANDS' ) ;
INSERT INTO
UNIVERSE VALUES ( 'EUROPE', 'GERMANY' ) ;
INSERT INTO UNIVERSE VALUES
( 'WORLD', 'ASIA' ) ;
INSERT INTO UNIVERSE VALUES ( 'ASIA', 'JAPAN' )
;
INSERT INTO UNIVERSE VALUES ( 'ASIA', 'CHINA' ) ;
INSERT
INTO UNIVERSE VALUES ( 'WORLD', 'AMERICA' ) ;
INSERT INTO UNIVERSE
VALUES ( 'AMERICA', 'UNITED STATES' ) ;
INSERT INTO UNIVERSE VALUES (
'AMERICA', 'MEXICO' ) ;
INSERT INTO UNIVERSE VALUES ( 'WORLD', 'AFRICA'
) ;
INSERT INTO UNIVERSE VALUES ( 'AFRICA', 'EGYPT' ) ;
INSERT INTO UNIVERSE VALUES ( 'AFRICA', 'MOROCCO' ) ;
위의 자료를 다음과 같이 보고자 하는 경우
WORLD
AFRICA
EGYPT
MOROCCO
AMERICA
MEXICO
UNITED STATES
ASIA
CHINA
JAPAN
EUROPE
ENGLAND
GERMANY
THE
NETHERLANDS
만약,ORDER BY절이 없이 QUERY하면
SELECT RPAD( ' ', LEVEL * 5 ) || NAME FROM UNIVERSE
CONNECT
BY PRIOR NAME = PARENT START WITH PARENT IS NULL;
다음과 같은 결과를 얻게 된다.
WORLD
EUROPE
ENGLAND
GERMANY
THE NETHERLANDS
ASIA
JAPAN
CHINA
AMERICA
UNITED STATES
MEXICO
AFRICA
EGYPT
MOROCCO
만약, 위 문장에 ORDER BY 절을 사용하면
SELECT RPAD( ' ', LEVEL * 5 ) || NAME FROM UNIVERSE
CONNECT BY PRIOR NAME = PARENT START WITH PARENT IS NULL
ORDER BY NAME;
다음과 같은 원치 않는 결과를 얻게 된다.
AFRICA
AMERICA
ASIA
CHINA
EGYPT
ENGLAND
EUROPE
GERMANY
JAPAN
MEXICO
MOROCCO
THE NETHERLANDS
UNITED STATES
WORLD
7. 1이상 VERSION에서는 다음과 같이 USER DEFINED FUNCTION을 이용하여
원하는 자료를 얻을 수 있다.
CREATE OR REPLACE FUNCTION UNIVERSESORTORDER( PKEY
UNIVERSE.NAME%TYPE )
RETURN VARCHAR2 IS
PATH
VARCHAR2(2000);
BEGIN
PATH := PKEY;
-- INSERT
ALL PREVIOUS PARENT RECORDS LIKE A DIRECTORY STRUCTURE
-- E.G.
WORLD/EUROPE/...
FOR CREC IN ( SELECT PARENT FROM UNIVERSE
CONNECT BY PRIOR PARENT = NAME
START WITH NAME = PKEY ) LOOP
PATH :=
CREC.PARENT || '/' || PATH;
END LOOP;
RETURN PATH;
END;
/
SELECT SUBSTR( RPAD( ' ', LEVEL * 5) ||
NAME, 1, 40) "THE UNIVERSE"
FROM UNIVERSE
CONNECT BY PRIOR
NAME = PARENT
START WITH PARENT IS NULL
ORDER BY
UNIVERSESORTORDER( NAME ) ;
Properties - Run/Debug Settings - Arguments tab - VM arguments 로 이동하여 아래의 그림과 같이 설정한다 .
[-Xms256m, -Xmx1024m] 로 -Xms 는 최소, -Xmx 는 최대로 메모리로, 사용자의 편의에 맞게 적당히 지정한다
추가사항 (02/March/2009): 간혹 온라인 게임 프리서버를 돌리기 위해서 나타나는 java sql heap 스페이스 방법에는 사용되지 않습니다, 혹시 class 파일을 변경한다면 될지 모르겟네요.
위에 표기된 해결 방법은 이클립스에서 실행하는 어플에 적용된다고 알려드리고 싶습니다..
sqlite를 일단 설치했습니다..
설치 방법은 루비가 설치된 콘솔 창에 "gem install sqlite3-ruby" 으로 설치하시면 됩니다. .
hello.app 를 실행합니다. 그결과 또다른 에러가 발생합니다..
에러내용은 sqlite3.dll 이 없다고 나오네요 http://sqlite.org/download.html 에 가셔서 dll 파일을 받아 Windows\system32 아래 넣어주시면 모든 에러가 해결됩니다.
정말 기본 비기닝 책이 이렇게 힘들줄은 몰랐습니다 ㅠ 이오류는 sqllite 라는 DB에 관한 오류지만 책에서는 Mysql 을 다룹니다 ㅠㅠ 흐악 과연 또다른 문제가 어떻게 발생할지 모르겠군요...
이올린에 북마크하기
ireceiverWindowversion.exe
iReceiver_1.0.1MacOSXversion.zip
