<?xml version="1.0" encoding="utf-8"?>
<page xmlns="http://projectmallard.org/1.0/" xmlns:its="http://www.w3.org/2005/11/its" xmlns:xi="http://www.w3.org/2001/XInclude" type="topic" style="task" id="03_getting_the_signal.js" xml:lang="ko">
  <info>
    <link type="guide" xref="beginner.js#tutorials"/>
    <link type="seealso" xref="button.js"/>
    <link type="seealso" xref="entry.js"/>
    <link type="seealso" xref="radiobutton.js"/>
    <link type="seealso" xref="switch.js"/>
    <revision version="0.1" date="2012-08-12" status="draft"/>

    <credit type="author copyright">
      <name>Taryn Fox</name>
      <email its:translate="no">jewelfox@fursona.net</email>
      <years>2012</years>
    </credit>

    <desc>단추와 단추를 누르면 동작하는 다른 위젯을 만듭니다.</desc>
  
    <mal:credit xmlns:mal="http://projectmallard.org/1.0/" type="translator copyright">
      <mal:name>조성호</mal:name>
      <mal:email>shcho@gnome.org</mal:email>
      <mal:years>2017-2019.</mal:years>
    </mal:credit>
  </info>

  <title>3. 시그널 취하기</title>
  <synopsis>
    <p>이전 따라하기 과정에서 레이블, 그림, 단추 위젯을 만드는 방법을 알아보았습니다. 여기서는 단추를 누르거나 어떤 반응을 받았을 때 보내는 시그널을 처리할 함수를 작성하여 단추와 기타 입력 위젯을 만드는 방법을 알아보겠습니다.</p>
  </synopsis>

  <links type="section"/>

  <section id="application">
    <title>기본 프로그램</title>
    <p>그놈에서 단추, 스위치 같이 다룰 수 있는 위젯은 누르거나 마우스 커서를 올려두는 식으로 활성화하면 시그널을 내보냅니다. 예를 들어, 단추라면 누군가가 단추를 누르면 "clicked" 시그널을 내보냅니다. 시그널이 나오면, 그놈에서는 여러분이 작성한 코드에서 시그널에 반응하는 부분을 찾습니다.</p>
    <p>코드를 어떻게 작성할까요? 단추의 "clicked" 시그널을 콜백 함수에 연결하면, 해당 함수에서 시그널을 처리합니다. 따라서 시그널을 줄 때마다 시그널에 연결한 함수가 동작하죠.</p>
    <p>매우 기본적인 예제입니다:</p>

    <media type="image" mime="image/png" src="media/03_jssignal_01.png"/>

    <p>ApplicationWindow에는 단추와 레이블이 있는데 이걸 그리드로 정렬했습니다. 단추를 클릭할 때마다 과자 갯수 값을 가진 변수 값이 하나씩 늘어나고, 과자 갯수를 보여주는 레이블이 바뀝니다.</p>
    <note style="tip"><p>이 예제의 과자는 웹사이트에서 로그인 정보를 저장하고 방문 사이트 상태를 보관하는 그런 과자가 아닙니다. 그냥 상상속의 무언가일 뿐이죠. 원하면 실제로 구워드세요.</p></note>
    <p>하여간, 윈도우와 위젯 만들기를 시작하기 전 프로그램을 시작하는 기본 기반 코드를 작성하겠습니다. 프로그램에 고유 이름을 붙이고, 기반 코드에서 확 바뀌는 부분은 과자 갯수 값을 보관하는 코드 시작 부분의 전역 변수 추가입니다.</p>
    <code mime="application/javascript">
#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';
const Gtk = imports.gi.Gtk;

// We start out with 0 cookies
var cookies = 0;

class GettingTheSignal {
    // Create the application itself
    constructor() {
        this.application = new Gtk.Application();

        // Connect 'activate' and 'startup' signals to the callback functions
        this.application.connect('activate', this._onActivate.bind(this));
        this.application.connect('startup', this._onStartup.bind(this));
    }

    // Callback function for 'activate' signal presents window when active
    _onActivate() {
        this._window.present();
    }

    // Callback function for 'startup' signal builds the UI
    _onStartup() {
        this._buildUI ();
    }
</code>
    <p>프로그램의 connect 메서드와 bind 부분을 보시죠. 창을 나타내고 사용자 인터페이스를 구성하는 함수에 activate 시그널과 startup 시그널을 연결하죠. 단추에도 "clicked" 시그널에 연결한다는 점만 빼고는 같은 방식을 취합니다.</p>
  </section>

