GTK+ 프로그래밍에서 그림 그리기.

익명 사용자의 이미지

GTK+ 를 이용한 프로그래밍 입니다.
윈도우를 하나 만들고 거기에 그림그리는 함수를 써서 그려 보려 합니다.
근데 어떻게 해야할 지 모르겠습니다. 아래에 소스를 그대로 올립니다.

;-------------------------------------
ex0007.c 파일 입니다.
;-------------------------------------

/* 2001년 9월 26일
* GTK+ 을 이용한 X 윈도우 프로그래밍 [ex0007]
*
* 유니코드로 "안녕하세요" 표시 */

#include
#include
#include

/* 함수 선언 */
void fn_quit(GtkWidget *widget, gpointer data);

/* 메인 함수 */
int main(int argc, char *argv[])
{
/* 변수 선언 */
GtkWidget *Win_main;

gchar *progname = "ex0007";

/* GTK+ 함수 시작 */
gtk_init(&argc, &argv);

/* 메인 윈도우 생성 */
Win_main = gtk_window_new(GTK_WINDOW_TOPLEVEL);

gtk_signal_connect (GTK_OBJECT(Win_main), "delete_event",
GTK_SIGNAL_FUNC(fn_quit), NULL);

/* 윈도우 제목 설정 */
gtk_window_set_title( (GtkWindow *)Win_main, progname);

/* 여기가 그림그리는 함수 입니다. 선을 하나 그려 보려 합니다. */
gtk_draw_hline(Win_main->style, Win_main->window,
GTK_STATE_NORMAL, 50, 150,
50);

/* 윈도우 보이기 */
gtk_widget_show(Win_main);

/* 이벤트 처리 */
gtk_main();

return 0;
}

/* 종료 함수 */
void fn_quit(GtkWidget *widget, gpointer data)
{
g_print("프로그램이 종료되었습니다.\n");
gtk_main_quit();
}

;------------------------------------------------
Makefile 입니다.
;------------------------------------------------

# 2001년 9월 26일
# ex0007
#
# GTK+ 을 이용한 안녕하세요 프로그램

# 기본 컴파일러
CC = gcc

# 확장자를 제외한 소스 파일 이름
BJSOURCE = ex0007

# 일반적인 컴파일 옵션
BJCOMPILE = -Wall -g

# Xlib를 컴파일 하기위한 플래그
BJXINCLUDE = -I/usr/X11R6/include/X11

# Xlib 의 라이브러리
BJXLIB = -L/usr/X11R6/lib -lX11

# ksc2utf8 을 위한 옵션
BJKSC2UTF8 = -I/usr/local/lib/ksc2utf8 -L/usr/local/lib -lksc2utf8

# GTK+ 의 컴파일 옵션
BJGTKOPT = `gtk-config --cflags` `gtk-config --libs`

all $(BJSOURCE)

$(BJSOURCE)
$(CC) $(BJCOMPILE) $(BJGTKOPT) -o $(BJSOURCE) $(BJSOURCE).c

clean
rm -f $(BJSOURCE)

익명 사용자의 이미지

윈도우 시스템은 이벤트가 발생하면 그것을 처리하는 형식으로 구성됩니다.

일반적으로 윈도우 시스템은 다른 윈도우가 겹쳐지고 이동되고,
크기를 변경하는 등의 이벤트에 대해 화면내용을 적절히 복원하도록
특정한 윈도우에 이벤트를 보내도록 되어있습니다.

GTK 에서는 시그널이라는 개념을 사용해서, 특정한 이벤트와 그것을
처리하는 루틴을 연결하는 것으로 알고 있습니다.

그러므로, www.gtk.org 에 가셔서, GTK 시그널을 어떻게 연결하고
사용할 수 있는지 보시면 될 것 같습니다. 그 중 비타당화(invalidated)된
화면내용을 복원할 때 발생되는 시그널 위주로 공부하시면 되겠습니다.

지금 작성하신 루틴은 윈도우가 보이지 않는 상태에서 한 번 그리고
윈도우를 보이게 했으므로, 안그려지는 건 당연한 일입니다.
윈도우를 먼저 보이게하고 그리더라도 안그려질 수 있습니다. 그건
GTK 내부가 어떻게 구현되어있는지에 따라 다르겠지요.

익명 사용자의 이미지

#include

/* Backing pixmap for drawing area */
static GdkPixmap *pixmap = NULL;

/* Create a new backing pixmap of the appropriate size */
static gint configure_event( GtkWidget *widget,
GdkEventConfigure *event )
{
if (pixmap)
gdk_pixmap_unref(pixmap);

pixmap = gdk_pixmap_new(widget->window,
widget->allocation.width,
widget->allocation.height,
-1);
gdk_draw_rectangle (pixmap,
widget->style->white_gc,
TRUE,
0, 0,
widget->allocation.width,
widget->allocation.height);

return TRUE;
}

