'JFace'에 해당되는 글 1건

  1. 2008.11.01 SWT/JFace 초짜 도전기 -(2) 안녕 세상~
SWT/JFace2008. 11. 1. 15:08

SWT, JFace가 뭐여?

자, 이제 시작해볼까? 일단 SWT, JFace가 뭔지부터 찾아봤다.

머 간단히 요약하자면 SWT(Standard Widget Toolkit)는 Swing의 단점을 보완한 IBM에서 개발해서 기증한 eclipse의 Widget Toolkit 이란다.

가장 큰 장점으로 Swing은 모든 사용자 인터페이스의 그래픽 컴포넌트들을 직접 구현한다. 하지만 SWT는 자신이 굴러가는 OS의 자원을 이용한다. 그렇기 때문에 가볍고, 그래서 속도도 Swing에 비해 빠르다고 한다.(Swing 프로그래밍을 안해봐서 직접 체험해보지 않아 이렇게 표현했다.ㅎ~ 근데 최근 소식에 의하면 Swing도 제법 빨라졌다고 한다.)

여기에 JFace는 SWT 개발을 좀 더 쉽게 하기 위해 모델 기반으로 쪼겠다. 모델 중엔 MVC 모델이 젤루 유명하지? 이와 유사하게 쪼갠거 같다.

 

허접 SWT 만들어보기

SWT는 크게 Display, Shell, Widget 으로 구성된다. OS 위에 Display를 얹고(이건 단지 Display 객체를 생성하면 자동 얹어진다~), 그 Display 객체에다가 Shell 객체를 얹고, 그 Shell 객체에다가 Widget 객체를 얹는다. 머 쉽네~ 함 해보까?

(다행히 객체를 생성할 땐 new {class 명} 하는건 안다.ㅋㅋㅋ...)

 

Display display = new Display(); //<-- Display 객체를 생성하고(이럼 OS 위에 얹어진다) 

Shell shell = new Shell(display); //<-- display 객체에다가 Shell 객체를 얹고,      

Text helloText = new Text(shell, SWT.CENTER); //<-- shell 객체에다가 Text Widget을 얹는다.

 

근데 다른 건 다 얹고자 하는 객체만 파라미터로 받는데 Text 객체는 인자가 두개네? SWT.CENTER 는 뭐야?

class 구조를 가지고 유추해본다면 swt class의 멤버변수 쯤 되나보다. 권한은 public 으로 되어있으니깐 외부에서도 직접 접근할 수 있겠지? ^^

이건 대충 이렇게 하고 넘어가자.  

가만, 얹으기만 하면 다 되는게 아니자나? 아무리 얹으면 뭐해. 화면에 나와야지. 지금까진 단지 초기화만 했을 뿐이다.

 

shell.open(); //<-- 자! 열고!

 

근데 이게 끝난게 아니란다!! 헉! 열면 다 끝난거 아냐?

우리가 엑셀같은 프로그램을 쓸 때를 생각해보면 그제사 이해가 간다.

엑셀을 쓸 때 프로그램 열고 땡인가? 아니자너~ 거다가 글도 쓰고, 숫자도 넣고, 수식도 넣어서 계산도 하고, 차트도 넣고, 별별 짓을 다 한다.

그럼 그동안 이 엑셀프로그램은 내가 하는 짓을 다 받아줘서 원하는대로 해줘야 할 것 아닌가.ㅋㅋㅋ

 

그럼 이것도 마찬가지로 해야지. 자 내가 뭔 짓을 할지 기다리면서 그 짓들을 다 받아줘라~


while(!shell.isDisposed()){

if(!display.readAndDispatch()){

display.sleep();

}

}

 

위 코드를 분석해보자. 영어공부도 함 해보까? ^^;

dis·pose vt.
1 <군대·물건을> 배치하다, 배열하다 《for》
   《dispose+++》 dispose soldiers for the battle 병사를 전장에 배치하다

2 …할 마음이 내키게 하다 《to》(⇒ disposed 1a)
   《dispose++to do》 His advice disposed me to read it. 그의 조언으로 그것을 읽고 싶어졌다.