  <section id="button">
    <title>단추 누르기</title>

    <p>보통 때와 같이, 프로그램을 시작할 때 호출하는 _buildUI 함수에, 단추와 다른 위젯을 만드는 모든 코드를 넣겠습니다.</p>
    <code mime="application/javascript">
    // Build the application's UI
    _buildUI() {
</code>

    <p>우선, 창을 만들고요:</p>
    <code mime="application/javascript">
        // Create the application window
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            default_height: 200,
            default_width: 400,
            title: "Click the button to get a cookie!"});
</code>
    <p>여기서 default_height, default_width 속성을 설정한 걸 보시죠. ApplicationWindow의 너비 높이를 픽셀 단위로 설정합니다.</p>
    <p>다음, 과자 갯수를 보여줄 레이블을 만들겠습니다. 레이블의 label 속성 일부로 cookies 변수를 사용할 수 있습니다.</p>
    <code mime="application/javascript">
        // Create the label
        this._cookieLabel = new Gtk.Label ({
            label: "Number of cookies: " + cookies });
</code>

    <p>다음, 단추를 만들겠습니다. 단추에 표시할 텍스트를 보여줄 때 label 속성 값을 설정할 수 있고, 프로그램 사용자 인터페이스를 구성하고 나서 작성할 _getACookie 함수에 "clicked" 시그널을 연결하겠습니다.</p>
    <code mime="application/javascript">
        // Create the cookie button
        this._cookieButton = new Gtk.Button ({ label: "Get a cookie" });

        // Connect the cookie button to the function that handles clicking it
        this._cookieButton.connect ('clicked', this._getACookie.bind(this));
</code>
    <p>마지막으로, 그리드를 만들어 레이블과 단추를 붙여넣은 후, 그리드에 붙여넣은 위젯을 창 위에 표시하도록 창에 추가하겠습니다. 이게 _buildUI 함수에서 작성할 모든 내용이니, 중괄호로 닫으세요. 쉼표를 입력해서 다음 함수로 넘어간다는걸 그놈에 알려주시고요. 레이블 코드를 먼저 작성하겠지만, 해당 코드 아래에서 그리드에 붙여넣을 수 있습니다.</p>
    <code mime="application/javascript">
        // Create a grid to arrange everything inside
        this._grid = new Gtk.Grid ({
            halign: Gtk.Align.CENTER,
            valign: Gtk.Align.CENTER,
            row_spacing: 20 });

        // Put everything inside the grid
        this._grid.attach (this._cookieButton, 0, 0, 1, 1);
        this._grid.attach (this._cookieLabel, 0, 1, 1, 1);

        // Add the grid to the window
        this._window.add (this._grid);

        // Show the window and all child widgets
        this._window.show_all();

    }
</code>
    <p>이제 _getACookie 함수를 작성하겠습니다. 단추에서 "clicked" 시그널을 보낼 따마다 이 함수의 코드를 실행합니다. 이 때 과자 갯수가 하나씩 늘어나며, 레이블에 새 과자 갯수 값이 들어가서 바뀝니다. 이 동작은 레이블의 set_label 메서드로 처리하겠습니다.</p>
    <note style="tip"><p>여러 위젯에 동일한 속성과 메서드가 있습니다. 레이블 및 단추에도 어떤 텍스트를 넣는지 나타내는 lable 속성이 있고, 어떤 텍스트가 있는지 확인하는 get_label과 텍스트를 바꾸는 set_label 메서드가 있습니다. 따라서 위젯 동작 방식을 알면 다른 위젯 동작 방식도 알게 되는거죠??.</p></note>
    <code mime="application/javascript">
    _getACookie: function() {

        // Increase the number of cookies by 1 and update the label
        cookies++;
        this._cookieLabel.set_label ("Number of cookies: " + cookies);

    }

};
</code>

    <p>마지막으로, 이전 따라하기 예제에서 코드를 실행했던 방식으로 프로그램을 실행하겠습니다.</p>
    <code mime="application/javascript">