/* Redraw the screen from the backing pixmap */
static gint expose_event( GtkWidget *widget,
GdkEventExpose *event )
{
gdk_draw_pixmap(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
pixmap,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);

return FALSE;
}

/* Draw a rectangle on the screen */
static void draw_brush( GtkWidget *widget,
gdouble x,
gdouble y)
{
GdkRectangle update_rect;

update_rect.x = x - 5;
update_rect.y = y - 5;
update_rect.width = 10;

gdk_draw_rectangle (pixmap,
widget->style->black_gc,
TRUE,
update_rect.x, update_rect.y,
update_rect.width, update_rect.height);
gtk_widget_draw (widget, &update_rect);
}

static gint button_press_event( GtkWidget *widget,
GdkEventButton *event )
{
if (event->button == 1 && pixmap != NULL)
draw_brush (widget, event->x, event->y);

return TRUE;
}

static gint motion_notify_event( GtkWidget *widget,
GdkEventMotion *event )
{
int x, y;
GdkModifierType state;

if (event->is_hint)
gdk_window_get_pointer (event->window, &x, &y, &state);
else
{
x = event->x;
y = event->y;
state = event->state;
}

if (state & GDK_BUTTON1_MASK && pixmap != NULL)
draw_brush (widget, x, y);

return TRUE;
}

void quit ()
{
gtk_exit (0);
}

int main( int argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *drawing_area;
GtkWidget *vbox;

GtkWidget *button;

gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_name (window, "Test Input");

vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show (vbox);

gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (quit), NULL);

/* Create the drawing area */

drawing_area = gtk_drawing_area_new ();
gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);

gtk_widget_show (drawing_area);

/* Signals used to handle backing pixmap */

gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
(GtkSignalFunc) expose_event, NULL);
gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
(GtkSignalFunc) configure_event, NULL);

/* Event signals */

gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
(GtkSignalFunc) motion_notify_event, NULL);
gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
(GtkSignalFunc) button_press_event, NULL);

gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
| GDK_LEAVE_NOTIFY_MASK
| GDK_BUTTON_PRESS_MASK
| GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK);

/* .. And a quit button */
button = gtk_button_new_with_label ("Quit");
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);

gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (gtk_widget_destroy),
GTK_OBJECT (window));
gtk_widget_show (button);

gtk_widget_show (window);

gtk_main ();

return 0;
}
/* example-end */

지나가다 보고 example 하나 올려 봅니다.
여기선 drawing_area 에다가 사각형을 그리는 예제 인데 이부분만 고치신다면
생각하시는 것과 맞을지 모르겠네요.

참고가 됐으면 좋겠네요

익명 사용자의 이미지

소스를 보니 window에 바로 드로잉을 하려고
한듯하네요..
무언가를 그릴때는 먼저 드로잉 영역을 생성한
후에 드로잉 영역에 그리고
윈도우에 드로잉 영역을 연결시켜주셔야 합니다.
이곳의 "개발자코너/엑스윈도우프로그래밍"을
보시면 기본적인 엑스 플밍과
gtk에 관한 문서가 있습니다. 참고하세요.

익명 사용자의 이미지

"지나가다"님께서 올리신 소스를 http//www.gtk.org에서 보고 해결한 소스를 올립니다.
근데 제가 완성형 한글을 유니코드로 변환하는 라이브러리를 따로
만들어서 그 라이브러리를 이용해서 프로그래밍을 했기 때문에 컴파일이 안될겁니다.

http//myhome.hitel.net/~leesbk/utf_8/utf_8_index.html 에 해당 라이브러리
소스가 있습니다. 혹시 실행 시켜 보실거라면 여기 가셔서 라이브러리도 설치 해야 합니다.

워낙 초보라서 라이브러리라 할것도 없지만 아래 소스에 필요하기에 졸작을 올립니다.

;--------------------------------
ex0007.c 파일입니다.
;--------------------------------

/* 2001년 9월 26일
* GTK+ 을 이용한 X 윈도우 프로그래밍 [ex0007]
*
* 유니코드로 "안녕하세요" 표시 */

#include
#include

#include

#include

/* 전역 변수 선언 */
GdkPixmap *backing = NULL;
gchar *font_name = "-*-clearlyu-medium-*-normal-*-17-120-100-100-*-120-iso10646-*";

GdkWChar *message;
gint msg_count = 5;

guchar *han_message = "안녕하세요";
guchar *progname = "ex0007";

/* 함수 선언 */
void fn_quit(GtkWidget *widget, gpointer data);
gint expose_event( GtkWidget *widget, GdkEventExpose *event);
gint get_KSCs_To_GdkWChars(guchar *ksc, GdkWChar *ucs);

