반응형

파이게임과 GUI 라이브러리를 사용해 보자.

ImGui를 사용해 보려 했는데, OpenGL을 이용해야 하고 pygame.Surface.fill()을 사용할 수 없는 등 마음에 들지 않아 Pygame GUI를 사용하기로 했다.

 

pygame-gui를 설치한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import pygame
import pygame_gui
 
pygame.init()
pygame.display.set_caption("Super fun game development")
screenSize = (640480)
screen = pygame.display.set_mode(screenSize, pygame.DOUBLEBUF | pygame.RESIZABLE)
clock = pygame.time.Clock()
 
manager = pygame_gui.UIManager(screenSize)
hello_button = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((1010), (10050)),
                                            text='Say Hello', manager=manager)
 
running = True
 
while running:
    time_delta = clock.tick(60)/1000
    # As you may have noticed we also had to create a pygame Clock to track the amount of time
    # in seconds that passes between each loop of the program. We need this 'time_delta' value
    # because several of the UI elements make use of timers and this is a convenient place to
    # get it.
        
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
        
        if event.type == pygame_gui.UI_BUTTON_PRESSED:
              if event.ui_element == hello_button:
                  print('Hello World!')
        
        manager.process_events(event)
    
    manager.update(time_delta)
 
    screen.fill("black")
    pygame.draw.circle(screen, "gray", screen.get_rect().center, 100)
 
    manager.draw_ui(screen)
 
    pygame.display.flip()
 
pygame.quit()
 

 

코드를 입력하고 실행한다.

 

버튼이 표시된다.

 

2024.01.28 - [Python] - [Pygame] Box2D 파이게임 물리 라이브러리

위 링크의 코드를 이용해 조금 더 실용적인 예제를 만들어 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import math
import pygame
import pygame_gui
from Box2D import *
 
pygame.init()
pygame.display.set_caption("Physics Test")
screen = pygame.display.set_mode((640480))
running = True
player = pygame.image.load("player.png").convert()
 
manager = pygame_gui.UIManager((640480))
again_button = pygame_gui.elements.UIButton(relative_rect=pygame.Rect((35010), (200100)),
                                            text='Play again', manager=manager)
 
world = b2World(gravity=(09.8), doSleep=True)
 
groundBody = world.CreateStaticBody(position=(0400), shapes=b2PolygonShape(box=(5000)))
 
wallBody = world.CreateStaticBody(position=(3000), shapes=b2PolygonShape(box=(0400)))
 
playerBody = world.CreateDynamicBody(position=(00), linearVelocity=(500), angularVelocity=0.2)
playerFixtureDef = playerBody.CreatePolygonFixture(box=(player.get_width()/2,
                              player.get_height()/2), density=1, friction=0.5, restitution=0.7)
 