// Run the application
let app = new GettingTheSignal ();
app.application.run (ARGV);
</code>
  </section>

  <section id="switch">
    <title>스위치 젖히기</title>
    <p>GTK+ 도구함에는 단추만 있는게 아닙니다. 이 예제에서와 같이 스위치도 있구요~. 스위치는 레이블 속성이 없어서 스위치가 어떤 역할을 하는지 레이블을 옆에 따로 만들어야합니다.</p>

    <media type="image" mime="image/png" src="media/03_jssignal_02.png"/>

    <p>스위치 단추의 위치는, 끔 아니면 켬 두가지가 있죠. 스위치를 켠 상태로 두면 텍스트와 배경 색이 바뀌어서 어떤 상태인지 확인할 수 있습니다.</p>

    <p>큰 글씨를 표시하고 화면 키보드를 켜고 끄는 기능을 갖춘 그놈 접근성 메뉴 같은데서 이런 스위치를 볼 수 있죠. 여기서 스위치로 가상의 과자 뽑기 기계 동작 여부를 다루겠습니다. 스위치를 켜두면 "Get a cookie" 단추를 눌렀을 때 과자를 받을 수 있습니다. 스위치를 끄면 단추를 눌렀을 때 반응하지 않고요.</p>
    <note style="tip"><p>화면의 우측 상단에 사용자 이름이 있는 사람 모양 아이콘을 누르면 접근성 메뉴로 들어갈 수 있습니다.</p></note>
    <p>이제 스위치를 어떻게 만드는지 알아보죠:</p>
    <code mime="application/javascript">
        // Create the switch that controls whether or not you can win
        this._cookieSwitch = new Gtk.Switch ();
</code>

    <p>스위치에서 뭘 할지는 실제로 연결할 필요가 없습니다. 우리가 할 일은 _getACookie 함수에서 if 구문을 작성해서 스위치가 켜졌는지 여부만 확인하면 됩니다. 스위치를 젖혔을 때 바로 무언가를 하려면 notify::active 시그널을 다음처럼 연결하면 됩니다:</p>
    <code mime="application/javascript">
        // Connect the switch to the function that handles it
        this._cookieSwitch.connect ('notify::active', this._cookieDispenser.bind(this));
</code>

    <p>스위치는 기본적으로 끔 위치로 설정해둡니다. 켠 상태로 시작하게 하려면, 스위치를 만들 때 active 속성을 true로 설정하면 됩니다.</p>
    <code mime="application/javascript">
        this._cookieSwitch = new Gtk.Switch ({ active: true });
</code>

    <p>그럼 평범하게 만들어보고 옆에 레이블을 붙여두죠. 스위치와 레이블은 오른편에 두는걸로 하겠습니다. 그렇게 해서, 이 위젯에 맞는 그리드를 만들고 이 그리드를 큰 그리드에 넣겠습니다. 다 만들고 나면 코드가 다음과 같이 되겠죠:</p>
    <code mime="application/javascript">
        // Create the switch that controls whether or not you can win
        this._cookieSwitch = new Gtk.Switch ();

        // Create the label to go with the switch
        this._switchLabel = new Gtk.Label ({
            label: "Cookie dispenser" });

        // Create a grid for the switch and its label
        this._switchGrid = new Gtk.Grid ({
            halign: Gtk.Align.CENTER,
            valign: Gtk.Align.CENTER });

        // Put the switch and its label inside that grid
        this._switchGrid.attach (this._switchLabel, 0, 0, 1, 1);
        this._switchGrid.attach (this._cookieSwitch, 1, 0, 1, 1);
</code>

    <p>마찬가지로 이제 더 큰 그리드에 몽땅 정리하겠습니다.</p>
    <code mime="application/javascript">
        // Put everything inside the grid
        this._grid.attach (this._cookieButton, 0, 0, 1, 1);
        this._grid.attach (this._switchGrid, 0, 1, 1, 1);
        this._grid.attach (this._cookieLabel, 0, 2, 1, 1);
</code>

    <p>이제 _getACookie 함수 코드를 바꿔서 과자 뽑기가 켜졌는지 확인하겠습니다. 스위치의 get_active 메서드를 사용하겠습니다. 스위치가 켜져있으면 true, 꺼져있으면 false를 반환합니다.</p>
    <note style="tip"><p>if 구문에서 다음과 같이 메서드를 사용하면, 메서드에서 true를 반환했을 때 if 구문 안에 있는 코드를 실행합니다.</p></note>
    <code mime="application/javascript">
    _getACookie() {

        // Is the cookie dispenser turned on?
        if (this._cookieSwitch.get_active()) {

            // Increase the number of cookies by 1 and update the label
            cookies++;
            this._cookieLabel.set_label ("Number of cookies: " + cookies);

        }

    }