/* 메인 함수 */
int main(int argc, char *argv[])
{
/* 변수 선언 */
GtkWidget *Win_main, *board;

message = (GdkWChar *)malloc (sizeof(GdkWChar) * msg_count);

get_KSCs_To_GdkWChars(han_message, message);

/* GTK+ 함수 시작 */
gtk_init(&argc, &argv);

/* 메인 윈도우 생성 */
Win_main = gtk_window_new(GTK_WINDOW_TOPLEVEL);

gtk_signal_connect (GTK_OBJECT(Win_main), "delete_event",
GTK_SIGNAL_FUNC(fn_quit), NULL);

/* 윈도우 제목 설정 */
gtk_window_set_title( (GtkWindow *)Win_main, progname);

gtk_container_set_border_width ( (GtkContainer *)Win_main, 3);

/* GtkDrawingArea 생성 */
board = gtk_drawing_area_new();

/* 그리는 지역의 크기를 지정합니다. 이것보다 더 작아지지
* 않습니다. */
gtk_drawing_area_size(GTK_DRAWING_AREA(board), 200, 200);

gtk_container_add(GTK_CONTAINER(Win_main), board);

board->style->font = gdk_font_load(font_name);

gtk_widget_show(board);

/* 시그널 연결 */
gtk_signal_connect( GTK_OBJECT(board), "expose_event",
(GtkSignalFunc)expose_event, NULL);

gtk_widget_set_events(board, GDK_EXPOSURE_MASK);

/* 윈도우 보이기 */
gtk_widget_show(Win_main);

/* 이벤트 처리 */
gtk_main();

return 0;
}

/* 종료 함수 */
void fn_quit(GtkWidget *widget, gpointer data)
{
g_print("프로그램이 종료되었습니다.\n");
gtk_main_quit();
}

/* expose 이벤트 처리 함수 */
gint expose_event( GtkWidget *widget, GdkEventExpose *event)
{
if(backing != NULL)
{
gdk_pixmap_unref(backing);
}

backing = gdk_pixmap_new (widget->window,
widget->allocation.width,
widget->allocation.height,
-1);

gdk_draw_rectangle (backing,
widget->style->white_gc,
TRUE,
0, 0,
widget->allocation.width,
widget->allocation.height);

gdk_draw_text_wc (backing,
widget->style->font,
widget->style->black_gc,
50,50,
message, 10);

gdk_draw_pixmap (widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
backing,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}

/* 완성형 문장을 유니코드 문장으로 바꾸는 함수 */
gint get_KSCs_To_GdkWChars(guchar *ksc, GdkWChar *ucs)
{
unsigned short temp;
int i, j;

i = 10;

for(j = 0; j < i; j += 2)
{
temp = (unsigned short)(ksc[j]<<8) +
(unsigned short)(ksc[j + 1] & 0xff);;

ucs[j / 2] = getKSC2UCS(temp);
}

return i;
}

;-----------------------------------
Makefile 입니다.
;-----------------------------------

# 2001년 9월 26일
# ex0007
#
# GTK+ 을 이용한 안녕하세요 프로그램

# 기본 컴파일러
CC = gcc

# 확장자를 제외한 소스 파일 이름
BJSOURCE = ex0007

# 일반적인 컴파일 옵션
BJCOMPILE = -Wall -g

# Xlib를 컴파일 하기위한 플래그
BJXINCLUDE = -I/usr/X11R6/include/X11

# Xlib 의 라이브러리
BJXLIB = -L/usr/X11R6/lib -lX11

# ksc2utf8 을 위한 옵션
BJKSC2UTF8 = -I/usr/local/lib/ksc2utf8 -L/usr/local/lib -lksc2utf8

# GTK+ 의 컴파일 옵션
BJGTKOPT = `gtk-config --cflags` `gtk-config --libs`

all $(BJSOURCE)

$(BJSOURCE)
$(CC) $(BJCOMPILE) $(BJGTKOPT) $(BJKSC2UTF8) -o $(BJSOURCE) $(BJSOURCE).c

clean
rm -f $(BJSOURCE)

익명 사용자의 이미지

저도 윈도우 프로그래밍 처음 할 때 이걸 몰라서 헤맸는데
지금 화면에 보이는 마우스 포인터가 움직여도 이게 공짜로 되는게
아니더군요. -_-;

예를 들어 마우스 포인터를 마우스 움직이는 것에 따라서 계속
그려줘야 하고 이전에 가려졌던 부분을 다시 복구시켜 줘야 하죠.

이런 복구 시켜주는 루틴을 짜서 넣어줘야 복구 루틴이 콜 될 때
화면이 정상적으로 돌아오게 되죠. 보통 이미지 하나를 만들어서
그곳에 현재 화면을 복사해 두었다가 복구시킬 때 이벤트가 일어난
부분만 새로 그려주거나 하는 방법을 사용하죠.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.