한국어
오픈소스포럼
 이곳은 다양한 오픈소스 프로젝트를 소개하고 리뷰, 활용 방법을 공유합니다.

NAppGUI는 C 프로그래밍 언어(ANSI C90)를 사용하여 크로스 플랫폼 데스크톱(Windows, macOS 또는 Linux) 애플리케이션을 구축하기 위한 라이브러리다.

c_programming_stack.png
운영체제 네이티브 API 위에 경량의 레이어로 구축되어 외부 종속성 없이 작고 빠르고 이식 가능한 프로그램을 만들 수 있다. C++로도 가능하지만 필수는 아니며 C언어만 사용하여 완전한 프로그램을 작성할 수 있다. (잘 작성된 문서가 제공되서 맘에든다.)

애플리케이션의 국제화 및 현지화 지원도 쉽게 가능하다. 모든 텍스트에 UTF-8을 사용하므로 세계 모든 언어에 대한 번역을 추가하고 응용 프로그램을 다시 실행 할 필요 없이 동적으로 텍스트를 조정하는 실시간 인터페이스 구성기능을 제공한다.

static void i_OnLangPopUp(Ctrl *ctrl, Event *e)
{
    const EvButton *params = event_params(e, EvButton);
    static const char_t *LANGS[] = { "en_US", "es_ES", "pt_PT", "it_IT", "vi_VN", "ru_RU", "ja_JP" };
    gui_language(LANGS[params->index]);
}

NAppGUI는 MIT 라이선스에 따라 배포되며, 이는 상업 및 오픈 프로젝트 모두에서 무료로 사용할 수 있음을 의미한다.

Windows에서 빠르게 시작하기

시작하기 전에 다음 도구가 설치되어 있어야 한다.

  • Microsoft Visual Studio C++ build tools 또는 Visual Studio
  • CMake
  • Git

첫 번째 단계는 GitHub를 통해 SDK 사본을 얻는 것이다. x64 Native Tools Command Prompt for VS 2019를 실행하고 다음과 같이 할 수 있다.

git clone --depth 1 https://github.com/frang75/nappgui.git nappgui_sdk

템플릿 디렉토리 구성
inc : SDK 헤더 파일.
lib : Windows, macOS 및 Linux 시스템용의 미리 컴파일된 NAppGUI 라이브러리(x86, x64, arm).
prj : CMake 빌드 스크립트 또는 솔루션을 생성하는 데 사용할 파일.
src : 예제 소스코드 또는 향후에 자신의 프로젝트를 추가할 위치.

다음 단계는 CMake 구성을 실행하고 컴파일을 실행한다.

# 빌드 디렉토리 생성
mkdir build
cd build

# CMake 구성 실행. 이 명령은 예제와 향후 프로젝트를 컴파일하는 데 필요한 NAppGUI.sln 솔루션을 자동으로 생성한다.
cmake -G "Visual Studio 16 2019" ../nappgui_sdk/src

# 동일한 작업 디렉토리에서 msbuild를 실행.
msbuild NAppGUI.sln

컴파일되면 demo 및 howto 디렉토리에서 예제 애플리케이션을 실행할 수 있다.

run_demo_windows.png

NAppGUI 응용프로그램 기본 구조

NAppGUI 응용 프로그램은 다른 시스템에서 데스크톱 프로그램의 시작을 통합하는 다중 플랫폼 매크로인 osmain에서 시작한다. #include "osmain.h"에 정의되어 있으며 4개의 매개변수를 받는다. 생성자, 소멸자, 옵션 문자열, 응용 프로그램 개체의 유형이 그것이다. 이런 식으로 기본 골격은 다음과 같다.

#include "nappgui.h"

typedef struct _app_t App;
struct _app_t
{
    Window *window;
};

static App *i_create(void)
{
    App *app = heap_new0(App);
    return app;
}

static void i_destroy(App **app)
{
    heap_delete(app, App);
}

#include "osmain.h"
osmain(i_create, i_destroy, "", App)

지시문 #include "nappgui.h"는 단일 명령으로 NAppGUI의 많은 것들을 포함한다. 원하는 경우 필요한 헤더만 별도로 포함하도록 할 수 있다.

#include "gui.h"
#include "button.h"
#include "heap.h"
#include "label.h"
#include "layout.h"
#include "listener.h"
#include "panel.h"
#include "strings.h"
#include "v2d.h"
#include "vtext.h"
#include "window.h"

완전한 예제 프로그램

조금 더 실용적인 예제를 통해 어떻게 생겼는지 살펴볼 필요가 있다. 다음은 예제로 살펴볼 완전한 프로그램이다.
demo/hello/main.c