3 <사람에게> …의 경향을 갖게 하다, <사람에게> …의 영향을 받기 쉽게 하다 《to》(⇒ disposed 1b)
   《dispose+++》 His physique disposes him to backache. 그는 요통을 앓기 쉬운 체격이다.

4 <사무·문제 등을> 처리하다
━ vi.
1 처리하다, 처치[처분]하다
2 일의 추세[성패]를 결정하다
dispose of…을 처분하다, 처리하다, …의 결말을 짓다;팔아 버리다;해치우다, 죽이다:dispose of oneself 거취를 결정하다, 처신하다

 그럼 대충 해석해 보면 shell.isDisposed() 메소드는 무엇을 묻는 것이냐 하면 shell 객체가 일할 생각이 있냐 없냐, 또는 잘 배치되어 있냐를 묻는 것인데...

이렇게 해석한다면 생각이 있으면 true를, 일할 생각이 없이 이제 그만 둘란다 하면 false를 뱉어낼텐데... 그게 아닌가보다.

while(조건문) 문법에 따르면 {조건문}이 참(true)인 동안 계속 돈다는 것인데 거기에 not(!)을 붙였으니 shell.isDisposed() 가 false를 뱉어내는 동안 계속 돈다는 거다.

뭐 내 생각과는 반대인데 그래도 어쩌겠는가 이렇게 해야 shell이 죽지 않고 계속 화면에 떠있게 할 수 있다는데. ^^;

shell객체가 처리가 끝났냐, 일 다하고 죽었냐 하고 묻는 것이다. 아 수동태니깐 살해되었냐 군. ㅋㅋㅋ  그럼 말이 되네. shell 이 죽지 않았으면 while 문을 수행해라.

그 다음 일단 shell이 죽지 않고 돌고 있는 상태에서 display 객체에 조건을 주었다. display 객체는 OS와 통신하는 부분이다. OS바로 위에 붙어서 말이다.

display.readAndDispatch() 메소드는 ... 또 영어공부 함 해보까?

dis·patch vt.
1 <군대·특사 등을> 급파[특파]하다;<급보를> 발송하다 《to》
2 <일 등을> 재빨리 해치우다;신속히 처리하다;<식사를> 빨리 먹어치우다
3 죽이다(kill);<사형수 등을> 처형하다
━ n.
1 급파, 특파, 파견;급송, 발송, 발신; 속달편
2 급송 공문서;【신문】 급보, 특전
3 (처리 등의) 신속;날랜 처리;[U.C] 죽음에 의한 해결, 살해(killing)
   a happy dispatch 《익살》 할복 자살

4 (속달 화물) 운송 대리점
be mentioned in dispatches《영》 <군인의 이름이> 수훈(殊勳) 보고서에 오르다
with dispatch신속히, 재빠르게

(음. 앞으론 대충 뜻만 써야겠다. ^^;)

또 대충 해석해보면 readAndDispatch 라고 하면 지금 OS와 통신하고 있냐 하는 것으로 보면 되겠다. 그러니까 display 객체에게 묻는거지. "야~ 너 OS랑 이바구 까고 있냐?  이바구 안까고 있으면 display 객체에게 잠자코 있어라(sleep)" 라고 한다. 워워~

 

그럼 모든 초짜들이 반드시 넘어야 할 산 HelloWorld 를 짜보자~!!!

 

package com.swtjface.unit1; 

import org.eclipse.swt.*;

import org.eclipse.swt.widgets.*;

 

public class HelloWorld{

public static void main(String[] args){

Display display = new Display();

Shell shell = new Shell(display);

Text helloText = new Text(shell,SWT.CENTER);

helloText.setText("Hello World!");

shell.open();

 

while(!shell.isDisposed()){

if(!display.readAndDispatch()) display.sleep();

}

display.dispose();

}

}

 

자! 그럼 실행!

 

helloWorld1.gif

 

엥? 이게 뭐야? 덩그러니 창 하나만 떴다. 뭐가 문제인가?

책을 다시 보니 내가 짠 코드랑 틀린게 있네?

 