</code>

  </section>

  <section id="radio">
    <title>라디오 튜닝</title>

    <p>우리가 쓸 수 있는 다른 입력 위젯으로 RadioButton이 있습니다. 한 모임 단위로 만들 수 있고, 모임 안에 있는 RadioButton은 한번에 하나만 선택할 수 있습니다. 구식 카 라디오의 프리셋 단추 처럼 동작하기 때문에 RadioButton으로 부릅니다. 라디오는 한번에 방송국 하나만 선택할 수 있기에, 어떤 단추를 누르면 다른 단추는 도로 튀어나옵니다.</p>

    <media type="image" mime="image/png" src="media/03_jssignal_03.png"/>

    <p>우선 ApplicationWindow의 이름을 바꾸고 border_width 속성 값을 늘려서, 위젯이 답답하게 붙어있지 않게 하겠습니다. border_width는 위젯과 창 가장자리 사이의 픽셀 단위 간격입니다.</p>
    <code mime="application/javascript">
        // Create the application window
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            default_height: 200,
            default_width: 400,
            border_width: 20,
            title: "Choose the one that says 'cookie'!"});
</code>

    <p>그 다음 RadioButton을 만들겠습니다. 근데 그룹안에 어떻게 만들었죠? 우리가 할 일은 각 RadioButton의 그룹 속성에 다른 RadioButton 이름을 넣는 일입니다.</p>
    <code mime="application/javascript">
        // Create the radio buttons
        this._cookieRadio = new Gtk.RadioButton ({ label: "Cookie" });
        this._notCookieOne = new Gtk.RadioButton ({ label: "Not cookie",
            group: this._cookieRadio });
        this._notCookieTwo = new Gtk.RadioButton ({ label: "Not cookie",
            group: this._cookieRadio });
</code>

    <p>다음 RadioButton의 그리드를 만들겠습니다. 만든 순서대로 그리드에 똑같이 정렬할 필요는 없습니다.</p>
    <code mime="application/javascript">
        // Arrange the radio buttons in their own grid
        this._radioGrid = new Gtk.Grid ();
        this._radioGrid.attach (this._notCookieOne, 0, 0, 1, 1);
        this._radioGrid.attach (this._cookieRadio, 0, 1, 1, 1);
        this._radioGrid.attach (this._notCookieTwo, 0, 2, 1, 1);
</code>

    <p>보통 기본으로 선택한 RadioButton은 그룹 이름으로 설정한 RadioButton입니다. 우선은 기본적으로 "Not cookie" 단추를 선택한 상태로 두려고 합니다. 그러니까 set_active 메서드를 쓰겠습니다.</p>
    <note style="tip"><p>RadioButton을 만들 때 active 속성을 설정할 수도 있습니다.</p></note>
    <code mime="application/javascript">
        // Set the button that will be at the top to be active by default
        this._notCookieOne.set_active (true);
</code>

    <p>이제 흔히 하던대로 메인 그리드에 모든 위젯을 정리하겠습니다 ...</p>
    <code mime="application/javascript">
        // Put everything inside the grid
        this._grid.attach (this._radioGrid, 0, 0, 1, 1);
        this._grid.attach (this._cookieButton, 0, 1, 1, 1);
        this._grid.attach (this._cookieLabel, 0, 2, 1, 1);
</code>

    <p>그리고 과자 단추를 선택했는지 확인하도록 _getACookie 함수 코드를 바꾸겠습니다.</p>
    <code mime="application/javascript">
    _getACookie() {

        // Did you select "cookie" instead of "not cookie"?
        if (this._cookieRadio.get_active()) {

            // Increase the number of cookies by 1 and update the label
            cookies++;
            this._cookieLabel.set_label ("Number of cookies: " + cookies);

        }

    }
</code>

  </section>

  <section id="spell">
    <title>"cookie" 쓸 수 있죠?</title>

    <p>우리가 다룰 마지막 위젯은 단일 행 텍스트 항목을 다루는 Entry 위젯입니다.</p>
    <note style="tip"><p>텍스트 편집기를 만들 때 처럼 한 문당 이상을 입력할 수 있는게 필요하다면, 개별적으로 이리저리 자유롭게 바꿀 수 있는 <link xref="textview.js">TextView</link> 위젯을 찾으시려는 지도 모르겠습니다.</p></note>
    <media type="image" mime="image/png" src="media/03_jssignal_04.png"/>

    <p>창 이름을 바꾸고 나서 Entry 위젯을 만들겠습니다.</p>
    <code mime="application/javascript">
        // Create the text entry field
        this._spellCookie = new Gtk.Entry ();
