Susanna Huhtanen
ihmis.suski@gmail.com 2012
조성호
shcho@gnome.org 2017-2019.

# 주 프로그램 파일

        안내서의 이 부분에서는 날씨 프로그램의 주 프로그램 파일을 만들어보겠습니다. 여러분이 모든 코드 예제를 작성하고 실행하려면, 코드를 작성할 편집기, 터미널, 그놈 3 이상을 컴퓨터에 설치해야합니다. 여기서는 다음 내용을 진행합니다:

          실행 프로그램 스크립트
          가져올 라이브러리
          프로그램 메인 창 만들기
          그리드를 추가하고 필요한 위젯 넣기
          날씨 정보 비동기 요청
          단추와 항목에 시그널 연결.
          weatherapp.js

# 실행 프로그램 스크립트

#!/usr/bin/gjs

이 줄은 스크립트 실행 방법을 알려줍니다. 이 부분은 코드의 처음 부분에 들어가야하며, 스크립트 파일을 실행할 수 있어야합니다. 실행 권한을 가져오려면 터미널을 열고 올바른 폴더에서 chmod +x scriptname 명령을 실행하십시오. 또는 그래픽 파일 관리자를 활용할 수 있습니다. 코드가 있는 적절한 폴더에 들어가서 코드를 작성한 파일에 마우스 커서를 두고 오른쪽 단추를 누른 다음, 속성, 권한 탭을 선택하시고 파일을 프로그램처럼 실행하도록 상자에 표시하십시오.

# 가져올 라이브러리

var Gtk = imports.gi.Gtk; const WeatherService = imports.geonames;

프로그램이 동작하려면 GObject 인트로스펙션 라이브러리를 가져와야합니다. UI를 동작하게 할 목적으로 Gtk가 필요합니다. Gtk는 앞부분에서 임포팅해서 코드의 모든 곳에서 쓸 수 있습니다. 또한, 우리가 여기서 사용할 JavaScript geonames 자체 라이브러리를 임포티해야합니다.

# 프로그램 메인 창 만들기

// Initialize the gtk Gtk.init(null, 0); //create your window, name it and connect the x to quit function. Remember that window is a taken word var weatherwindow = new Gtk.Window({type: Gtk.WindowType.TOPLEVEL}); weatherwindow.title = "Today's weather"; //Window only accepts one widget and a title. Further structure with Gtk.boxes of similar weatherwindow.connect("destroy", function(){Gtk.main_quit()});

weatherwindow.show_all(); //and run it Gtk.main();

# 그리드를 추가하고 그리드에 필요한 모든 위젯을 넣으십시오

var grid = new Gtk.Grid(); weatherwindow.add(grid);

//We initialize the icon here, but decide the file later in geonames.js. var weatherIcon = new Gtk.Image();

//Set some labels to your window var label1 = new Gtk.Label({label: ""}); var label2 = new Gtk.Label({label: "Looking in the sky..."}); var label3 = new Gtk.Label({label: ""});

var entry = new Gtk.Entry(); entry.set_width_chars(4); entry.set_max_length(4); var label4 = new Gtk.Label({label: "Enter ICAO station for weather: "}); var button1 = new Gtk.Button({label: "search!"});

grid.attach(label4, 2, 1, 1, 1); grid.attach_next_to(label1,label4,3,1,1); grid.attach_next_to(label2,label1,3,1,1); grid.attach_next_to(label3,label2,3,1,1); grid.attach_next_to(entry,label4,1,1,1); grid.attach_next_to(button1,entry,1,1,1); grid.attach_next_to(weatherIcon,label2,1,1,1)

여기서는 위젯을 적소에 배치할 때 활용할 그리드를 만들겠습니다. 모든 단추, 레이블, 항목을 초기화 하고 그리드에 배치합니다. 각기 다른 위젯의 배치에서 보셨듯이 하나의 위젯에만 관계있는건 아닙니다. 여기서는 일부 레이블에는 어떤 내용도 들어가지 않습니다. 이 위젯의 내용은 나중에 반영합니다. 프로그램을 이 단계에서 실행하면, UI를 준비한 상태이지만, 위젯은 그 어떤 요소와도 연결한 상태가 아닙니다. 여기서 날씨 검색 자체 라이브러리를 우선 만들고, 필요한 정보를 비동기 방식으로 가져와야합니다. 자체 라이브러리를 준비하고 나면 필요한 위젯에 연결할 수 있습니다.

# 비동기 방식으로 날씨 정보 요청