helloText.pack();

 

pack 이라 함은 팩을 싼다는 건데... 확인해보니 pack() 메소드는 구성 요소의 필요한 만큼만 공간을 사용하라는 것이다. 근데 머 필요하지 않는 공간도 그냥 쓰면 안되는건가? ^^;

어쨋든 pack()을 해야만 helloText 객체가 나타난다. 그럼 뭐 이왕 하는거 shell 도 pack()을 해서 자원절약에 동참해볼까?

 

package com.swtjface.unit1;

import org.eclipse.swt.*;

import org.eclipse.swt.widgets.*;

 

public class HelloWorld{

public static void main(String[] args){

Display display = new Display();

Shell shell = new Shell(display);

Text helloText = new Text(shell,SWT.CENTER);

helloText.setText("Hello World!");

helloText.pack();

shell.pack();

shell.open();

 

while(!shell.isDisposed()){

if(!display.readAndDispatch()) display.sleep();

}

 

display.dispose(); 

}

}

 

자! 그럼 다시 실행!

 

helloWorld2.gif

 

우헤~ 증말 pack 됐네? ㅋㅋㅋ

그럼 이제 SWT는 성공했구 JFace도 함 해보까?

 

허접 SWT/JFace 만들어보기

 JFace로도 위에 SWT로 만든 Hello World 를 똑같이 만들어본다.

그전에 JFace가 SWT와 뭐가 다른지 잠깐 알아보자.

JFace는 모델 기반 어뎁터(model-based adapters), 또는 Helper Classes 라고 한다. Helper Classes 라고 하면 머 도우미 클래스라고 생각하면 되겠지만 model 기반이라...흠. model이 뭐야? 이런건가?

model.jpg

오~~!!! 잠이 확 달아난다!!

하지만 이건 아닌것 같고.

영어사전을 뒤져보면 [모형, 설계도]로 나온다. 즉, 미리 모형을 만들어놓고 'adapter' 라고 하니깐 그걸 상속해서 변형하여 쓴다는 것이리라.

이런 model adapter classes는 크게 7가지가 있다.

  1. Viewer

  2. Action

  3. Contribution

  4. Image

  5. Font registry

  6. Dialog

  7. Wizard

그리고 SWT의 Shell 을 JFace는 대신 만들어주는 ApplicationWindow class 가 있다. 즉, Shell 을 직접 개발자가 컨트롤 할 필요없이 ApplicationWindow 객체가 기본적인 것은 다 컨트롤 해준다는 것이다. 근데 사실 아직까진 이 두개의 차이를 알지 못하겠다. 왜냐면 Shell을 직접 컨트롤 한게 그다지 복잡하지도 않았기 때문이다. 이건 앞으로 좀 더 복잡한 Shell 컨트롤을 해보게 되면 그 차이점을 알게 되리라 위안을 삼으면서 다시 JFace를 알아보자.

 

일단 HelloWorld 를 SWT 처럼 직접 정의하지 않고 JFace의 ApplicationWindow 를 상속받아서 만들어보자.

public class HelloWorld extends ApplicationWindow

 

그리고 ApplicationWindow 가 대신 만들어준다는 Shell을 만들기 위해선 ApplicationWindow 의 생성자를 그대로 사용하면 되겠지?

public HelloWorld(){

super(null);

}

 

위와 같이 하면 Display 객체와 Shell 객체가 생성된다는 것이다. 뭐 기껏해야 SWT의 두줄을 줄여준거지만 일단 믿고 가보자.

잠깐. 근데 아까 만든 SWT용 HelloWorld 를 좀 비스무리하게라도 해놔야 비교가 될 거 같다.

다음과 같이 SWT 의 HelloWorld를 바꿔봤다.

 

package com.swtjface.unit1;

 

import org.eclipse.swt.*;

import org.eclipse.swt.widgets.*;

 