</code>

    <p>그 다음, 그리드에 모두 정리하고요 ...</p>
    <code mime="application/javascript">
        // Put everything inside the grid
        this._grid.attach (this._spellCookie, 0, 0, 1, 1);
        this._grid.attach (this._cookieButton, 0, 1, 1, 1);
        this._grid.attach (this._cookieLabel, 0, 2, 1, 1);
</code>

    <p>Entry의 get_text 메서드로 텍스트를 가져와서 "cookie" 문자열이 맞는지 확인하도록 _getACookie의 if 구문을 수정하겠습니다. "cookie"의 어디가 대문자인지는 상관하지 않을거기에 if 구문 안에서 Entry의 모든 텍스트 문자를 소문자로 바꾸는 JavaScript 내장 함수 toLowerCase를 사용하겠습니다.</p>
    <note style="tip"><p>Entry 위젯은 사용자가 못바꾸는 텍스트 문자열을 설정하는 label 속성이 없습니다(심지어 단추에도 보통은 레이블의 문자열을 바꿀 수 없습니다). 대신 사용자가 입력한 내용이 일치하는지 여부를 바꾸는 text 속성이 있습니다.</p></note>
    <code mime="application/javascript">
    _getACookie() {

        // Did you spell "cookie" correctly?
        if ((this._spellCookie.get_text()).toLowerCase() == "cookie") {

            // Increase the number of cookies by 1 and update the label
            cookies++;
            this._cookieLabel.set_label ("Number of cookies: " + cookies);

        }

    }
</code>

  </section>

  <section id="whats_next">
    <title>다음은요?</title>
    <p>과자 만들기 프로그램의 여러가지  각 버전에 해당하는 완전한 코드를 보려면 계속 읽어나가십시오.</p>
    <note style="tip"><p>메인 JavaScript 지침서 페이지에는 여기서 다루지 못한 여러가지 입력 위젯을 다룬 <link xref="beginner.js#buttons">상세 예제 코드</link>가 있습니다.</p></note>

  </section>

  <section id="complete">
    <title>완전한 예제 코드</title>

    <links type="section"/>

    <section id="buttonsample">
      <title>단추 코드 예제</title>
      <media type="image" mime="image/png" src="media/03_jssignal_01.png"/>
      <code mime="application/javascript" style="numbered">#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';
const Gtk = imports.gi.Gtk;

// We start out with 0 cookies
var cookies = 0;

class GettingTheSignal {

    // Create the application itself
    constructor() {
        this.application = new Gtk.Application();

        // Connect 'activate' and 'startup' signals to the callback functions
        this.application.connect('activate', this._onActivate.bind(this));
        this.application.connect('startup', this._onStartup.bind(this));
    }

    // Callback function for 'activate' signal presents window when active
    _onActivate() {
        this._window.present();
    }

    // Callback function for 'startup' signal builds the UI
    _onStartup() {
        this._buildUI();
    }

    // Build the application's UI
    _buildUI() {

        // Create the application window
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            default_height: 200,
            default_width: 400,
            title: "Click the button to get a cookie!"});

        // Create the label
        this._cookieLabel = new Gtk.Label ({
            label: "Number of cookies: " + cookies });

        // Create the cookie button
        this._cookieButton = new Gtk.Button ({ label: "Get a cookie" });

        // Connect the cookie button to the function that handles clicking it
        this._cookieButton.connect ('clicked', this._getACookie.bind(this));

        // Create a grid to arrange everything inside
        this._grid = new Gtk.Grid ({
            halign: Gtk.Align.CENTER,
            valign: Gtk.Align.CENTER,
            row_spacing: 20 });

        // Put everything inside the grid
        this._grid.attach (this._cookieButton, 0, 0, 1, 1);
        this._grid.attach (this._cookieLabel, 0, 1, 1, 1);

        // Add the grid to the window
        this._window.add (this._grid);

        // Show the window and all child widgets
        this._window.show_all();

    }

    _getACookie() {

        // Increase the number of cookies by 1 and update the label
        cookies++;
        this._cookieLabel.set_label ("Number of cookies: " + cookies);

    }

};