function getWeatherForStation() { var station = entry.get_text();

var GeoNames = new WeatherService.GeoNames(station); //"EFHF";

GeoNames.getWeather(function(error, weather) { //this here works bit like signals. This code will be run when we have weather. if (error) { label2.set_text("Suggested ICAO station does not exist Try EFHF"); return; } weatherIcon.file = GeoNames.getIcon(weather);

label1.set_text("Temperature is " + weather.weatherObservation.temperature + " degrees."); if (weather.weatherObservation.weatherCondition !== "n/a"){ label2.set_text("Looks like there is " + weather.weatherObservation.weatherCondition + " in the sky."); } else { label2.set_text("Looks like there is " + weather.weatherObservation.clouds + " in the sky."); } label3.set_text("Windspeed is " + weather.weatherObservation.windSpeed + " m/s") // ... }); }

이 함수는 날씨 정보를 호출하고 레이블과 아이콘을 즉시 업데이트하는 과정에 관여합니다. 함수 시작 부분을 보면 검색에 필요한 사용자 입력을 가져옵니다. 따라서 여기서는 처음에 자체 라이브러리랄 활용하고 GeoNames 변수에 할당하겠습니다. WeatherService를 할당하는 동안 기상대에 요청을 줍니다. GeoNames에 할 일은 날씨 정보 요청입니다. GeoNames.getWeather(function(error,weather))를 호출하고 난 다음 일은 오류 메시지를 받거나 날씨 정보를 받는 일만 있을 뿐입니다. 두가지 경우가 모두 아닌 경우 프로그앰이 할 일은 그냥 평범하게 있을 때 와 동일하므로 main_Quit를 동작합니다.

# 단추와 항목에 시그널 연결.

entry.connect("key_press_event", function(widget, event) { if (entry.get_text().length === 4) { // Enough is enough getWeatherForStation(); } return false; });

button1.connect("clicked", function(){ getWeatherForStation(); });

그리고 마지막으로 전체 프로그램이 돌아가도록 돌아가도록 연결하겠습니다. 항목과 단추를 동일한 방식으로 연결하여 날씨 정보를 가져오겠습니다. 따라서 엔터키를 누르든 검색 단추를 누르든 상관 없이 동작합니다.

# Weatherapp.js

Weatherapp.js 파일의 내용은 다음과 같습니다:

#!/usr/bin/gjs //The previous line is a hash bang tells how to run the script. // Note that the script has to be executable (run in terminal in the right folder: chmod +x scriptname)

var Gtk = imports.gi.Gtk;

const WeatherService = imports.geonames; //Bring your own library from same folder (as set in GJS_PATH). If using autotools .desktop will take care of this

// Initialize the gtk Gtk.init(null, 0); //create your window, name it and connect the x to quit function. Remember that window is a taken word var weatherwindow = new Gtk.Window({type: Gtk.WindowType.TOPLEVEL}); weatherwindow.title = "Today's weather"; //Window only accepts one widget and a title. Further structure with Gtk.boxes of similar weatherwindow.connect("destroy", function(){Gtk.main_quit()}); //We initialize the icon here, but decide the file later in geonames.js.

var weatherIcon = new Gtk.Image();

//Set some labels to your window var label1 = new Gtk.Label({label: ""}); var label2 = new Gtk.Label({label: "Looking in the sky..."}); var label3 = new Gtk.Label({label: ""});

var grid = new Gtk.Grid(); weatherwindow.add(grid);

var entry = new Gtk.Entry(); entry.set_width_chars(4); entry.set_max_length(4); var label4 = new Gtk.Label({label: "Enter ICAO station for weather: "}); var button1 = new Gtk.Button({label: "search!"});

//some weather

entry.connect("key_press_event", function(widget, event) { // FIXME: Get weather on enter (key 13) if (entry.get_text().length === 4) { // Enough is enough getWeatherForStation(); } return false; });

button1.connect("clicked", function(){ getWeatherForStation(); });

function getWeatherForStation() { var station = entry.get_text();

var GeoNames = new WeatherService.GeoNames(station); //"EFHF";

GeoNames.getWeather(function(error, weather) { //this here works bit like signals. This code will be run when we have weather. if (error) { label2.set_text("Suggested ICAO station does not exist Try EFHF"); return; } weatherIcon.file = GeoNames.getIcon(weather);

label1.set_text("Temperature is " + weather.weatherObservation.temperature + " degrees."); if (weather.weatherObservation.weatherCondition !== "n/a"){ label2.set_text("Looks like there is " + weather.weatherObservation.weatherCondition + " in the sky."); } else { label2.set_text("Looks like there is " + weather.weatherObservation.clouds + " in the sky."); } label3.set_text("Windspeed is " + weather.weatherObservation.windSpeed + " m/s") // ... }); }

grid.attach(label4, 2, 1, 1, 1); grid.attach_next_to(label1,label4,3,1,1); grid.attach_next_to(label2,label1,3,1,1); grid.attach_next_to(label3,label2,3,1,1); grid.attach_next_to(entry,label4,1,1,1); grid.attach_next_to(button1,entry,1,1,1); grid.attach_next_to(weatherIcon,label2,1,1,1) weatherwindow.show_all(); //and run it Gtk.main();

모든 autotool 파일을 준비하기 전까지 실행합니다:

     $  GJS_PATH=`pwd` gjs weatherapp.js

모듈을 개발하는 동안에는 터미널에서 이 명령을 사용하십시오. 프로그램을 이 방식으로 호출할 때, 프로그램에서 개별 JS 라이브러리 위치를 파악합니다. 이 경우는 geonames.js 입니다.