/* NAppGUI Hello World */

#include "nappgui.h"

typedef struct _app_t App;

struct _app_t
{
    Window *window;
    TextView *text;
    uint32_t clicks;
};

/*---------------------------------------------------------------------------*/

static void i_OnButton(App *app, Event *e)
{
    String *msg = str_printf("Button click (%d)\n", app->clicks);
    textview_writef(app->text, tc(msg));
    str_destroy(&msg);
    app->clicks += 1;
    unref(e);
}

/*---------------------------------------------------------------------------*/

static Panel *i_panel(App *app)
{
    Panel *panel = panel_create();
    Layout *layout = layout_create(1, 3);
    Label *label = label_create();
    Button *button = button_push();
    TextView *text = textview_create();
    app->text = text;
    label_text(label, "Hello!, I'm a label");
    button_text(button, "Click Me!");
    button_OnClick(button, listener(app, i_OnButton, App));
    layout_label(layout, label, 0, 0);
    layout_button(layout, button, 0, 1);
    layout_textview(layout, text, 0, 2);
    layout_hsize(layout, 0, 250);
    layout_vsize(layout, 2, 100);
    layout_margin(layout, 5);
    layout_vmargin(layout, 0, 5);
    layout_vmargin(layout, 1, 5);
    panel_layout(panel, layout);
    return panel;
}

/*---------------------------------------------------------------------------*/

static void i_OnClose(App *app, Event *e)
{
    osapp_finish();
    unref(app);
    unref(e);
}

/*---------------------------------------------------------------------------*/

static App *i_create(void)
{
    App *app = heap_new0(App);
    Panel *panel = i_panel(app);
    app->window = window_create(ekWNSTD);
    window_panel(app->window, panel);
    window_title(app->window, "Hello, World!");
    window_origin(app->window, v2df(500, 200));
    window_OnClose(app->window, listener(app, i_OnClose, App));
    window_show(app->window);
    return app;
}

/*---------------------------------------------------------------------------*/

static void i_destroy(App **app)
{
    window_destroy(&(*app)->window);
    heap_delete(app, App);
}

/*---------------------------------------------------------------------------*/

#include "osmain.h"
osmain(i_create, i_destroy, "", App)

생성자

첫 번째 osmain 매개변수는 애플리케이션의 생성자다.
프로그램이 시작되자마자 특정 내부 자료 및 개체를 초기화해야 하고 모든 데스크톱 응용 프로그램에 고유한 메시지 루프를 시작해야 한다. 모든 것이 준비되면 생성자가 호출되어 응용 프로그램 개체를 만든다. 이 개체는 모든 유형이 될 수 있으며 Application 또는 이와 유사한 클래스에서 파생될 필요가 없다. 이 예제의 단순성을 감안할 때 응용 프로그램 개체에는 하나의 창만 표시된다.

static App *i_create(void)
{
    App *app = heap_new0(App);
    Panel *panel = i_panel(app);
    app->window = window_create(ekWINDOW_STD);
    window_panel(app->window, panel);
    return app;
}

메인 패널

기본 창을 만들려면 창에 표시된 모든 인터페이스 컨트롤을 통합하는 컨테이너인 메인 패널이 필요하다. 패널 내부 공간은 레이아웃이라는 보이지 않는 그리드로 구성된다. 각 패널은 여러 레이아웃을 가질 수 있고 그 사이에서 재구성될 수 있지만 적어도 하나는 필요하다. 셀 내에서 다양한 인터페이스 컨트롤을 찾는다.

static Panel *i_panel(App *app)
{
    Panel *panel = panel_create();
    Layout *layout = layout_create(1, 3);
    Label *label = label_create();
    Button *button = button_push();
    TextView *text = textview_create();
    label_text(label, "Hello!, I'm a label");
    button_text(button, "Click Me!");
    layout_label(layout, label, 0, 0);
    layout_button(layout, button, 0, 1);
    layout_textview(layout, text, 0, 2);
    panel_layout(panel, layout);
    return panel;
}

소멸자

응용 프로그램이 종료되면 osmain은 소멸자(매크로의 두 번째 매개변수)를 호출하여 프로그램을 완전히 종료하기 위해 응용 프로그램 개체와 이에 종속된 모든 것을 해제한다. 모든 메모리를 적절하게 해제하지 못하면 심각한 코딩 오류로 간주되기 때문에 우리는 이것에 많은 중점을 둬야 한다.

static void i_destroy(App **app)
{
    window_destroy(&(*app)->window);
    heap_delete(app, App);
}

Window 보이기