// Run the application
let app = new GettingTheSignal ();
app.application.run (ARGV);
</code>
    </section>

    <section id="switchsample">
      <title>스위치 코드 예제</title>
      <media type="image" mime="image/png" src="media/03_jssignal_02.png"/>
      <code mime="application/javascript" style="numbered">#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';
const Gtk = imports.gi.Gtk;

// We start out with 0 cookies
var cookies = 0;

class GettingTheSignal {

    // Create the application itself
    constructor() {
        this.application = new Gtk.Application();

        // Connect 'activate' and 'startup' signals to the callback functions
        this.application.connect('activate', this._onActivate.bind(this));
        this.application.connect('startup', this._onStartup.bind(this));
    }

    // Callback function for 'activate' signal presents window when active
    _onActivate() {
        this._window.present();
    }

    // Callback function for 'startup' signal builds the UI
    _onStartup() {
        this._buildUI();
    }

    // Build the application's UI
    _buildUI() {

        // Create the application window
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            default_height: 200,
            default_width: 400,
            title: "Click the button to get a cookie!"});

        // Create the label
        this._cookieLabel = new Gtk.Label ({
            label: "Number of cookies: " + cookies });

        // Create the cookie button
        this._cookieButton = new Gtk.Button ({
            label: "Get a cookie" });

        // Connect the cookie button to the function that handles clicking it
        this._cookieButton.connect ('clicked', this._getACookie.bind(this));

        // Create the switch that controls whether or not you can win
        this._cookieSwitch = new Gtk.Switch ();

        // Create the label to go with the switch
        this._switchLabel = new Gtk.Label ({
            label: "Cookie dispenser" });

        // Create a grid for the switch and its label
        this._switchGrid = new Gtk.Grid ({
            halign: Gtk.Align.CENTER,
            valign: Gtk.Align.CENTER });

        // Put the switch and its label inside that grid
        this._switchGrid.attach (this._switchLabel, 0, 0, 1, 1);
        this._switchGrid.attach (this._cookieSwitch, 1, 0, 1, 1);

        // Create a grid to arrange everything else inside
        this._grid = new Gtk.Grid ({
            halign: Gtk.Align.CENTER,
            valign: Gtk.Align.CENTER,
            row_spacing: 20 });

        // Put everything inside the grid
        this._grid.attach (this._cookieButton, 0, 0, 1, 1);
        this._grid.attach (this._switchGrid, 0, 1, 1, 1);
        this._grid.attach (this._cookieLabel, 0, 2, 1, 1);

        // Add the grid to the window
        this._window.add (this._grid);

        // Show the window and all child widgets
        this._window.show_all();

    }

    _getACookie() {

        // Is the cookie dispenser turned on?
        if (this._cookieSwitch.get_active()) {

            // Increase the number of cookies by 1 and update the label
            cookies++;
            this._cookieLabel.set_label ("Number of cookies: " + cookies);

        }

    }

};

// Run the application
let app = new GettingTheSignal ();
app.application.run (ARGV);
</code>
    </section>

    <section id="radiobuttonsample">
      <title>RadioButton 코드 예제</title>
      <media type="image" mime="image/png" src="media/03_jssignal_03.png"/>
      <code mime="application/javascript" style="numbered">#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';
const Gtk = imports.gi.Gtk;

// We start out with 0 cookies
var cookies = 0;

class GettingTheSignal {

    // Create the application itself
    constructor() {
        this.application = new Gtk.Application();

        // Connect 'activate' and 'startup' signals to the callback functions
        this.application.connect('activate', this._onActivate.bind(this));
        this.application.connect('startup', this._onStartup.bind(this));
    }

    // Callback function for 'activate' signal presents window when active
    _onActivate() {
        this._window.present();
    }

    // Callback function for 'startup' signal builds the UI
    _onStartup() {
        this._buildUI();
    }