timeStep = 1.0 / 300
vel_iters, pos_iters = 62
  
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            playerBody.transform = ((00), 0)
            playerBody.linearVelocity = (500)
            playerBody.angularVelocity = 0.2
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            running = False
            
        if event.type == pygame_gui.UI_BUTTON_PRESSED:
            if event.ui_element == again_button:
                playerBody.transform = ((00), 0)
                playerBody.linearVelocity = (500)
                playerBody.angularVelocity = 0.2
        
        manager.process_events(event)
            
    manager.update(timeStep)
    
    world.Step(timeStep, vel_iters, pos_iters)
    world.ClearForces()
     
    screen.fill("black")
    pygame.draw.rect(screen, "brown", (040060020))
    pygame.draw.rect(screen, "yellow", (300020400))
 
    rotated_player = pygame.transform.rotate(player, playerBody.angle * 180/math.pi)
    
    screen.blit(rotated_player, (playerBody.position[0- rotated_player.get_width()/2,
                                 playerBody.position[1- rotated_player.get_height()/2))
 
    manager.draw_ui(screen)
    
    pygame.display.flip()
    
pygame.quit()
 

 

코드를 입력하고 실행한다.

 

버튼을 클릭하면 캐릭터가 다시 던져진다.

 

※ 참고

GUIs with pygame

Pygame GUI

 

반응형
Posted by J-sean
:
반응형

SDL에서 ImGui를 이용해 간단한 그래픽 유저 인터페이스를 구현해 보자.

 

비주얼 스튜디오에서 C++ 프로젝트를 만들고 소스파일(Source.cpp)을 추가한다.

SDL을 사용하기 위한 Include, Library 디렉토리 설정 등을 진행하고 ..\imgui-1.90.1\backends 에서 imgui_impl_sdl2.*, imgui_impl_sdlrenderer2.* 파일들을 복사한다. 나머지 파일들은 ..\imgui-1.90.1 에서 복사한다.

 

필터(ImGui)를 추가하고 복사한 파일들을 프로젝트에 추가한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <iostream>
#include "SDL.h"
#include "imgui.h"
#include "imgui_impl_sdl2.h"
#include "imgui_impl_sdlrenderer2.h"
 
int main(int argc, char* argv[]) {
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = SDL_CreateWindow("SDL Test", SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED, 640480, SDL_WINDOW_RESIZABLE);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -10);
 
    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO();
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
    //io.Fonts->AddFontFromFileTTF("newfont.ttf", 20);
    // If no fonts are loaded, dear imgui will use the default font.
 
    // Setup Dear ImGui style    
    ImGui::StyleColorsLight();
    //ImGui::StyleColorsDark();
 
    // Setup Platform/Renderer backends
    ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
    ImGui_ImplSDLRenderer2_Init(renderer);
 
    // Our state
    bool show_demo_window = true;
    bool show_another_window = false;
    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
 
    SDL_Event event;
    bool quit = false;
 
    // Poll and handle events (inputs, window resize, etc.)
    // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to
    // use your inputs.
    // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or
    // clear/overwrite your copy of the mouse data.
    // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application,
    // or clear/overwrite your copy of the keyboard data.
    // Generally you may always pass all inputs to dear imgui, and hide them from your application based on
    // those two flags.
    while (!quit) {
        while (SDL_PollEvent(&event)) {
            ImGui_ImplSDL2_ProcessEvent(&event);
            switch (event.type) {
            case SDL_QUIT:
                quit = true;
                break;
            case SDL_KEYDOWN:
                printf("Key pressed: %s\n", SDL_GetKeyName(event.key.keysym.sym));
                if (event.key.keysym.sym == SDLK_ESCAPE)
                    quit = true;
                break;
            default:
                break;
            }
        }
 
        // Start the Dear ImGui frame
        ImGui_ImplSDLRenderer2_NewFrame();
        ImGui_ImplSDL2_NewFrame();
        ImGui::NewFrame();
 
        // Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
        {
            static float f = 0.0f;
            static int counter = 0;
 
            ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
 
            ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
            ImGui::Checkbox("Demo Window"&show_demo_window); // Edit bools storing our window open/close state
            ImGui::Checkbox("Another Window"&show_another_window);
 
            ImGui::SliderFloat("float"&f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
            ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
 
            if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
                counter++;
            ImGui::SameLine();
            ImGui::Text("counter = %d", counter);
 
            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)"1000.0f / io.Framerate, io.Framerate);
            ImGui::End();
        }
 
        // Show another simple window.
        if (show_another_window)
        {
            ImGui::Begin("Another Window"&show_another_window);
            // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
            ImGui::Text("Hello from another window!");
            if (ImGui::Button("Close Me"))
                show_another_window = false;
            ImGui::End();
        }
 
        // Show only a button at (0, 0).
        {
            ImGui::SetNextWindowPos(ImVec2(00), ImGuiCond_Always);
            ImGui::Begin("No Name"NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration
                | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoSavedSettings);
            if (ImGui::Button("MyButton", ImVec2(200100))) {
                std::cout << "Clicked" << std::endl;
            }
            ImGui::End();
        }
 
        // Rendering
        ImGui::Render();
        SDL_SetRenderDrawColor(renderer, 255255255, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(renderer);
        ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData());
        SDL_RenderPresent(renderer);
    }
 
    // Cleanup
    ImGui_ImplSDLRenderer2_Shutdown();
    ImGui_ImplSDL2_Shutdown();
    ImGui::DestroyContext();
 
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
 
    return 0;
}
 

 

코드를 입력하고 빌드한다.

 

실행하면 윈도우에 GUI가 출력된다.

 

ImGui의 스타일(테마)은 아래와 같이 개별적으로도 지정할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Setup Dear ImGui style
//ImGui::StyleColorsLight();
//ImGui::StyleColorsDark();
ImGuiStyle& style = ImGui::GetStyle();
 
style.Colors[ImGuiCol_Text] = ImVec4(0.86f, 0.93f, 0.89f, 0.78f);
style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.86f, 0.93f, 0.89f, 0.28f);
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.13f, 0.14f, 0.17f, 1.00f);
style.Colors[ImGuiCol_Border] = ImVec4(0.31f, 0.31f, 1.00f, 0.00f);
style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.22f, 0.27f, 1.00f);
style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.92f, 0.18f, 0.29f, 0.78f);
style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_TitleBg] = ImVec4(0.20f, 0.22f, 0.27f, 1.00f);
style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.20f, 0.22f, 0.27f, 0.75f);
style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.20f, 0.22f, 0.27f, 0.47f);
style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.22f, 0.27f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.09f, 0.15f, 0.16f, 1.00f);
style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.92f, 0.18f, 0.29f, 0.78f);
style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_CheckMark] = ImVec4(0.71f, 0.22f, 0.27f, 1.00f);
style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.47f, 0.77f, 0.83f, 0.14f);
style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_Button] = ImVec4(0.92f, 0.18f, 0.29f, 0.70f);
style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.92f, 0.18f, 0.29f, 0.86f);
style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_Header] = ImVec4(0.92f, 0.18f, 0.29f, 0.76f);
style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.92f, 0.18f, 0.29f, 0.86f);
style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_Separator] = ImVec4(0.14f, 0.16f, 0.19f, 1.00f);
style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.92f, 0.18f, 0.29f, 0.78f);
style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_ResizeGrip] = ImVec4(0.47f, 0.77f, 0.83f, 0.04f);
style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.92f, 0.18f, 0.29f, 0.78f);
style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_PlotLines] = ImVec4(0.86f, 0.93f, 0.89f, 0.63f);
style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.86f, 0.93f, 0.89f, 0.63f);
style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.92f, 0.18f, 0.29f, 1.00f);
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.92f, 0.18f, 0.29f, 0.43f);
style.Colors[ImGuiCol_PopupBg] = ImVec4(0.20f, 0.22f, 0.27f, 0.9f);
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.22f, 0.27f, 0.73f);
 

 

 