기본적으로 NAppGUI는 모든 창을 숨김 모드로 생성하므로 명시적으로 표시해야 한다. 제목 및 초기 위치를 설정하고 window_show로 시작한다.

static App *i_create(void)
{
   ...
   window_title(app->main_window, "Hello World!");
   window_origin(app->main_window, v2df(500, 200));
   window_show(app->main_window);
   ...
}

hello_world_without_format.png

레이아웃 형식

창의 모양을 개선하기 위해 디자인에 약간의 형식을 지정해 본다. 특히, 세 번째 행(텍스트 컨트롤)의 열 너비와 높이를 설정한다. 그런 다음 가장자리에 여백을 남기고 행 사이를 분리한다.

layout_hsize(layout, 0, 200);
layout_vsize(layout, 2, 100);
layout_margin(layout, 5);
layout_vmargin(layout, 0, 5);
layout_vmargin(layout, 1, 5);

hello_world_formatted.png

프로그램 닫기

기본적으로 메인 창을 닫을 때 프로그램이 종료되지 않는다. 이것은 열려 있는 창이 없어도 Dock에서 계속 실행되는 macOS 응용 프로그램의 일반적인 것이다. NAppGUI는 프로그램을 닫지 않는 것과 동일한 기준을 따르므로 osapp_finish 함수를 명시적으로 호출해야 한다. 이를 위해 listener매크로를 통해 버튼 이벤트를 캡처한다.

static void i_OnClose(App *app, Event *e)
{
    osapp_finish();
}

static App *i_create(void)
{
   window_OnClose(app->main_window, listener(app, i_OnClose, App));
}

버튼 이벤트

마지막으로 버튼의 클릭 이벤트를 캡처하고 누를 때마다 텍스트 상자에 메시지를 표시한다. 메시지 작성 및 표시를 담당하는 i_OnButton 핸들러를 구현하고 이전에 만든 Button 컨트롤에 연결한다.

static void i_OnButton(App *app, Event *e)
{
    String *msg = str_printf("Button click (%d)\n", app->clicks);
    text_insert(app->vtext, tc(msg));
    str_destroy(&msg);
    app->clicks += 1;
}
...
button_OnClick(button, listener(app, i_OnButton, App));

 

공식 웹사이트: https://nappgui.com
저장소: https://github.com/frang75/nappgui_src

번호 제목 글쓴이 날짜 조회 수
» NAppGUI, C언어용 크로스 플랫폼 GUI 라이브러리 file makersweb 2022.10.10 123
29 OTA 오픈소스 프로젝트 makersweb 2022.08.03 66
28 AGL (Automotive Grade Linux) 개요 file makersweb 2022.06.19 1179
27 Chromium과 Ozone 층 file makersweb 2022.03.03 410
26 Flutter Application 에서 한글(EUC-KR) 깨져서 나오는 문제 file makersweb 2022.01.06 725
25 CopperSpice 에 대해서 (C++ Gui 라이브러리) file makersweb 2022.01.02 314
24 Flutter/Dart 와 Qt/QML 비교 file makersweb 2021.11.07 652
23 VSCode 와 Qbs 플러그인으로 C/C++ 개발환경 구성 file makersweb 2021.09.12 496
22 ZeroMQ 를 이용한 Qt 응용프로그램 간 통신 file makersweb 2021.08.28 560
21 C++를 위한 Lottie 라이브러리 with SDL2 file makersweb 2021.08.15 678
20 CANdevStudio 를 사용하여 CAN 네트워크 시뮬레이션 file makersweb 2021.03.09 939
19 Protocol Buffers 를 이용한 직렬화 with Conan Package Manager file makersweb 2021.02.24 544
18 라즈베리파이에서 Redis의 Pub/Sub 패턴을 사용하는 Electron 응용프로그램 file makersweb 2021.01.31 483
17 Nana, C++용 크로스플랫폼 GUI 라이브러리 file makersweb 2021.01.06 1596
16 라즈베리파이4에서 openFrameworks 예제 실행 file makersweb 2020.12.13 413
15 Dear ImGui, 경량의 C++ 용 GUI 및 Widget 라이브러리 file makersweb 2020.11.28 6297
14 GENIVI DLT(Diagnostic Log and Trace) 활용 file makersweb 2020.11.19 4150
13 윈도우에서 안드로이드 flutter 프로그래밍 개발환경 구축(with Visual Studio Code) file makersweb 2020.09.16 560
12 가볍고 쉬운 임베디드용 그래픽 라이브러리 - LVGL file makersweb 2020.09.16 1511
11 Qt와 GStreamer 로 작성한 flac 오디오 재생 예제 file makersweb 2020.09.05 909