    // Build the application's UI
    _buildUI() {

        // Create the application window
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            default_height: 200,
            default_width: 400,
            border_width: 20,
            title: "Choose the one that says 'cookie'!"});

        // Create the radio buttons
        this._cookieRadio = new Gtk.RadioButton ({ label: "Cookie" });
        this._notCookieOne = new Gtk.RadioButton ({ label: "Not cookie",
            group: this._cookieRadio });
        this._notCookieTwo = new Gtk.RadioButton ({ label: "Not cookie",
            group: this._cookieRadio });

        // Arrange the radio buttons in their own grid
        this._radioGrid = new Gtk.Grid ();
        this._radioGrid.attach (this._notCookieOne, 0, 0, 1, 1);
        this._radioGrid.attach (this._cookieRadio, 0, 1, 1, 1);
        this._radioGrid.attach (this._notCookieTwo, 0, 2, 1, 1);

        // Set the button that will be at the top to be active by default
        this._notCookieOne.set_active (true);

        // Create the cookie button
        this._cookieButton = new Gtk.Button ({
            label: "Get a cookie" });

        // Connect the cookie button to the function that handles clicking it
        this._cookieButton.connect ('clicked', this._getACookie.bind(this));

        // Create the label
        this._cookieLabel = new Gtk.Label ({
            label: "Number of cookies: " + cookies });

        // Create a grid to arrange everything inside
        this._grid = new Gtk.Grid ({
            halign: Gtk.Align.CENTER,
            valign: Gtk.Align.CENTER,
            row_spacing: 20 });

        // Put everything inside the grid
        this._grid.attach (this._radioGrid, 0, 0, 1, 1);
        this._grid.attach (this._cookieButton, 0, 1, 1, 1);
        this._grid.attach (this._cookieLabel, 0, 2, 1, 1);

        // Add the grid to the window
        this._window.add (this._grid);

        // Show the window and all child widgets
        this._window.show_all();

    }

    _getACookie() {

        // Did you select "cookie" instead of "not cookie"?
        if (this._cookieRadio.get_active()) {

            // Increase the number of cookies by 1 and update the label
            cookies++;
            this._cookieLabel.set_label ("Number of cookies: " + cookies);

        }

    }

};

// Run the application
let app = new GettingTheSignal ();
app.application.run (ARGV);
</code>
    </section>

    <section id="entrysample">
      <title>Entry 코드 예제</title>
      <media type="image" mime="image/png" src="media/03_jssignal_04.png"/>
      <code mime="application/javascript" style="numbered">#!/usr/bin/gjs

imports.gi.versions.Gtk = '3.0';
const Gtk = imports.gi.Gtk;

// We start out with 0 cookies
var cookies = 0;

class GettingTheSignal {

    // Create the application itself
    constructor() {
        this.application = new Gtk.Application();

        // Connect 'activate' and 'startup' signals to the callback functions
        this.application.connect('activate', this._onActivate.bind(this));
        this.application.connect('startup', this._onStartup.bind(this));
    }

    // Callback function for 'activate' signal presents window when active
    _onActivate() {
        this._window.present();
    }

    // Callback function for 'startup' signal builds the UI
    _onStartup() {
        this._buildUI();
    }

    // Build the application's UI
    _buildUI() {

        // Create the application window
        this._window = new Gtk.ApplicationWindow({
            application: this.application,
            window_position: Gtk.WindowPosition.CENTER,
            default_height: 200,
            default_width: 400,
            border_width: 20,
            title: "Spell 'cookie' to get a cookie!"});

        // Create the text entry field
        this._spellCookie = new Gtk.Entry ();

        // Create the cookie button
        this._cookieButton = new Gtk.Button ({
            label: "Get a cookie" });

        // Connect the cookie button to the function that handles clicking it
        this._cookieButton.connect ('clicked', this._getACookie.bind(this));

        // Create the label
        this._cookieLabel = new Gtk.Label ({
            label: "Number of cookies: " + cookies });

        // Create a grid to arrange everything inside
        this._grid = new Gtk.Grid ({
            halign: Gtk.Align.CENTER,
            valign: Gtk.Align.CENTER,
            row_spacing: 20 });

        // Put everything inside the grid
        this._grid.attach (this._spellCookie, 0, 0, 1, 1);
        this._grid.attach (this._cookieButton, 0, 1, 1, 1);
        this._grid.attach (this._cookieLabel, 0, 2, 1, 1);

        // Add the grid to the window
        this._window.add (this._grid);

        // Show the window and all child widgets
        this._window.show_all();

    }

    _getACookie() {

        // Did you spell "cookie" correctly?
        if ((this._spellCookie.get_text()).toLowerCase() == "cookie") {

            // Increase the number of cookies by 1 and update the label
            cookies++;
            this._cookieLabel.set_label ("Number of cookies: " + cookies);

        }

    }

};

// Run the application
let app = new GettingTheSignal ();
app.application.run (ARGV);
</code>
    </section>

  </section>

</page>