※ 참고

Dear ImGui는 API Reference가 없다. Python 래퍼 pyimgui 를 참고하자.

pyimgui

 

반응형
Posted by J-sean
:
반응형

SDL 에는 GUI 기능이 없어 다른 라이브러리를 사용해야 한다. 많은 GUI 라이브러리가 있는데 ImGui 를 확인해 보자.

아래 링크에서 ImGui를 다운로드 한다.

Dear ImGui

 

압축을 풀고 examples - imgui_examples.sln 파일을 실행한다.

 

비주얼 스튜디오 버전이 다르면 프로젝트를 업그레이드 한다.

 

sdlrenderer2를 startup 프로젝트로 설정한다.

 

main.cpp 파일을 확인하자.

 

 

SDL 관련 명령에서 에러가 발생한다.

 

Project Property Pages - Additional Include Directories 에 정확한 SDL Include 디렉토리를 지정한다.

 

Project Property Pages - Additional Library Directories 에 정확한 SDL Library 디렉토리를 지정한다.

 

프로젝트를 빌드한다.

 

실행하면 윈도우에 GUI가 출력된다. (SDL2.dll 파일이 없다는 에러가 발생하면 복사해 넣어준다)

 

 

이번엔 내가 직접 만든 프로젝트에서 ImGui 예제를 실행해 보자.

 

ImGui 라이브러리 디렉토리는 위 그림과 같이 구성 되어 있다.

 

비주얼 스튜디오 프로젝트를 만들고 소스 파일 하나만 추가한다.

 

SDL2.dll 파일을 찾을 수 있도록 환경을 설정한다.

 

SDL과 ImGui에서 사용하는 Include 디렉토리를 설정한다.

 

 

SDL에서 사용하는 Library 디렉토리를 설정한다.

 

SDL에서 사용하는 라이브러리 파일을 설정한다.

 

ImGui, ImGui-Backend 필터를 만들고 ImGui SDL 예제에서 사용하는 파일을 추가한다.

 

처음에 만들어둔 소스 파일에 예제 소스파일(..\imgui-1.90.1\examples\example_sdl2_sdlrenderer2\main.cpp) 내용을 복사하고 빌드한다.

 

 

실행하면 운도우에 GUI가 출력된다.

 

※ 참고

Getting Started

 

반응형
Posted by J-sean
:
반응형