public class HelloWorld{

 

Display display;

Shell shell;

 

public HelloWorld(){

display = new Display();

shell = new Shell(display);

}

 

public void createText(){

Text helloText = new Text(shell, SWT.CENTER);

helloText.setText("Hello World!");

helloText.pack();

shell.pack();

}

 

public static void main(String[] args){

helloWorld hw = new helloWorld();

hw.createText();

hw.shell.open();

 

while(!hw.shell.isDisposed()){

if(!hw.display.readAndDispatch()) hw.display.sleep();

}

 

hw.display.dispose(); 

}

}

 

자, 그럼 이제 다시 시작해볼까?

일단 생성자는 위에서 벌써 했구,

윈도우에 텍스트를 보이기 위한 부분인 createText() 메소드는 거의 변함이 없지만 단, JFace에선 ApplicationWindow에서 생성한 Shell에 표현되는 부분을 정의하는 메소드는 정해져 있다.

protect Control createContents(Composite parent){

Text helloText = new Text(parent, SWT.CENTER);

parent.pack();

return parent;

}

 

위와같이 상속받은 ApplicationWindow Class의 createContents 메소드를 재정의(overriding)하면 된다.

이 메소드는 parent 란 이름을 가진 Composite 를 만든 뒤 반환(return)한다. 그럼 ApplicationWindow 객체는 이를 받아 Shell에 보여주게 된다.

이 작업은 어디서 하냐구? 이거까지 알려면 ApplicationWindow Class 를 봐야 하는데 ... 너무 깊이 들어가진 말자. ㅋㅋㅋ

 

그럼 이제 main 메소드를 짜야지?

public static void main(String[] args){

helloWorld hw = new helloWorld();

hw.setBlockOnOpen(true);

hw.open();

Display.getCurrent().dispose();

}

 

JFace가 SWT와 다른 점은 while문을 이용해서 생성한 Shell 객체가 죽었나 살았나 보고, 살아있는 동안 Display 객체보고 일안하면 쉬어라 라고 명령 내리는 부분이 결국 모든 SWT 프로그램에서 반복적으로, 그리고 필수적으로 들어가는 거니깐 하나의 메소드로 만들어놓고 그 메소드만 실행시키자는 것이다.

그 메소드가 바로 setBlockOnOpen(true) 다.

여기서 parameter 를 true로 줬는데 이건 "윈도우가 닫힐 때까진 계속 대기하고 있어라."이고,

만일 false로 준다면 "일 끝내고 바로 객체 자원을 다 돌려줘라."라는 것으로 결국 윈도우가 닫히게 된다.

근데 이렇게 짜질 않자나?

그냥 default를 true로 두지. 흠. 머 SDK 짜는 사람 맘이니깐 머. 이런 경우가 있나 보지 머.

마지막으로 Display 객체에 현재 열려있는 스레드, 즉 shell 객체들을 모두 dispose 하면 된다.

 

위에꺼 모두 이제 붙여보면 완전한 코드가 완성된다.

package com.swtjface.unit2;

 

import org.eclipse.jface.window.*;

import org.eclipse.swt.*;

import org.eclipse.swt.widgets.*;

 

public class helloWorld extends ApplicationWindow{

public helloWorld(){

super(null);

}

 

protected Control createContents(Composite parent){

Text helloText = new Text(parent, SWT.CENTER);

parent.pack();

return parent;

}

 

public static void main(String[] args){

helloWorld hw = new helloWorld();

hw.setBlockOnOpen(true);

hw.open();

Display.getCurrent().dispose();

}

}

 

26줄이 20줄로 줄었다. 그러니까 코딩줄수로 보면 23% 줄었다.

흠. 약 1/4이 줄었으니 꽤 줄은거 같다. ㅎㅎ

근데 JFace가 model 기반이라고 했는데 그 7가지 중 하나도 안쓴거 같은데?

근데 머 꼴랑 text 한줄꺼리도 안되는거 가지고 거창하게 model을 쓰네 마네 할 필요는 없을 거 같아서 너그러운 맘으로 넘어가준다.


 

 

이 글은 스프링노트에서 작성되었습니다.

'SWT/JFace' 카테고리의 다른 글

SWT/JFace 초짜 도전기 - (1) 들어가기 전에  (2) 2008.10.22
Posted by gildong0