何某日和

「カメラ」のち「ハンダゴテ」ところにより「プログラミング」 ── そんな私“かめきち”のウェブサイト

2012.11.14:地球をクリック

概要

 先月に始まったGUIシリーズも第6弾「地球をクリック」を迎えました。 前回の「リファクタリング」はそれまでの様相を異にした内容でしたが、今回はまた以前のようにGUI部品への導きを行います。 特研座学や、計6回のペアプログラミングで学んできたことを思い出しながら、これからの題材に取り組んでいただけると非常に嬉しいです。大切なのは「連想」する力を養うこと。

 また、今日は座標計算が多く現れます。プログラムの端々に記されている数値から、実際に生み出される空間を「想像」してください。 想像することに先立つDo itを御法度としますので、くれぐれもご協力を。 ちなみにテキストはこちら(http://www.cc.kyoto-su.ac.jp/~atsushi/Programs/ClickEarth/index-j.html

準備

マシンメンテナンス

 今日も今日とて。(日々のマシンメンテナンス

今日の目標

 今日は、2次元と3次元の地球を表示するアプリケーションを拵えます。

完成したアプリケーション(メルカトル図法) 完成したアプリケーション(立体の地球)

左(メルカトル図法)の地図のどこかをクリックして選択すると、右(立体)の地球はその選択位置を中心にして再表示します。

準備プログラムの実行

 以下のプログラムを実行して、準備を整えましょう。

| aCollection |
(aCollection := OrderedCollection new)
    add: #url: -> 'http://www.cc.kyoto-su.ac.jp/~atsushi/Programs/ClickEarth/ClickEarth.st';
    add: #comment: -> 'Copyright 2008-2011 KSU (Kyoto Sangyo University). All Right Reserved.';
    add: #bundle: -> #KSU;
    add: #package: -> 'KSU-Template';
    add: #nameSpace: -> #KSU;
    add: #category: -> 'KSU-Template';
    add: #class: -> #{KSU.ClickEarth};
    add: #protocol: -> #examples;
    add: #selector: -> #example1;
    add: #execute: -> [#{KSU.ClickEarth} value example1];
    yourself.
JunSystem
    perform: ((aCollection collect: [:each | each key]) inject: String new
            into: [:selector :key | selector , key]) asSymbol
    withArguments: (aCollection collect: [:each | each value]) asArray
準備完了

今回のGUI部品:Click Widget, Label, Input Field

  • GUI部品の設置(クリックウィジェット、ラベル、フィールド)
  • 設定の確認
  • ちゃんと動きますか?

GUI部品の設置(クリックウィジェット、ラベル、フィールド)

 次の画像を参考にGUI部品を貼り付けてゆきましょう。

Palette Window

これまで、各部品の設定は掲載画像に従って入力していたと思いますが、今回はプログラム(完成したwindowSpecメソッド)を参考に入力してみましょう。 「まだ習っていない」とは言わずに、類推・連想の力を援用して入力しましょう。もちろん、出来る範囲で構いません。

(ちなみに、ラベル及びフィールドの位置・背景色は、多少のズレがあっても問題ありません。)

windowSpec
    "Tools.UIPainter new openOnClass: self andSelector: #windowSpec"

    <resource: #canvas>
    ^#(#{UI.FullSpec} 
        #window: 
        #(#{UI.WindowSpec} 
            #label: '地球をクリック' 
            #min: #(#{Core.Point} 512 320 ) 
            #max: #(#{Core.Point} 512 320 ) 
            #bounds: #(#{Graphics.Rectangle} 494 285 1006 605 ) 
            #flags: 4 
            #menu: #menuBar ) 
        #component: 
        #(#{UI.SpecCollection} 
            #collection: #(
                #(#{UI.MappedClickWidgetSpec} 
                    #layout: #(#{Graphics.Rectangle} 0 0 512 256 ) 
                    #name: #imageOfEarth 
                    #visualSelector: #imageOfEarth 
                    #defaultClickSelector: 
                    #clicked: ) 
                #(#{UI.LabelSpec} 
                    #layout: #(#{Core.Point} 72 264 ) 
                    #name: #longitude 
                    #label: '経度:' ) 
                #(#{UI.LabelSpec} 
                    #layout: #(#{Core.Point} 288 264 ) 
                    #name: #latitude 
                    #label: '緯度:' ) 
                #(#{UI.InputFieldSpec} 
                    #layout: #(#{Graphics.Rectangle} 120 264 220 286 ) 
                    #name: #longitudeField 
                    #colors: 
                    #(#{UI.LookPreferences} 
                        #setBackgroundColor: #(#{Graphics.ColorValue} 6143 8191 7167 ) ) 
                    #model: #longitudeField ) 
                #(#{UI.InputFieldSpec} 
                    #layout: #(#{Graphics.Rectangle} 336 264 436 286 ) 
                    #name: #latitudeField 
                    #colors: 
                    #(#{UI.LookPreferences} 
                        #setBackgroundColor: #(#{Graphics.ColorValue} 8191 7167 6143 ) ) 
                    #model: #latitudeField ) ) ) )

設定の確認

 もし不安な箇所があれば、以下の画像で確認してみてください。

MainWindow imageOfEarth Basics imageOfEarth Position longitude latitude longitudeField Basics longitudeField Color latitudeField Basics latitudeField Color

ちゃんと動きますか?

Do it 完成したウィンドウ

 左のウィンドウでクリックした地点が、右のウィンドウにも反映されることを確認しましょう。

コードリーディング

 今日はコードリーディングを主体として進めますが、今日はいつもに増してスパルタ指導で...。 ☆や★の付いている全てのメッセージを自分自身で説明してみてください。1行1行を説明する必要はありません。 そのメッセージ全体の処理の流れを(初心者にもわかるように)日本語で分かりやすく説明していただければ充分です。 (1行1行を細かく説明してしまうと、全体構造の中の自分の位置を見失い、コードに溺れてしまいますので。) (☆:比較的簡単 ★:比較的難解)

  • ☆imageOfEarth, ★pictureOfEarth
  • ☆postOpenWith:, ☆noticeOfWindowClose:
  • ☆longitudeField, ☆latitudeField
  • ★bodyOfEarth, ☆viewfinderOfEarth
  • ★viewEarth
  • ★clicked:
  • ☆updateLongitudeField:, ☆updateLatitudeField
  • ★updateViewfinderOfEarth:
インスタンスメソッド一覧 クラスメソッド位置

☆imageOfEarth, ★pictureOfEarth

 ペインタでGUI部品を配置する時、いつもそれぞれの部品に対してIDを付していたはずですが、その理由をようやく知ることができたと思います。 IDのシンボルとcomponentAt:メッセージがあれば、目的のオブジェクトを簡単に探しだすことができるのです。 pictureOfEarthでは、深いネスト構造に抵抗を覚えるかもしれませんが、GUIの部品を包み込む風呂敷(ラッパー/包み紙)を展開するだけですから難しいことはありません。 この際、新出語彙は覚えてしまいましょう。

☆postOpenWith:, ☆noticeOfWindowClose:

 postOpenWith:はご存知のとおりです。では、noticeOfWindowClose:とは何でしょうか。postOpenWith:と同じ節で紹介していることからも類推できるかもしれませんね。

☆longitudeField, ☆latitudeField

 すでに幾度も見てきた構造です。さらっと説明しましょう。

★bodyOfEarth, ☆viewfinderOfEarth

 きっと不明瞭な点が散在すると思います。そうした疑問を解決する方法として、少々荒っぽいですが「self halt」を用いてみると良いでしょう。 プログラムの実行時点で変数に束縛されているオブジェクトが何かを調べることができますし、その他にも様々なことができます。 (ただし、プログラムによっては「self halt」の挿入が危険な行為にあたる場合があります。実は今回もその類なのですが...。)

self haltで強制的にデバッグ

★viewEarth

 ウィンドウの表示に関する様々な配慮が窺える部分です。あらゆる状況に対処しているという構造を認識できるでしょうか。

★clicked:

 見慣れないイディオムがあると思いますが、それさえ掴めば難しい構造ではありません。特に、3つ目(accuracy)は押さえておきたいところ。

JunCursors crossCursor showWhile: [3 seconds wait]
13 \\ 5
JunGeometry accuracy

☆updateLongitudeField:, ☆updateLatitudeField

 ゴチャゴチャと書いてありますが、その内容は単純なものばかりですから気負けせず。

★updateViewfinderOfEarth:

 このメソッドは読み応えがあります。それも「プログラム的に」というより「数学的に」です。 3次元グラフィクスにおける基本操作が集っているので、しっかりと理解しておきましょう。

さいごに

 さて、今日のペアプログラミングでは、脳裏にどのようなことを浮かべましたか?

  • インプットフィールドの後ろには賢いオブジェクトが居て...(
  • 2つのウィンドウ(View)が連携している。モデルは...(
  • 2つのウィンドウは同じ地球を表現している。形は違うように見えるけど...(
  • これに類似したアプリケーションは何であろうか。どのような抽象化が施せるだろうか...(

これまでと同様の「GUIアプリケーションの開発」でしたが、そこに様々な別世界を(連想によって)同時に垣間見ることができたとすれば、今日のペアプログラミングは成功です。

「読み」を抜いて「書く」こともなし

 かなり多くの部分を自分自身の言葉で説明していただきましたが、いかがでしょう、類推力や連想力がどれほど必要とされているかを体感することができたでしょうか。 きっと、未知の比喩(知らなかった言葉やアルゴリズム)と幾つも遭遇しましたね。そしてそれは「プログラムの読みの少なさ」の現れに他なりません。

 人間が持する語彙の限界は、その人間の思考の限界であるとも言われます[1]。 是非、自身の知らない言葉と多く対峙し、類推・連想を用いて我が物にしてください。 きっとプログラムを読むことが楽に、また書くことも楽になります。 全てのソースコードを読むことができるSmalltalkは、必ずやその助力となりましょう。ふたつとないこの珠玉をどうか手の内に。

さいごに:プログラムの保存

 データを保存しておきましょう。


[1] 「私の言語の限界は、私の世界の限界を意味する。」(ウィトゲンシュタイン)

[2] 『プログラマは「書く」より「読む」』 青木 淳 - BCN Bizline