Qt6는 더 이상 오프라인 인스톨러를 제공하지 않는다. 오픈소스 온라인 인스톨러를 다운 받고 설치하자.

예전에는 Qt에 가입할 필요는 없었지만 지금은 아이디가 필요하다. 설치 전 미리 가입하자.

 

Latest releases - Qt - Qt 6.X.X - MSVC 2019 64-bit 만 선택하고 Developer and Designer Tools는 기본 상태 그대로 설치한다.

 

Qt 설치가 완료되면 Visual Studio - Extensions - Manage Extensions를 클릭한다.

 

Online - Visual Studio Marketplace에서 qt를 검색하고 Qt Visual Studio Tools를 설치한다. (Visual Studio 재시작이 필요하다)

 

Extensions - Qt VS Tools - Options를 클릭한다.

 

 

사용할 Qt를 추가해 주어야 한다. +아이콘을 클릭하고 Path를 클릭한다.

 

Qt가 설치된 디렉토리에서 qmake.exe 파일을 선택한다.

 

위 그림과 같이 설정 되었다면 OK를 클릭한다.

 

Qt Widgets Application 프로젝트를 만들자.

 

 

프로젝트 이름, 위치등을 지정하고 Create 버튼을 클릭한다.

 

Qt Widgets Application Wizard가 실행된다.

 

적당한 옵션을 선택한다.

 

적당한 옵션을 지정하고 Finish 버튼을 클릭한다.

 

 

소스파일이 표시된다.

 

Solution Explorer에서 UI 디자인 파일을 더블 클릭한다.

 

UI 디자인 화면이 표시된다.

 

Project Property Pages - Configuration Properties - C/C++ - Language를 클릭한다

 

 

Qt6는 C++ 17을 사용한다.

 

소스나 UI 수정없이 빌드하고 실행했을 때 위와 같은 위도우가 뜨면 성공이다. 

 

그런데 UI 디자인툴에서 PushButton - 우클릭을 해도 'Go to slot...'에 해당하는 명령어가 나오지 않는다.

그 뿐만 아니라 프로젝트 생성시 Qt Creator와 생성되는 파일도 다르고 코드를 작성해도 이해할 수 없는 방식으로 작동한다.

 

Qt Creator를 실행하고 Projects - New를 클릭한다.

 

 

Application (Qt) - Qt Widgets Application을 선택한다. 나머지 옵션은 적당히 선택한다.

 

Visual Studio와는 약간 다른 파일들이 생성되었다.

 

Forms - mainwindow.ui를 더블 클릭한다.

 

Label과 Pushbutton을 적당히 배치하고 Pushbutton에서 우클릭 - Go to slot...을 클릭한다.

 

 

clicked()를 선택하고 OK 버튼을 클릭한다.

 

mainwindow.cpp에 on_pushButton_clicked()가 생성되었다. (mainwindow.h 파일도 변경된다)

 

mainwindow.h 파일을 위와 같이 수정한다.

 

mainwindow.cpp 파일을 위와 같이 수정하고 빌드한다.

 

 

프로젝트를 실행하면 위와 같은 윈도우가 나타난다.

 

Pushbutton을 클릭하면 Label이 변경된다.

 

Pushbutton을 클릭할때마다 Label은 계속 변경된다.

다른 간단한 예제는 아래 링크를 참고한다.

2019.01.16 - [C, C++] - Qt 설치 및 간단한 사용 예

2019.02.21 - [C, C++] - Qt 스프라이트 애니매이션

 

반응형
Posted by J-sean
:
반응형

리눅스(우분투)에서 Qt5를 이용해 GUI 프로그래밍을 해 보자.

 

Qt5를 설치한다.

 

단순한 window를 만드는 소스를 입력한다. (qt.cpp)

 

-fPIC 옵션과 함께 컴파일(빌드)하고 생성된 파일을 실행하면 Simple Example 윈도우가 나타난다.

 

이번엔 같은 소스를 qmake를 이용해 컴파일(빌드)해 보자. -project 옵션과 함께 실행하면 c.pro 파일이 생성된다. (디렉토리 이름.pro)

 

 

c.pro 파일의 내용을 보면 Qt Widgets 모듈이 포함되지 않았다.

 

파일의 끝에 Qt Widgets 모듈을 포함시킨다.

 

qmake, make 명령을 차례로 실행하면 컴파일(빌드)이 완료된다.

 

