From YYpBD's MediaWiki
제 목:[강좌] 트윕(Twip)을 아십니까..?? 관련자료:없음 [1048]
보낸이:민성기 (minske ) 1998-08-27 06:43 조회:1477 추천:0
트윕(Twip)을 아십니까…?
(파워러브 델파이 98년 9월호)
해상도나 화면 글꼴 크기에 따라 중구난방 변하는 어플리케이션의 변덕은 언제나
고민거리다. 아마도 많은 사람들이 이 문제에 지치고 단련되어 이제는 나름대로 모
종의 해결책을 가지고 있지 않을까 생각된다. 필자또한 이 현상과 때론 싸우고 때론
타협하며 머리숱이 많이 엷어져 온 사람들 중 하나이다.
변덕스런 해상도에 대해서는 이미 97년 10월호 "해상도 문제 해결하기"라는 기사
에서 잠깐 다룬적이 있지만, 이번엔 아예 이런 원인이 무엇이고 해결책은 무엇인지
뿌리를 뽑아 다시는 필자처럼 머리카락들과 아픈 이별을 하는 사람들이 없도록 해
보자.
♣ XXX 널뛰듯한 어플리케이션의 변덕.
점잖은 기술잡지에서 왠 망언이냐고 혹 꾸짖는 독자가 있더라도, 필자의 아까운
머리카락들을 생각하면 이 표현은 정말 얌전한 것이다. T_T;
먼저 이 널뛰는 현상을 함께 감상하자. 새 프로젝트를 시작하고 버튼 세개, 에디
트 세개, 라벨 하나를 폼 위에 적당히 올린다. 폼의 BorderStyle 프로퍼티는 bsDial
og 로, OnCreate이벤트에는 다음 리스트1을 코딩하자.
리스트1. 테스트용 어플리케이션
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := Format('Pixels / Inch : %d', [Screen.PixelsPerInch]);
Label1.Caption :=
Format('폼 : Left %d, Top %d, Width %d, Height %d',
[Left, top, Width, Height])+#13+#13+
Format('버튼1 : Left %d, Top %d, Width %d, Height %d',
[Button1.Left, Button1.top, Button1.Width, Button1.Height])+#13+#13+
Format('버튼2 : Left %d, Top %d, Width %d, Height %d',
[Button2.Left, Button2.top, Button2.Width, Button2.Height])+#13+#13+
Format('버튼3 : Left %d, Top %d, Width %d, Height %d',
[Button3.Left, Button3.top, Button3.Width, Button3.Height])+#13+#13+
Format('에딧1 : Left %d, Top %d, Width %d, Height %d',
[Edit1.Left, Edit1.top, Edit1.Width, Edit1.Height])+#13+#13+
Format('에딧2 : Left %d, Top %d, Width %d, Height %d',
[Edit2.Left, Edit2.top, Edit2.Width, Edit2.Height])+#13+#13+
Format('에딧3 : Left %d, Top %d, Width %d, Height %d',
[Edit3.Left, Edit3.top, Edit3.Width, Edit3.Height]);
end;
<위의 어플을 실행시킨 그림이 있습니당..>
그림1. 작은 글꼴 (96dpi)에서 실행시킨 경우.
<위의 어플을 실행시킨 그림이 있습니당..>
그림2. 큰 글꼴 (120dpi)에서 실행시킨 경우.
그림1과 그림2는 위의 어플리케이션을 각각 윈도우의 작은 글꼴(96dpi)과 큰 글꼴
(120dpi)에서 실행시킨 모습이다. 폼의 위치를 제외한 모든 값들이 다른 것을 볼 수
있다. 이 문제는 생각보다 심각한데, 하드 코딩으로 컨트롤의 위치를 코드 내에서
조절하는 경우, 이것들이 제 위치에 나타난다는 것을 아무도 보장할 수 없다는 얘기
가 된다.
지금까지 이와 같은 문제를 해결하기 위해 여러 사람들이 사용해온 일반적인 해결
방법들을 종합하면 벢遮育? 좌표뵸遮? 말로 압축할 수 있다. 컨트롤의 좌표를 직접
지정하지 말고 가능하면 윈도우가 재배치한 다른 컨트롤의 위치와 크기를 참조하는
것이다. 또 다른 방법으로는 어플리케이션의 실행 조건에 벪? 어플리케이션은 작은
글꼴에서만 (또는 큰 글꼴에서만...) 돌아갑니다!!!? 라고 명시하는 것도 있을 수
있겠지만, 여기서 잠깐 임인건님의 프로그래머의 십계명중 한 구절을 음미해 볼 필
요가 있겠다.
9. 사용자가 알아서 잘 써 주리라고 희망하지 말지어다. 너의 프로그램은 항상 바
보와 미친놈만이 쓰느니라. 사용 설명서를 쓸 때에는 결코 빠뜨리지 말아라.
빠뜨린 만큼 사용자는 너를 괴롭힐 것이니라.
자 위의 계명을 맘에 새기면서, 왜 이런 현상이 일어나는지 함께 생각해 보자.
♣ 윈도우의 좌표단위 트윕!!
결론부터 말해 윈도우는 트윕(Twip)이란 단위를 화면 해상도(dpi)에 따라 재 매핑
하여 사용한다. 우리가 별 생각없이 사용하던 좌표값은 절대적인 값이 아니었던 것
이다. 일반적으로 가장 눈에 익은 윈도우의 화면 해상도는 96dpi이다. 만약 윈도우
가 이 해상도만을 지원했다면 많은 사람들이 행복했을 것이다. 그러나 이 값은 윈도
우를 사용하는 사람 마음대로 얼마든지 변형시킬 수 있기 때문에 경우에 따라 우리
가 지정한 좌표값은 엉뚱한 위치를 가리키게 된다.
트윕은 1440/1 Inch를 나타낸다. 따라서 96dpi에서의 한 픽셀당 트윕은 1440/96
인 15가 된다. 여기서 현재 화면의 해상도는 GetDeviceCaps() API 함수를 사용하여
구할 수 있고 이 함수의 원형은 다음과 같다.
function GetDeviceCaps(
hdc: HDC; // device-context handle
nIndex : integer // index of capability to query
) : Integer;
nIndex에 LOGPIXELSX와 LOGPIXELSY를 사용하여 각각 X 및 Y방향의 물리적인 인치
당 도트수를 구할 수 있다. 현재 윈도우의 모든 DC는 같은 인치당 도트수를 가지므
로 hdc에는 아무 DC값이나 넣어줄 수 있다. 아마도 더욱 변태같은 사람은 X방향과 Y
방향의 해상도 마저도 다르게 사용하는 모양인데, 이 두 값이 다르게 나오도록 윈도
우를 설정하는 방법은 필자도 모르겠고 이렇게 쓰는 사람 또한 한번도 만나지 못했
다. 때문에 물리적인 화면 해상도를 구하는 경우 복잡하게 화면 DC를 얻을 필요 없
이 단순히 Screen객체의 PixelsPerInch값을 사용해도 무방할 듯 싶다. (프로그래머
의 계명이 맘에 걸리기는 하지만...^^;)
리스트2는 현재 해상도에서 X 및 Y방향의 한 픽셀당 트윕을 구하는 함수이고, 리
스트3은 좀 더 간단하게 픽셀당 트윕의 개수를 구하는 함수이다.
리스트2. TwipsPerPixel
function TwipsPerPixelX : Real;
var
DC : HDC;
nPixelsX : integer;
begin
DC := GetDc(0);
try
nPixelsX := GetDeviceCaps(DC,LOGPIXELSX);
Result := 1440/nPixelsX;
finally
ReleaseDC(0, DC);
end;
end;
function TwipsPerPixelY : Real;
var
DC : HDC;
nPixelsY : integer;
begin
DC := GetDc(0);
try
nPixelsY := GetDeviceCaps(DC,LOGPIXELSY);
Result := 1440/nPixelsY;
finally
ReleaseDC(0, DC);
end;
end;
리스트3. 간단한 TwipsPerPixels
function TwipsPerPixel : Real;
begin
Result := 1440/Screen.PixelsPerInch;
end;
이제 앞에서 살펴본 어플리케이션의 컨트롤들이 해상도 마다 널을 뛰는 이유를 살
펴보자. 그림1에서 보이듯이 96dpi에서 Edit3의 Left프로퍼티는 241point 이다. 이
를 트윕으로 환산하면 15 X 241 = 3615twip이 되고, 이것을 120dpi의 화면에 뿌리기
위한 포인트값은 3615 ÷ 12 = 301.25point가 된다. 화면 좌표에는 소수값이 없으
므로 그림2에 보이는 값과 같다고 할 수 있다. 다른 값들도 유사한 결과를 보인다.
그러나 특정 해상도에서 구한 트윕값은 참고용일 뿐이지 정확한 값은 아니다. 위의
경우 보다 정확한 트윕값은 96dpi에서의 값 3615와 120dpi에서의 값 3612의 평균인
3613.5가 될 것이다. 이 값이 화면 해상도에 따라 재 매핑 되면서 96dpi에서는 241p
oint로, 120dpi에서는 301point로 반올림된 것이라고 생각하자.
♣ 맺으며...
오랫동안 필자의 머리털을 괴롭혔던 트윕에 대해 알아보았다. 컨트롤의 크기나 위
치속성을 트윕의 단위로 통일해 사용한다면 위치등의 계산에 혼동이 없을 것이다.
덧붙이자면 이 단위는 벡터 이미지인 메타파일의 좌표계에서도 사용된다.
혹 코드 내에서 컨트롤의 크기를 바꾸고 싶은 독자가 있다면 이 트윕을 머리속에
새겨두도록 하자. 머리털을 지켜주며 속이 비쳐보이는 현상을 방지하는 탁월한 효능
이 있음을 필자가 보장한다...^^;