본문으로 바로가기

Day-15 Win32 API 이야기와 실습2

category Programming/TIPS 17기 2017. 8. 17. 15:23

 

 

 

GDI(Graphics Device Interface)

 

Windows 운영체제가 그래픽 장치에 대해 프로그램 소스 코드가 독립성을 유지할 수 있도록 그래픽 장치를 하나의 모델로 추상화 했다.

그리고 이 장치를 사용해서 그림을 그리거나 여러가지 속성을 표현하는 작업에 대해 다양한 API 함수를 제공해서 프로그래머가 윈도우에 쉽게 그림을 그릴 수 있도록 했다. 따라서 Windows 운영체제가 그래픽 장치에 대해 프로그램이 독립성을 유지할 수 있도록 만든 기술이다.

 

GDI Object

 

Windows 운영체제는 그래픽 장치를 추상화 시키기 위해서 그리기에 필요한 요소들을 여러 개의 객체로 구성하고 장치에 종속적인 내용(장치에 따라 수정되어야 하는 내용)들을 해당 객체에 숨겼는데 그 객체를 GDI Object라고 한다.

 

Bitmap

 

'비트 패턴'을 추상화한다.

 

Pen

 

선 그리기에 사용되는 속성이다.

 

Brush

 

도형의 내부 영역을 채우기 위해 사용되는 속성이다.

 

그리기를 GDI를 사용하지 않고 그릴 수 있다. 하지만 소스코드가 엄청 길어지고 굉장히 힘들어진다.

 

프로그래머가 그림을 그릴 때 하드웨어에 따라 표현하는 것이 어렵다. 따라서 GDI를 사용해 그래픽 장치에 종속적이지 않게 쉽게 프로그래밍 할 수 있다.

 

프로그램에서 GDI를 사용하기 위해서 기본적인 정보가 필요하다. 이러한 정보들을 GDI가 관리하면 병목이 많아지기 때문에 이것을 APP에서 관리하고 이것을 DC라고 부른다. 즉, APP이 Graphics Device를 사용하기 위해 가지는 값이다.

 

DC(Device Context)

 

GDI 기술이 윈도우에 그림을 그릴 때 그래픽 장치에 종속적인 내용을 GDI Object에 숨겼다. 따라서 그림을 그리는데 사용 중인 GDI Object를 저장(관리)하는 객체가 필요한데 이 객체를 DC라고 부른다. 그림을 그리기위한 정보를 다 DC가 가지고 있다.

 

DC

 

PEN                        // 선색

BRUSH                   // 채우는 색

FONT                      // 글꼴

BITMAP                   // 그림을 어디에 저장할 것인지

 

윈도우는 어떤 APP이 그림을 그릴지 모르고 이것을 다 확인하려면 시간이 많이 걸린다. 따라서 DC를 사용하겠다고 하는 APP만 윈도우가 감시를 한다.

GetDC 함수를 이용해 윈도우로부터 그림을 그리겠다고 윈도우에 정보를 말해주고 윈도우는 이 APP을 감시한다.

 

APP(그림) -> GDI -> 그래픽 장치(Graphics Device)

 

그래픽 장치와 APP을 연결해주는 작업을 GDI가 기능을 한다.

 

단점

 

그래픽 카드가 비약적으로 좋아질 때에 반해서 GDI가 발전하지 않았다. GDI는 그래픽 카드와 독립적이기 때문에 그래픽 카드의 성능을 GDI가 반영 할 수 없다. 따라서 최근 GDI를 사용하지 않고 GDI +를 사용한다. GDI +는 하드웨어의 특성을 반영할 수 있다. 이후에 DIRECT 2D를 사용한다. GDI는 1990년 후반부터 2000년 초반까지 유행했다. 2000년 초반부터 2010년까지 GDI+를 사용하고 2010년부터는 DIRECT 2D를 주로 사용한다.

 

Day-14에 이이서 실습을 계속 해보자. 사각형을 그리는 소스코드를 작성해보자.

 

왼쪽 마우스를 클릭할 때 (10, 10), (100, 100)을 연결하는 직사각형을 그리는 프로그램이다.

 

 

이렇게 소스를 작성하고 디버깅 하면 아래의 윈도우 창이 실행되고 마우스 왼쪽을 클릭하면 (10, 10), (100, 100)을 연결하는 직사각형이 그려진다.

 

 

 

 

이번에는 지정된 곳에 사각형을 그리지 말고 마우스 왼쪽을 클릭한 곳에 사각형을 그리는 소스코드를 작성해보자.

(x-15, y-15)와 (x+15, y+15)를 연결하는 직사각형을 그린다.

 

 

이렇게 소스를 작성하고 디버깅 하면 아래의 윈도우 창이 실행되고 마우스 왼쪽을 클릭할 때 사각형이 그려진다.

 

 

 