컴파일(빌드)된 파일을 실행하면 윈도우가 나타난다.

 

반응형
Posted by J-sean
:
반응형

리눅스(우분투)에서 GTK+3를 이용해 GUI 프로그래밍을 해 보자.

 

GTK+3를 설치한다.

 

단순한 window를 만드는 예제 소스를 입력한다.

 

컴파일(빌드)하고 실행하면 창이 나타나다. 단순한 창이지만 이동, 종료등의 모든 기본적인 기능을 갖고 있다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <gtk/gtk.h>
 
/* This is a callback function. The data arguments are ignored
 * in this example. More on callbacks below. */
static void hello( GtkWidget *widget,
                   gpointer   data )
{
    g_print ("Hello World\n");
}
 
static gboolean delete_event( GtkWidget *widget,
                              GdkEvent  *event,
                              gpointer   data )
{
    /* If you return FALSE in the "delete-event" signal handler,
     * GTK will emit the "destroy" signal. Returning TRUE means
     * you don't want the window to be destroyed.
     * This is useful for popping up 'are you sure you want to quit?'
     * type dialogs. */
 
    g_print ("delete event occurred\n");
 
    /* Change TRUE to FALSE and the main window will be destroyed with
     * a "delete-event". */
 
    return TRUE;
}
 
/* Another callback */
static void destroy( GtkWidget *widget,
                     gpointer   data )
{
    gtk_main_quit ();
}
 
int main( int   argc,
          char *argv[] )
{
    /* GtkWidget is the storage type for widgets */
    GtkWidget *window;
    GtkWidget *button;
    
    /* This is called in all GTK applications. Arguments are parsed
     * from the command line and are returned to the application. */
    gtk_init (&argc, &argv);
    
    /* create a new window */
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    
    /* When the window is given the "delete-event" signal (this is given
     * by the window manager, usually by the "close" option, or on the
     * titlebar), we ask it to call the delete_event () function
     * as defined above. The data passed to the callback
     * function is NULL and is ignored in the callback function. */
    g_signal_connect (window, "delete-event",
              G_CALLBACK (delete_event), NULL);
    
    /* Here we connect the "destroy" event to a signal handler.  
     * This event occurs when we call gtk_widget_destroy() on the window,
     * or if we return FALSE in the "delete-event" callback. */
    g_signal_connect (window, "destroy",
              G_CALLBACK (destroy), NULL);
    
    /* Sets the border width of the window. */
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
    
    /* Creates a new button with the label "Hello World". */
    button = gtk_button_new_with_label ("Hello World");
    
    /* When the button receives the "clicked" signal, it will call the
     * function hello() passing it NULL as its argument.  The hello()
     * function is defined above. */
    g_signal_connect (button, "clicked",
              G_CALLBACK (hello), NULL);
    
    /* This will cause the window to be destroyed by calling
     * gtk_widget_destroy(window) when "clicked".  Again, the destroy
     * signal could come from here, or the window manager. */
    g_signal_connect_swapped (button, "clicked",
                  G_CALLBACK (gtk_widget_destroy),
                              window);
    
    /* This packs the button into the window (a gtk container). */
    gtk_container_add (GTK_CONTAINER (window), button);
    
    /* The final step is to display this newly created widget. */
    gtk_widget_show (button);
    
    /* and the window */
    gtk_widget_show (window);
    
    /* All GTK applications must have a gtk_main(). Control ends here
     * and waits for an event to occur (like a key press or
     * mouse event). */
    gtk_main ();
    
    return 0;
}
 

 

GTK+2 스타일의 예제 소스를 입력해 보자.

 

GTK+2 스타일의 소스를 빌드해도 문제 없다. Hello World 버튼을 클릭한다.

 

터미널 출력까지 잘 된다.

 

반응형
Posted by J-sean
:
반응형

cvui is a (very) simple UI lib built on top of OpenCV drawing primitives. Other UI libs, such as imgui, require a graphical backend (e.g. OpenGL) to work, so if you want to use imgui in a OpenCV app, you must make it OpenGL enabled, for instance.

It is not the case with cvui, which uses only OpenCV drawing primitives to do all the rendering (no OpenGL or Qt required).


