64bit 버전으로 설치하고, 현 시점에 최신 버전은 3.10이지만, 인공지능을 위한 tensorflow가 지원하는 최신 버전인 3.9.13버전이고 Spinnaker라는 Camera 소프트웨어는 3.8.xx버전을 지원한다.
### pip(Python Install Package) 설치
설치하고 가장 먼저해야할 작은 pip(Python Install Package)를 업그레이드 하는 것이다.
PS D:\python -m pip install --upgrade pip
그럼 tensorflow를 설치할 수 있는 환경이 조성되었다.
### tensorflow 와 tensorflow-cpu 설치
PS D:\python -m pip install tensorflow
설치된 tensorflow를 확인해보자.
PS D:\> python
Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
2022-07-27 11:53:34.911913: W tensorflow/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'cudart64_110.dll'; dlerror: cudart64_110.dll not found
2022-07-27 11:53:34.912570: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
>>> quit()
CUDA 런타임 라이브러리가 없다고 에러를 발생시킨다. 그래서 cpu전용 구동할 수 있는 tensorflow-cpu를 추가 설치한다.
PS D:\> python -m pip install tensorflow-cpu
다시, 설치된 tensorflow의 버전을 확인해 보자.
PS D:\> python
Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> tf.__version__
'2.9.1'
>>> quit()
### PySide6 설치
PS D:\> python -m pip install PySide6
설치된 버전 확인한다.
PS D:\> python
Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import PySide6
>>> PySide6.__version__
'6.3.1'
>>> quit()
### OpenCV 설치
PS D:\> python -m pip install opencv-python
설치된 버전 확인한다.
PS D:\> python
Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> cv2.__version__
'4.6.0'
>>> quit()
## Visual Studio Code 설치
아래의 사이트를 방문해서 해당 시스템에 알맞은 설치파일을 다운로드 받는다.
https://code.visualstudio.com/download
설치 후 PySide6 예제를 코딩하고 실행해 본다.
## FLIR 카메라를 위한 환경 설정
과거의 Point Gray사의 카메라를 사용하기 위해서 현재는 FLIR로 합병된 Spinnaker SDK를 설치해야한다.
SpinnakerSDK_FULL_2.7.0.128.x64.exe 파일을 다운로드하고 설치한다.
그리고, Python 에서 카메라를 운용하기 위해서 spinnaker_python-2.7.0.128-cp38-cp38-win_amd64.zip 파일도 다운로드하고, 다음의 명령어로 설치한다.
GTK에서 어떻게 화면을 그리는 것을 이해하기 위해서,
여러분들은 GTK가 어떻게 widget 들을 그리는지에대한 것을 먼저 이해 해야만 한다.
그 이유는 GTK가 widget을 그리는 방식은 여러분의 그림을 출력하는 응용 프로그램을 어떻게 디자인해야하는데 중요한 역할을 가지고 있기 때문이다.
GTK가 widget들을 어떻게 그리는지를 이해하는 것은 여러분들이 자신만의 자체 widget들을 만들 계획이 있다면 또한 필요하다.
윈도우와 윈도우 갱신
대부분의 윈도우 시스템들은 응용 프로그램의 외형 표현이 윈도우라고 불리우는 화면의 네모난 영역내에 구현되는 개념으로 디자인 되어 있다. Gnome, KDE 혹은 Explorer 같은 윈도우 시스템은 응용 프로그램의 윈도우의 보여지는 내용을 자동적으로 저장하지 않는다. 그 대신 시스템은 필요할때 응용 프로그램 자신에게 자신의 윈도우를 다시 그려야 한다고 요청한다. 예를 들면, 다른 윈도우들 밑에 깔려 있는 어떤 윈도우가 가장 위에 놓이게 된다면, 해당 프로그램은 이전에 가려진 영역을 다시 그려야한다. 윈도우 시스템은 윈도우의 가려진 부분을 다시 그리도록 해당 프로그램에게 요청할때, 그 윈도우를 포함하는 프로그램에게 exposure 라는 이벤트를 보낸다. exposure 이벤트는 자체적으로 다시 그려져야 한다는 것을 알리기 위해 윈도우 시스템이 Widget에게 보내지는 단순한 이벤트이다.
이 단락에서는 윈도우는 자동적인 갱신이 가능한 내모난 영역을 의미하고 고차원의 응용 프로그램을 의미하는 것은 아니다. 화면 갱신은 다시 그려질 필요가 없거나 다른 방식으로 보여져야하는 윈도우의 어떤 부분을 제거하는 작업이다. 이것은 어떤 것들이 다시 그려져야하는 윈도우의 영역인지 판단하는 것이다. 그림 1에서 윈도우 A는 윈도우 C 밑에 있는 윈도우 B 밑에 있다. 사용자가 윈도우 A를 화면의 앞으로 가져오는 작업을 한다면, 다시 그려져야만하는 윈도우 A의 영역은 그림에서 그림자로 되어 있는 A ∩ (B ∪ C)안에 있는 윈도우 A의 부분이다.
대부분의 윈도우 시스템들은 자식 윈도우라고 불리우는 중첩된 윈도우를 지원한다. 고차원의 윈도우는 차례로(?) 자식 윈도우를 포함할지도 모르는 많은 자식윈도우들을 포함할 지도 모른다. 예를 들면, 고차원의 윈도우는 일반적으로 메뉴 바를 위한 윈도우와 문서 영역을 위한 윈도우, 각 스크롤바를 위한 윈도우, 그리고 상태바를 위한 윈도우를 포함할 것이다. 게다가, 클릭이 가능한 버튼 (일반적으로 자체 하위 윈도우를 같는) 같은 사용자 입력을 받는 컨트롤도 포함한다. GTK+는 중첩된 윈도우들에 대한 인지 없이 윈도우 시스템에서 실행되는 것을 가능하다. 이러한 방식은 GDK가 해당 시스템하에서 존재하는 그림 그리기 기능을 제공하기 때문에 문제가 되지 않는다. 그러므로, GTK+에서 중첩된 윈도우는 항상 가능하다.
화면 갱신 반복 작업
일반적으로 화면 갱신 반복 작업은 GTK+가 하부에서 작동하는 윈도우 시스템으로 부터 exposure 이벤트를 받을때 시작된다. 예를 들면 사용자가 윈도우를 다른 윈도우 위로 드레그하게 되었을때가 대표적이다. 이러한 경우 윈도우 시스템은 자체적으로 다시 그릴 필요가 있는 아래에 있는 윈도우에게 알려 주게 될 것이다. 또한, 이러한 화면 갱신 반복 작업은 윈도우 내의 Widget 자체가 다시 그려져야할 필요성이 있을때 시작되어 질 수도 있다. 예를 들면, 사용자가 GtkEntry Widget에 글자를 적어 넣을 때, GtkEntry Widget은 GTK+에게 자신을 다시 그려야 한다는 요구을 접수해 줄 것을 요청한다. 다른 말로, Widget은 윈도우 시스템 자체가 자신을 다시 그리는 event를 보내도록 요청하는 기능을 호출 할 수 있다. 이것은 여러분이 바로 볼 수 있을 만큼 프로그램을 단순화 시킨다.
GdkWindow는 GTK+가 실행되는 상황에서 맨 밑에서 있는 윈도우 시스템의 윈도우를 대표한다. X11 에서 이것은 (X) Window에 해당하고 Win32의 경우 HANDLE에 해당한다. 이것은 이러한 윈도우들을 위한 event를 생성하는 윈도우 시스템이다. 이러한 event 들은 GDK 인터페이스로 전달된다. 이는 이러한 원래의 event들을 GdkEvent 의 형태로 변환하고, GTK 층으로 전달한다. 그리고 그 다음으로 GTK widget 층은 특정 GdkWindow에 해당하는 widget을 검색하고, 그 widget에 연계되는 event 시그널들을 발생한다.
GdkWindow에 있거나 없는 Widget들
모든 단일 widget은 그 자신의 GdkWindow을 가졌다면, 화면 갱신 작업은 당연히 이루어 질 것이다; 밑에서 동작하는 윈도우 시스템은 다시 그려질 필요가 있는 윈도우에 해당하는 GDK에게 통지한다. 그리고 GDK는 특정 GdkWindow를 위한 exposure event를 GTK 층에 전달하고 GTK 층은 그 widget을 위한 exposure event 시그널을 발생 시키게 될 것이다. 그러면 widget의 exposure event 핸들러는 widget을 다시 그리게 될 것이다. 그 밖의 다른 것은 할 것이 없다; 윈도우 시스템은 필요로 하는 각각의 윈도우를 위한 exposure event를 발생하고, 그에 해당하는 각 widget은 자신을 다시 그리게 될 것이다.
그러나, 실제적으로 widget들이 자신의 GdkWindow를 갖지 못하도록 하는 것이 더 효과적이고 편리하기 때문이다. 그러나 대신 상위 widget으로 부터 하나를 공유 한다. 모든 widget은 widget이 자신의 윈도우를 갖는지 않 갖는지를 알리는 GTK_NO_WINDOW를 갖는다. widget이 윈도우를 갖지 않는다면 반드시 생성될때 이 플레그(GTK_NO_WINDOW)를 true로 설정하여 GTK에게 갖고 잊지 않다는 것을 알려야 한다. (GTK+ 2.18 혹은 그 이후의 버전에서 widget은 gtk_widget_set_has_window()의 두 번째 매개변수를 false로 설정하여 호출한다.) 이것은 프로그래머로써 해야하는 것은 아니다. 이것은 widget의 생성시에 이루어져야 하는 widget의 구현자가 해야하는 작업이다. 프로그래머로써 여러분들은 특정 widget이 GdkWindow를 가지고 있는지 아닌지를 GTK_NO_WINDOW의 값을 검사하거나 GTK+-2.18 이후의 버전에서는 gtk_widget_get_has_window() 함수를 호출하여 알아 볼 수 있다. GdkWindow를 갖지 않는 widget들은 no-window widget 혹은 GTK_NO_WINDOW widget으로 불린다.
왜 여러분은 윈도우가 없는 widget을 필요로 하게 될까요? 두 가지 큰 이유가 있다.
어떤 widget들은 부분적으로 그려져야할 지라도 상위 widget의 배경이 보여지기를 원할지도 모른다. 예를 들면 다음과 같은 경우이다. label이 themed texture를 가지고 있는 button위에 위치하고 있을때, 각각의 widget이 윈도우를 가지고 있고 배경을 가지고 있다면, 그들을 둘러싸는 것을 고려하여 보여지는 것이 멈추게 될지 모르기 때문에 label은 나쁘게 보여질 것이다.
GDK 윈도우들의 총 개수를 줄이는 것은 GDK와 GTK 사이의 데이터 교류의 양을 줄인다. 그래서 윈도우가 없는 widget을 구현할 수 있다면 성능은 한층 더 좋아 진다.
계층적인 그리기
이와 같은 사항을 이해 한다면, 우리는 우리의 관심을 GTK가 exposure event를 받을 때 발생하는 일련의 과정을 이해하는 것으로 돌려 보자. 가장 맨 처음 과정은 GTK가 event를 받은 윈도우에 해당하는 Widget을 찾는 것이다. 이 Widget은 no-window widget일 수 없다. (만약 그렇다면 event를 받을 만한 자신의 윈도우를 아예 갖을 수 없기 때문에 처리할 event라는 것은 존재 하지 않는다.) 이와 같은 Widget들은 배경을 그리는 것을 시작한다. 그런 다음 해당 Widget이 container widget이라면, 윈도우를 갖지 않는 자식 Widget들 각각에게 자신들을 다시 그리도록 이야기 해준다. 이러한 과정은 원래의 Widget의 윈도우가 없는 모든 상속자들에게 반복적으로 적용된다.
이러한 과정은 (GTK_NO_WINDOW가 true로 설정된 Widget들인) 자신의 윈도우들을 갖는 Widget에게 전달되어 지지는 않는다. 이것은 이러한 어떤 Widget들이 다시 그려져야한다면, 윈도우 시스템은 그들에 해당하는 GDK 윈도우에 exposure events를 보내게 될 것이기 때문이다. 이와같이, GTK+의 관점에서 이들에게 exposure를 전달할 필요는 없다.
최외각의 두꺼운 네모는 상위 레벨의 GtkWindow이다. 이것은 GTK_NO_WINDOW인 Widget은 아니다. 그러므로, exposure event를 반드시 받게된다. 왜냐하면, GDK로부터 생성되었기 때문이다. 먼저 GtkWindow는 그 자신의 배경을 그리게 될 것이다. 그런다음, 자식 윈도우에게 자신을 다시 그릴 것을 요청한다. 여기서는 2번으로 표시된 점선으로된 네모가 이에 해당한다.
점선으로된 네모는 GtkVBox이다. 이것은 GtkWindow의 단독 자식을 형성한다. GtkVBox류는 윈도우를 갖지 못하는 Widget이다. 그들 자체로는 아무것도 그릴 것이 없는 그져 Layout Container이다. 그레서 GtkVBox는 그릴 것이 아무것도 없다. 그러나, 대신 그릴 것을 가지고 있는 자식들에게는 요청을 한다. 그 자식들은 3번과 6번에 해당한다.
얇은 네모는 GtkFrame이다. 물론 윈도우를 가지고 있지 않고 두 개의 자식들을 가지고 있다; 4번으로 표시된 프레임을 위한 Label과 5번으로 표시된 또 다른 내부의 Label이다. 먼저, 프레임은 그 자신의 중간이 짤린 박스를 그리게 되고, 프레임의 Label과 그 안의 자식들에게 그들 자신을 다시 그리도록 요청한다.
프레임의 Label은 자식을 갖지 않는다. 그레서 그져 문자만 그린다. "Frame Label"
내부의 Label은 자식을 갖지 않는다. 그레서 그져 문자만 그린다. "This is some text inside the frame!"
점선으로 된 네모는 GtkHBox를 의미한다. 다시 말해서, 이것은 스스로 아무것도 그릴 것이 없지만, 그릴 것을 가지고 있는 그의 자식들에게는 요청을 한다. 그 자식들은 7번과 9번에 해당한다.
얇은 네모는 8번으로 표신된 자식을 하나만 가지고 있는 GtkButton이다. 먼저, 버튼은 그 자신의 박스를 그리고, 자식들에게 자신을 그릴 것을 요청하게 된다.
이것은 자식을 가지지 못하는 text label이다. 그레서 그져 문자만 그리면 된다.: "Cancel".
7번과 유사하게 이것은 10번으로 표시된 자식 하나만 가지고 있는 GtkButton이다. 먼저, 버튼은 박스를 그리고 그려야 할 것을 가지고 있는 자식들에게 요청을 하게된다.
8번과 유사하게 이것은 자식을 갖지 않는 GtkLabel이다. 그레서 자신의 문자만 그리면 된다: "OK".
위의 과정은 어떻게 Widget이 다시 그려지는지 보여준다. 이러한 그리기작업은 모두 화면에 직접적으로 위치해야 한다면, 다양한 부분들이 다시 그려짐에 따라 깜박거림이 발생하게 될 것이다. 이것은 부분적으로 배경과 장식용 요소같은 많은 영역들이 반복적으로 다시 그려지게 되기 때문이다.
그러므로, GTK는 GDK레벨에서 double buffering이라는 개념을 구현하게된다.
Double Buffering
double buffering에서 두개의 캔퍼스들이 존재한다: 화면에 안보이는 캔퍼스와 화면에 보이는 캔퍼스. 그리는 작업은 안보이는 캔퍼스위에서 발생하고 그러고 나서 화면에 그려지게 된다. 그리고 화면에 있었던 캔퍼스는 다음의 그리기 작업을 위해서 화면에 안보이는 캔퍼스가 된다. GTK에서 이런 double buffering은 Widget들에게 보이지 않는 부분이다; 그들은 일반적으로 그들이 화면에 안보이는 버퍼에 그려지고 있는 알지 못한다. 그들은 그져 그들의 일반적인 그리기 명령을 이슈화 할 뿐이다. 그리고 버퍼는 모든 그리기 작업이 완료되었을때 윈도우 시스템에게 돌려주게 된다.
GDK에서 두 개의 기본적인 함수들이 double-buffering의 작동원리의 핵심을 형성한다.
gdk_window_begin_paint_region()
gdk_window_end_paint()
첫째 함수는 GdkWindow에세 그리기 작업을 위해서 화면에 보이지 않는 버퍼를 생성할 것을 요청한다. 이러한 시스템에 가해지는 모든 차후의 그리기 과정들은 자동적으로 이 버퍼로 재 지정되게 된다. 두 번째 함수는 보이는 화면에 버퍼를 실질적으로 그리게 되고 버퍼를 해제하고 되돌려 주게된다.
자동화된 double buffering
이것은 exposure 핸들러에 초반부에 gdk_window_begin_paint_region()을 호출하고 마지막 부분에서 gdk_window_end_paint()를 호출하는 모든 Widget들에게는 적용되지 않는다. 이걸 좀더 쉽게 하기 위해서, 모든 GTK+ Widget들은
* 소개
* 첫번째 프로그램
* 메뉴와 툴바
* 모양세 관리
* 이벤트
* 다이얼로그
* 위젯
* 위젯 II
* GtkTreeView 위젯
* GtkTextView 위젯
* 사용자 GTK+ 위젯
이것은 GTK+ 프로그래밍 지침서이다. GTK+ 사용 지침서는 C 프로그래밍 언어에 관한 것만 쓰여졌다. GTK+ 사용 지침서는 새내기, 혹은 중급 정도의 프로그래머에 알맞도록 작성되어 졌다. Cario graphic 사용지침서도 살펴보는 것을 꼭 잊지 말아달라.
GTK+ 소개
이 사용 지침서에 관해서
이것은 소개를 목적으로하는 GTK+ 프로그래밍 사용지침서이다. 이 사용지침서는 C 프로그래밍 언어를 대상으로 다루고 있다. 모든 내용은 리눅스 시스템 상에서 작성되고 테스트 되었다. GTK+ 프로그래밍 지침서는 초심자 및 중급 프로그래머에 적합하도록 작성되었다.
GTK+
GTK+는 그래픽 사용자 인터페이스를 작성하기 위한 라이브러리다. 이 라이브러리는 C 프로그래밍 언어에서 작성되었다. GTK+ 라이브러리는 또한 GIMP 툴킷이라고도 불린다. 원래, 이 라이브러리는 GIMP 영상 조작 프로그램을 개발할때 작성되었다. 그 이후로 GTK+는 리눅스와 BSD 유닉스에서 가장 인기있는 툴킷중 하나가 되었다. 오늘날 오픈 소스 세계의 대부분의 GUI 소프트웨어는 QT혹은 GTK+로 작성되었다. GTK+는 Object Oriented 응용 프로그램 인터페이스이다. GObject는 다양한 다른 프로그래밍 언어를 위한 language binding을 생성할 수 있게 도와 준다. language binding은 C++, Python, Perl, Java, C# 그리고 다른 많은 언어에 대해서 존재한다.
GTK+ 자체는 다음과 같은 라이브러리에 의존하고 있다.
* Glib
* Pango
* ATK
* GDK
* GdkPixbuf
* Cairo
Glib는 일반적인 사용 용도의 라이브러리이다. 이것은 데이터 타입, 문자열관련 도구, 에러 처리, 메세지 추적, 쓰레드 관련 그리고 다른 유용한 프로그래밍 특빙들을 제공한다. Pango는 국제화를 가능하게 해주는 라이브러리이다. ATK는 사용자 접근을 돕는 툴킷이다. 이 툴킷은 물리적으로 사용자가 컴퓨터를 작동할 수 있도록 돕는 도구를 제공한다. GDK는 물밑에서 작동하는 그래픽 시스템에 의해서 제공되는 저수준의 그리기와 윈도우 함수와 관련된 wrapper이다. 최근에는 대부분의 이기능은 Cairo 라이브러리로 위임되었다. GdkPixbuf 라이브러리는 영상을 읽고 pixel buffer를 조작하는 툴킷이다. Cairo는 2D 벡터 그래픽을 위한 라이브러리이다. 이것은 2.8버전 이후로 GTK+에 포함되어졌다.
Gnome과 XFce 데스크탑 환경은 GTK+ 라이브러리를 사용해서 작성되었다. SWT와 wxWidgets 또한 GTK+를 사용하는 프로그래밍 frameworks로 널리 알려져있다. GTK+를 사용하는 많은 소프트웨어 응용프로그램중에 Firefox나 Inkscape이 있다.
GTK+ 응용프로그램 컴파일하기
GTK+ 응용프로그램을 컴파일하기 위해선 pkt-config라는 유용한 도구를 사용한다. pkg-config는 설치된 라이브러리의 metadata를 되돌려준다. 간단하게 말하자면, 특정 라이브러리를 사용하고자할 때, 우리가 필요로하는 include 파일과 라이브러리파일을 알려준다. pkt-config 프로그램은 특별한 metadata 파일에서 설치된 패키지에 관한 정보를 얻어온다.
이전의 예제에서 윈도우는 x 버튼을 클릭했을 때 완벽하게 종료되지 않았다. 명령행에서 예제를 실행시켜 보면 확인해 볼 수 있을 것이다. 윈도우는 기본적으로 destroy 시그널에 반응 하지 않는다. 그래서 우리는 destroy 시그널을 gtk_main_quit()함수에 연결시켜서 응용프로그램을 분명하게 종료해주어야 한다.
응용프로그램의 아이콘
다음 예제에서 우리는 응용프로그램의 아이콘을 살펴본다. 대부분의 윈도우 관리자는 titlebar와 taskbar 의 왼쪽 구석에 아이콘을 표현한다.
increase 콜백함수 내부에서 우리는 counter의 값을 증가시키고, 숫자 값을 textual 데이터로 만들고 label을 업데이트한다.
그림 : 증가하기 - 감소하기
이 장에서 우리는 약간의 간단한 GTK+ 프로그램을 소개했다.
GTK+에서의 메뉴와 툴바
GTK+ 프로그램 지침서의 이 장에서 우리는 메뉴와 툴바를 다루어 볼것이다.
menubar는 GUI 응용프로그램의 매우 공통적인 부분 중 하나이다. 이것은 다양한 메뉴에 위치한 명령어의 모음이다. 콘솔 응용프로그램에서는 모든 이런 비밀의 명령을 기억해야하는 반면에 여기선 대부분의 명령어의 모음을 논리적인 부분으로 다룬다. 새로운 프로그램을 습득하는데 드는 시간을 많이 만축시키주는 승인된 표준이다.
간단한 메뉴 예제
우리의 첫번째 예제에서 하나의 파일 메뉴를 갖는 menubar를 만들어 볼 것이다. 이 메뉴는 하나의 메뉴 항목만 갖는다. 이 항목을 선택하면 응용프로그램은 종료된다.
다음 예제는 우리가 어떻게 툴바에서 툴바 버튼을 비활성화시키는지를 보여주고 있다. 이것은 GUI 프로그래밍에서 기본적인 동작이다. 저장 버튼을 예로 들어 보자. 문서의 모든 변화를 디스크에 저장하면, 저장 버튼을 데부분의 문서 편집기에서 비활성화 된다. 이러한 방법으로 응용프로그램은 모든 변경사항들이 이미 저장되었다는 것을 사용자에세 알려준다.
이 예제는 GTK+ stock 리소스에서 undo , redo 버튼을 생성한다. 버튼을 각각 몇 번 클릭해서 비활성화 시키면 버튼이 회색조으로 변한다.
if (count < 0) {
gtk_widget_set_sensitive(widget, FALSE);
gtk_widget_set_sensitive(item, TRUE);
}
if (count > 5) {
gtk_widget_set_sensitive(widget, FALSE);
gtk_widget_set_sensitive(item, TRUE);
}
gtk_widget_set_sensitive()함수 호출은 툴바 버튼을 활성/비활성화 하는데 사용되어진다.
그림 : undo redo
GTK+ 모양새 관리
이 장에서 우리는 윈도우와 다이얼로그에서 위젯을 어떻게 배치할 것인지를 보여준다.
우리가 응용프로그램의 GUI를 디자인할 때, 사용할 위젯이 무엇이고 응용프로그램에서 어떻게 배치시켜야 하는지 결정해야한다. 위젯을 배치시키기 위해서 layout container라고 불리는 특성화된 보이지 않는 위젯을 사용한다. 이 장에서 우리는 GtkAlignment, GtkFixed, GtkVBox와 GtkTable을 언급할 것이다.
GtkFixed
GtkFixed 컨테이너는 고정된 위치와 크기로 child widget에 위치한다. 이 컨테이너는 자동 모양새관리를 수행하지는 않는다. 대부분의 응용프로그램에는 이 GtkFixed 컨테이너를 사용하지는 않는다. 하지만 이 컨테이너를 사용하는 몇가지 특수한 영역이 있다. 예를 들면, 게임같은 경우, diagram을 가지고 작업하는 특화된 응용프로그램이나 spreadsheet 응용프로그램에 있는 chart와 같이 움직일 수 있는 크기를 변경할 수 있는 요소를 갖는 작은 교육용 예제들이다.
첫 번째 버튼은 좌표 x=150, y=50에 gtk_fixed_put()함수를 이용해서 위치시킨다.
그림: GtkFixed 컨테이너
GtkVBox
GtkVBox는 vertical box container (세로로 적재하기 위한 컨테이너). 이 것은 하나의 column(하나의 행)에 child widget을 위치시킨다. GtkHBox는 이와 유사한 컨테이너이다. 이 컨테이너는 하나의 row(하나의 열)에 child widget을 위치시킨다.
우리는 이 컨테이너에 setting 버튼을 적재한다. 첫 번째 두 매개변수는 컨테이너와 child widget이다. 그리고 다음 세 개의 매개변수는 expand, fill 그리고 padding이다. 주의 할 것은 fill 매개변수는 expand 매개변수가 FALSE로 설정되면 동작하지 않는다. 이와 유사하게 컨테이너를 homegeneous 매개 변수를 TRUE로 설정해서 생성하면 expand 매개변수는 작동하지 않는다.
이 것은 우측에 child widget을 위치 시킬 alignment 컨테이너를 생성할 것이다. horizontal box를 이 alignment 컨테이너에 추가하고 이 alignment 컨테이너는 vertical box에 적재한다. 우리는 alignment 컨테이너는 단 하나의 child widget밖에 갖을 수 없다는 것을 명심해야한다. 그래서 여기서 우리가 여러 개의 box를 사용해야하는 이유가 그것 때문인 것이다.
그림: GtkAlignment 컨테이너
Windows
다음은 좀 더 확장된 예제를 생성하게 될 것이다. JDeveloper IDE에서 찾아 볼 수 있는 윈도우를 살펴볼 것이다.
그림: JDeveloper에서의 Window dialog
이 다이얼로그는 JDeveloper 응용프로그램에서 열려 있는 모든 윈도우들을 좀더 정확히 이야기 하자면 Tab들을 보여준다.
close button은 text view widget 옆의 4번째 column에 배치시킨다. (숫자 매기기는 0부터 시작한다.) 이 button은 alignment widget에 추가한다. 맨 위쪽에 위치 시킬 수 있도록 하기위해서,
그림: windows
GTK+ events and signals
GTK+ 프로그래밍 도움말의 이번 부분에서는 GTK+ 라이브러리의 event system에 대해서 이야기 할 것이다. GTK+ 라이브러리는 event 기반으로 운용되는 system이다. 모든 GUI 응용프로그램은 event로 운용된다. 응용프로그램은 새롭게 생성되는 event들에 대해서 계속적으로 검사하는 main loop를 시작한다. 만약 아무런 event가 없다면, 응용프로그램은 대기 하면서 아무런 동작도 하지 않는다. GTK+에서 event는 X server로부터의 message이다. event가 widget에 도달할때 signal을 방출하면서 이 event에 대해서 반응한다. GTK+ 프로그래머는 signal에 특정 callback함수를 연결할 수 있다. 이 callback 함수는 signal에 반응하는 handler 함수이다.
이 callback 함수는 "clicked" 문자를 console에 출력할 것이다. callback 함수의 첫 번째 매개변수는 signal을 방출하는 object이다. 이 경우에는 Click button이 된다. 두 번째 매개변수는 선택사항이다. 어떤 데이터라도 callback 함수에 전달 할 수 있을 것이다. 이 경우에는 어떤 데이터도 전달하지 않는다. g_signal_connect() 함수에서 NULL 매개변수를 전달한다.
widget의 event mask는 어떤 종류의 event가 특정 widget에서 처리될 것인지 결정한다. 어떤 event는 사전에 설정되어 있고, 그렇지 않은 종류의 event는 사후에 event mask에 추가되어져야 한다. gtk_widget_add_events() 함수는 GDK_CONFIGURE의 event 타입을 mask에 추가한다. GDK_CONFIGURE의 event type은 모든 크기, 위치, 스택 순서 event를 차지한다.