이번에는 마우스 왼쪽을 클릭했을때는 사각형을 그리고 Ctrl을 누르고 마우스 왼쪽을 클릭했을때 원을 그리는 소스코드를 작성해보자.

 

마우스가 클릭되었을때 좌표를 얻오는 또 다른 방법으로 사용했다. 지금 권장하는 것은 GET_X_LPARAM, GET_Y_LPARAM 함수이다. Windows.h 헤더파일을 선언해야 사용할 수 있다. 운영체제는 윈도우가 마우스를 클릭했을때 프로그램에서 WM_DOWN 메세지가 발생하면 자동으로 WPARAM(어떤 키가 눌렸는지), LPARAM(X, Y)에 구체적으로 명시되서 나온다. 운영체제가 얻는 정보는 3가지(조합키, X좌표, Y좌표)이다. '3가지 정보를 2가지 변수에 넣을까?'라는 고민에서 LPARAM의 상위 2바이트 하위 2바이트를 나누어서 사용하기로 정했다. 16비트는 폭이 6만이라서 아직까지 충분히 커버가 가능하다고 생각해서 32비트로 합쳐서 사용한다.

 

 

이렇게 소스를 작성하고 디버깅 하면 아래의 윈도우 창이 실행되고 마우스 왼쪽을 클릭할 때 사각형이 그려지고 Ctrl + 마우스 왼쪽을 누르면 원이 그려진다.

 

 

 

 

이번에는 원과 사각형의 배경색을 빨간색으로 채워 넣어 빨간색 원, 빨간색 사각형이 나오도록 소스 코드를 작성하자.

 

DC의 default를 알아보자. pen은 검은색이고, brush는 흰색으로 설정되어 있다. 핸들과 같이 윈도우 권한을 지키기 위해서 pen과 brush를 가리키는 메모리가 따로 있다. 각각 *pen에 대한 pen이 있고 *brush에 대한 brush가 있다. 다시 보면 DC를 *(포인터) 테이블로 볼 수 있다. 색을 바꾸고 싶을 때 기존의 brush가 아닌 새로운 brush를 정의하여 사용해야 한다. 하지만 이렇게 간단히 사용하면 기존의 brush는 고아가 된다. DC는 계속 쓰이는 정보이고 지역 변수로 brush를 만든다. release를 하면 brush가 사라져  *brush는 사라진 brush를 가리킨다. 즉, 여기서도 문제가 발생한다. 따라서 새로운 brush를 만들어 기존의 brush를 백업하고 나중에 다시 복구시키는 과정을 거쳐야 한다.

 

 

이렇게 소스를 작성하고 디버깅 하면 아래의 윈도우 창이 실행되고 마우스 왼쪽을 클릭할 때 빨간 사각형이 그려지고 Ctrl + 마우스 왼쪽을 누르면 빨간 원이 그려진다.

 

 

 

 

하지만 이렇게 소스를 작성하면  완벽한것 같지만 WM_PAINT 메세지를 처리하지 못해서 윈도우 밖으로 나가면 도형이 지워진다. 아래와 같은 상황이 발생한다.

 

 

 

 

WM_PAINT를 처리하는 소스코드를 작성해서 윈도우 창 밖으로 빠져나가도 도형이 지워지지 않는 소스코드를 작성해보자. 아래와 같이 소스코드를 작성하면 WM_PAINT를 처리하지만 색깔의 복구는 하지 못한다.

 

 

하지만 이렇게 소스를 작성하면  완벽한것 같지만 WM_PAINT 메세지를 처리하더라도 색의 복구는 할 수 없다.

 

 

 

 

위 소스코드는 C언어 코드 기반의 API로 구축 했다. 이번엔 이 코드를 C++기반의 MFC로 변환해서 구축해보자.

위 소스코드 중 바뀌지 않을 것은 class로 만든다. 그 후에 상속을 받아 사용하면 된다.

자세히 보면 winmain은 3개로 나눌 수 있다.

winclass --- window class 등록, application을 등록한다.

windows창 --- 창을 보여주는 작업이다. 실체화(구체화) 되는 것을 Instance라고 한다.

message --- 메세지를 처리하는 것, 프로그램이 진행된다. 

 

 

이렇게 소스 코드를 구성하면 비록 소스 코드가 길어지지만 변화에 대한 유지 보수가 쉽다.

 

 

 

 

 

 

 

 

 

'Programming > TIPS 17기' 카테고리의 다른 글

Day-17 MFC 이야기와 실습2  (0) 2017.08.29
Day-16 MFC이야기와 실습1  (0) 2017.08.20
Day-14 Win32 API 이야가와 실습1  (0) 2017.08.15
Day-13 C++ 이야기3  (0) 2017.08.14
Day-12 C++ 이야기2  (0) 2017.08.11