OpenCV는 실시간 이미지 프로세싱에 중점을 둔 라이브러리로, 기본적인 GUI 지원은 상당히 빈약하기 때문에 대부분 MFC나 QT등의 라이브러리를 이용해 따로 GUI를 구현 합니다. 보통 이런 라이브러리들은 공부하고 실제 사용하는데 상당히 오랜 시간이 걸리므로 쉽고 간단히 사용할 수 있는 cvui의 사용법을 알아 보도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <opencv2/opencv.hpp>
 
#define CVUI_IMPLEMENTATION
#include "cvui.h"
 
using namespace cv;
 
int main(int argc, char** argv)
{
    Mat img = imread("image.jpg");
    Mat canny;
    double threshold1 = 50.0;
    double threshold2 = 150.0;
    bool checked = false;
 
    if (img.empty())
        return -1;
 
    cvui::init("Canny");
 
    while (true)
    {
        if (checked)
        {
            cvtColor(img, canny, CV_BGR2GRAY);
            Canny(canny, canny, threshold1, threshold2);
            cvtColor(canny, canny, CV_GRAY2BGR);
 
            cvui::trackbar(canny, 10160195&threshold1, (double)5.0, (double)100.0);
            cvui::trackbar(canny, 10210195&threshold2, (double)50.0, (double)200.0);
        }
        else
        {
            img.copyTo(canny);
        }
 
        cvui::text(canny, 1010"cvui example"1.00xff0000);
        if (cvui::button(canny, 1060"Exit"))
            break;
        cvui::checkbox(canny, 10110"Canny edge detection"&checked);
 
        cvui::update();
 
        imshow("Canny", canny);
 
        waitKey(10);
    }
 
    return 0;
}
cs







반응형
Posted by J-sean
:

tkinter GUI

OpenCV 2018. 12. 29. 10:06 |
반응형

OpenCV와 함께 tkinter를 이용해 아래처럼 GUI를 원하는대로 만들 수 있다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import cv2
import sys
import tkinter as tk
from PIL import Image, ImageTk
# The ImageTk module contains support to create and modify Tkinter BitmapImage and PhotoImage objects from PIL images
 
main = tk.Tk()
main.title("OpenCV-tkinter")
 
cvFrame = tk.Frame(main)
# A frame is basically just a container for other widgets.
cvFrame.grid(row = 0, column = 0, padx = 10, pady = 10)
 
lbl1 = tk.Label(cvFrame)
lbl1.grid(row = 0, column = 0)
 
lbl2 = tk.Label(cvFrame)
lbl2.grid(row = 0, column = 1)
 
def ExitButton():
    sys.exit()
 
btn = tk.Button(cvFrame, text = "Exit", font = ('Arial''30''bold'), foreground = "Red", command = ExitButton) # (.., height = 2, width = 60, ..)
# fron - As a tuple whose first element is the font family, followed by a size (in points if positive, in pixels if negative), optionally followed by
# a string containing one or more of the style modifiers bold, italic, underline, and overstrike.
btn.grid(row = 1, column = 0, columnspan = 2, sticky = tk.N + tk.S + tk.W + tk.E)
# columnspan - Normally a widget occupies only one cell in the grid. However, you can grab multiple cells of a row and merge them into one
# larger cell by setting the columnspan option to the number of cells. For example, w.grid(row=0, column=2, columnspan=3) would place widget
# w in a cell that spans columns 2, 3, and 4 of row 0.
# sticky - This option determines how to distribute any extra space within the cell that is not taken up by the widget at its natural size.
 
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
frame_size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
print('frame_size =', frame_size)
 
def show_frame():
    retval, frame = cap.read()
    frame = cv2.flip(frame, 1)
 
    cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
    img = Image.fromarray(cv2image)
    # Creates an image memory from an object exporting the array interface (using the buffer protocol).
    imgtk = ImageTk.PhotoImage(image = img)
    # A Tkinter-compatible photo image. This can be used everywhere Tkinter expects an image object.
    # If the image is an RGBA image, pixels having alpha 0 are treated as transparent.
    lbl1.imgtk = imgtk
    lbl1.configure(image = imgtk)
    # Set the values of one or more options.
 
    lbl2.imgtk = imgtk
    lbl2.configure(image = imgtk)
 
    # lbl.after(10, show_frame)
    main.after(10, show_frame)
    # Requests Tkinter to call function callback with arguments args after a delay of at least delay_ms milliseconds.
 
show_frame()
main.mainloop()
cs


반응형
Posted by J-sean
: