2008-02-19
目次
りんご味Ruby 第19回 藤本 尚邦
前々回から、Xcode ToolsのサンプルアプリケーションSketchに、RubyCocoaフレームワークをリンクして、Rubyプログラムで機能を追加していく様子を示しています。前回は、角丸四角形(rounded corner rectangle)を表すSKTRoundedRectangleクラスをRubyプログラムとして定義しました。今回は、角丸四角形がツールとして使えるようにするための変更に着手します。
■ ツールパレットに角丸四角形ボタンを追加する
Sketchアプリケーションのツールパレットには5つのボタン(選択ツール、四角形、楕円形、線分、テキスト)があります。ここに6つめのボタンとして角丸四角形ボタンを追加します。SketchプロジェクトのToolPallete.nibファイルをInterface Builder 3で開き、以下のような手順で角丸四角形ボタンを追加してください。
(1) Panelを開いてPanelウィンドウの高さをボタン1つ分引き伸します
(ToolsメニューにあるSize Inspectorで変更することもできます)
(2) Panel内のMatrix(NSMatrix)を選択して、Attributes Inspectorで、
MatrixのCellsを5から6に変更します(ボタンが1つ増加)
(3) 新しいボタンを選択、Attributes Inspectorを表示します
(4) ModeをPush On Push Offに変更します
(5) Tagを5にします
(6) Imageを設定します(もし角丸四角形アイコンをお持ちなら)
できたら保存してXcodeに戻ってください。
■ プログラムの変更すべき箇所を探す
次に、SKTRoundedRectangleを使えるようにソースコードを変更しましょう。といっても、どこから手を付けたらいいのかわかりません。何か手がかりが必要ですね。手がかりは、SKTRectangleやSKTCircleなど既存のグラフィックオブジェクトです。これらについてプログラム中で何かしらやっているところを見つけて、SKTRoundedRectangleについても同じことをするように変更すればよいのではないでしょうか。
Xcodeの編集メニューの中の検索のサブメニューに「プロジェクトの検索」というコマンドがあるので、これを使って、とりあえずSKTRectangleが出てくるところを探してみます。すると、以下の6つのソースコードからSKTRectangleが見つかりました。そのうち、SKTRectangle.mとSKTRectangle.h の2つは見つかって当然で変更する必要はありません。残りの4つのソース(以下)は何かしら変更する必要がありそうです。
・SKTToolPaletteController.m
・SKTDocument.m
・Sketch.scriptSuite
・Sketch.scriptTerminology
■ SKTToolPaletteController.m を変更する
SKTToolPaletteController.mから見ていきます。ファイル名から、ツールパレットのボタンが押されたときには、この中のコードが呼ばれることが想像できます。まず
#import "SKTRectangle.h"
という行が見つかっています。しかし、Rubyで書いたSKTRoundedRectangleクラスにはヘッダーファイルはないのでこの行は無視します。次に
theClass = [SKTRectangle class];
という行が、currentGraphicClass というインスタンスメソッドの定義の中にありました。このメソッドは、パレット上で選択されているグラフィックオブジェクトのクラスを返すメソッドのようです。
- (Class)currentGraphicClass {
NSInteger row = [toolButtons selectedRow];
Class theClass = nil;
if (row == SKTRectToolRow) {
theClass = [SKTRectangle class];
} else if (row == SKTCircleToolRow) {
theClass = [SKTCircle class];
} else if (row == SKTLineToolRow) {
theClass = [SKTLine class];
} else if (row == SKTTextToolRow) {
theClass = [SKTText class];
}
return theClass;
}
どうやら、パレット上で選択されているグラフィックオブジェクトツールを表すrowの値によって返すクラスを決めているようです。ということは、ここに角丸四角形用の分岐を書き加えればよいでしょう。SKTTextの条件分岐のあとに
} else if (row == SKTRoundedRectToolRow) {
theClass = [SKTRoundedRectangle class];
を書き加えましょう...としたいところなのですが、実はこれはちょっと問題があり
} else if (row == SKTRoundedRectToolRow) {
theClass = NSClassFromString(@"SKTRoundedRectangle");
とする必要があります。前者の場合、Sketchのビルド時(静的リンク時)にSKTRoundedRectangleという名前が解決される必要があります。しかし、SKTRoundedRectangleクラスはRubyプログラムで記述されており、Sketchアプリケーションを実行してRubyプログラムがロードされるまでは存在しません。したがって、ビルド時にリンクエラーが発生してしまうはずです。
そこで、アプリケーション実行時に指定された名前を持つクラスを返すFoundationフレームワークの関数NSClassFromStringを使います。アプリケーション実行時にNSClassFromStringが呼ばれた時点では、Rubyで書かれたSKTRoundedRectangleがすでにロードされていて、SKTRoundedRectangleクラスが存在するので、後者のコードはうまく動くはずです。
このあたりは、RubyやObjective-Cの動的な性質がにじみ出ているところなのですが、C++派の方などは少しむずがゆさを感じたりするかもしれません。「まあそんなもんなんだな」と適当に読み流してください。
そういえば、SKTRoundedRectToolRowはまだ定義していませんでした。SKTRectToolRowが定義されている箇所を探して、そこにSKTRoundedRectToolRowの定義を書き加えます。SKTRectToolRowが定義されている箇所は、Xcodeのソースコード上の”SKTRectToolRow”を選択してコンテキストメニューで「定義へジャンプ」コマンドで見つけることができます。他のグラフィックオブジェクトクラスと一緒にenumで定義されているので、SKTTextToolRowの下にSKTRoundedRectToolRow を書き加えてください。これはさきほどInterface Builderで設定したタグの値と同じにする必要があるので順番に注意してください。
以上で、SKTToolPaletteController.mの必要な箇所の変更は完了しました。次回は続けて、SKTToolPaletteController.mの変更をすることにしましょう。
藤本裕之のプログラミング夜話 #132
前回はどこまで書いたんだっけ? 昔はマシンもソフトウエアも今よりずっと高くて、市場もすっげぇ小さかったのに、買ってみたいソフトウエアが山ほどあった、当時一種類しかなかったMac雑誌の後ろの方に印刷された、ソフトの名前(しかもたまにミススペルしてた)と売値だけの広告を眺めながら、これはいったい何をするソフトなんだろうか、こっちのこれを買ったらいったいどんなことが出来るんだろうかと想像を巡らすだけで楽しく時間が過ぎて行ったもんなんである。あれはいったいなんだったんだろうか(笑)。
月満ち星は流れ昭和は平成になり、金髪のネーチャンにでっかいわぁ♪と驚かれた「イシマルデンキのアキハバラ」は、いつの間にかよう分らん「世界のアキバ」に変貌し、先日そのアキバで逢った大学生は「高校生のとき最初に買ってもらったパソコンはハードディスクが10ギガくらいしかなくて」とか言うし、あ、いやそんなことはどうでもいいんだが、Macと言わずPCと言わず、コクミンの少なくとも半数はパソコンを使える環境にあり、テレビコマーシャルの終わりに「詳しくはWebで!」と言われて誰も文句を言わなくなった状況で、我々はあのころほどコンピュータにわくわくしてるか、と言うと……なんかしてないような気がするのである。
いや「してないような気がするのである」ってな自信なさげなことではいかんのだけど、前述した「生まれて初めてのコンピュータのハードディスクが10ギガ青年」……長いな、以下「10ギガ青年」と略します、などと話していると、そもそも彼らはコンピュータというものを当時我々が思ってたみたいな「モノ」と思ってないみたいに感じるんだよね。「コンピュータですか? やっぱり高校生くらいになったら必要だろって感じで買ってもらったってゆーか」とか「何をするかって、主にネットですよね。あ、メールはケータイの方が多いです。あとは……自分はその写真とかの趣味もないんで」てな具合。
そう言われて気がつくと、普及した普及したというけれど、結局パーソナル・コンピュータって「コンピュータ」として普及したのではなくて、「インターネット端末」として普及したみたいなもんなのだ。適当な喩えぢゃないかも知れぬが、お燗だ牛乳だ解凍だ、ついでにオーブンにもなってケーキも焼けます、マニュアルの他にレシピブックも付いていますてな電子レンジを、実はほとんどのヒトがコンビニ弁当温めるためにしか使ってませんという状態で、しかも2ちゃんよろしく「それが何か?」とか言われちゃうのである。
前回(前々回だっけ?)、パソコンの出荷台数の伸びに比べてソフトの売れ行きが伸びないと書いたが、つまりそれは電子レンジの普及に比べ、それを使って手料理をするヒトの数は増えていないという、聞きようによってはとっても当たり前のことだったのかも知れない。
これまた前回(これは間違いなく前回だ、覚えてる)書いたことだが、オレが MacPlus と一緒に MacWriteを買ったのは当時の飲み仲間の会報をキレイに印刷したかったからだし、MacPascal は Macで動くプログラムを作りたかったからだ(買ってみて分ったがこれはインタプリタでスタンドアロンのそふとは作れなかった)。FullPaint は当然、絵(つってもモノクロのドット絵だけどさぁ)を描きたかったからだし、Super Studio Session も適当に音符を並べるとそれが演奏されるのがとっても嬉しかったからである。
こう並べてみると、我ながらなかなか創造的、クリエイティブやないの(でもオレ、真面目な顔で「ボクはクリエイティブな仕事がしたいんです」とかいうヤツ信用しないんだけどさ)。つまるところコンピュータは電子レンジみたいに誰でも買うが、その使い道、使い方によってその後ソフトを買う人間と買わないヒトがいるのであり(この「人間」と「ヒト」の使い方はわざとです)、前者は言うほど増えてないのだ、ということになるんだろうか。……確かにそれもあるだろうけど、それだけで納得できるかと問われたら、まだなんかありそうな気がするよねぇ。
(以下次回 2008_02_16)
高橋真人の「プログラミング指南」第130回
〜XcodeによるPowerPlant X入門(19)〜
こんにちは、高橋真人です。
さて、連載2回分の間が開いてしまったためPPxの話がどこまで行ったか忘れてしまった方もおいでかもしれませんが、前回までにやったのは以下のようなことです。
PPx::BaseViewは、サブクラス作ってViewに関連するCarbonイベントのハンドラを加えると、様々な挙動を加えることができます。その手始めとして、“単なる黒い四角”が表示されるだけのViewを実装するプログラムを作りました。
いよいよここからさらなる拡張をして、PPx::Viewの秘める可能性を見ていくわけですが、今の単純な段階で仕組みをしっかりと理解しておくと、今後の拡張も抵抗なく理解できます。今の段階で理解が怪しい方は、しっかりと復習しておくことをお勧めします。
さて、それではいよいよ拡張の作業に入ります。手始めにViewにボタンの機能を持たせてみたいと思います。
ところでボタンといった場合、どのような挙動をするものであるか分かりますか? 以下にざっとボタンの特徴を列挙してみます。
・マウスダウンに反応する
・ドラッグをトラッキングする
・クリックに反応する
・(ウインドウのアクティベーションに反応する)
今さらですが、「クリック」というのは、マウスボタンを押すことではなく、「押して、すぐに放す」ことです。最近では「マウスボタンを押す」と「クリックする」が同じ意味で使われることも多いのですが、プログラムを書く人はきちんと違いを意識しておきましょう。
それと、トラッキングも重要です。初心者ユーザーですと、意識していない人もいるかもしれませんが、ボタンが機能するのは、マウスボタンを放した時です。ボタンのエリア内でマウスボタンを押しても、指でマウスボタンを押さえたまま、マウスポインタをボタンのエリア外に出してからマウスボタンを放せば、キャンセルすることになります。
きちんと認識しているユーザーには常識ですので、ちゃんとこのように動作しないと、「とんでもないボタン」が出来上がってしまいますので注意しましょう。
では、これらの挙動を実現するために早速プログラムを作成してみます。
前回のPPxForXcode05を複製して、PPxForXcode06というプロジェクトを作り、例のごとく各所の05を06に変更しておいてください。
それではソースコードです。新しいファイルはありません。変更個所だけを掲出します。それ以外は変更ありません。
=============MyView.h =============
・クラス定義の部分を以下のように書き替えます。
class MyView : public PPx::BaseView,
public PPx::ControlDrawDoer,
public PPx::ControlHitDoer,
public PPx::ControlHitTestDoer,
public PPx::ControlHiliteChangedDoer
{
public:
void Initialize(
// 変更ないので省略
bool inEnabled);
protected:
virtual OSStatus DoControlDraw(
// 変更ないので省略
CGContextRef inContext);
virtual OSStatus DoControlHit(
PPx::SysCarbonEvent& ioEvent,
ControlRef inControl,
ControlPartCode outPartCode,
UInt32 inKeyModifiers);
virtual OSStatus DoControlHitTest(
PPx::SysCarbonEvent& ioEvent,
ControlRef inControl,
const HIPoint& inHitPoint,
ControlPartCode& outPartCode);
virtual OSStatus DoControlHiliteChanged(
PPx::SysCarbonEvent& ioEvent,
ControlRef inControl);
private:
virtual void FinishInit();
};
=============MyView.cp=============
・FinishInit()の末尾に、以下を追加。
PPx::ControlHitDoer::Install(targetRef);
PPx::ControlHitTestDoer::Install(targetRef);
PPx::ControlHiliteChangedDoer::Install(targetRef);
・DoControlDraw()を以下にさしかえ
OSStatus
MyView::DoControlDraw(
PPx::SysCarbonEvent& ioEvent,
ControlRef inControl,
ControlPartCode inPartCode,
RgnHandle inClipRgn,
CGContextRef inContext)
{
#pragma unused (ioEvent, inControl, inPartCode, inClipRgn)
HIRect frame;
GetLocalFrame(frame);
float alpha = 0.4;
if (::IsControlHilited(inControl) and ::IsControlActive(inControl)) {
alpha = 0.8;
}
::CGContextSetRGBFillColor(inContext, 0.3, 0.6, 1.0, alpha);
::CGContextFillRect(inContext, frame);
return noErr;
}
・上記に続いて、以下を追加
OSStatus
MyView::DoControlHit(
PPx::SysCarbonEvent& ioEvent,
ControlRef inControl,
ControlPartCode outPartCode,
UInt32 inKeyModifiers)
{
#pragma unused (ioEvent, inControl, outPartCode, inKeyModifiers)
SInt16 itemHit;
::StandardAlert(kAlertPlainAlert, "\pClicked", "\p", nil, &itemHit);
return noErr;
}
OSStatus
MyView::DoControlHitTest(
PPx::SysCarbonEvent& ioEvent,
ControlRef inControl,
const HIPoint& inHitPoint,
ControlPartCode& outPartCode)
{
#pragma unused (ioEvent, inControl)
OSStatus status = eventNotHandledErr;
HIRect frame;
GetLocalFrame(frame);
if (::CGRectContainsPoint(frame, inHitPoint)) {
outPartCode = kControlButtonPart;
status = noErr;
}
return status;
}
OSStatus
MyView::DoControlHiliteChanged(
PPx::SysCarbonEvent& ioEvent,
ControlRef inControl)
{
#pragma unused (ioEvent, inControl)
SetNeedsDisplay(true);
return noErr;
}
============= MyApplication.cp =============
・DoSpecificCommand()を以下にさしかえ
OSStatus
MyApplication::DoSpecificCommand(
PPx::CommandIDType
解説は、次回に。
開発ツールよもやま話 Cocoa Tutorial日本語版 高橋 政明
MOSAicのお知らせにも載っていましたのでご覧になった方も多いと思いますが、待望の「Cocoaアプリケーションチュートリアル」の日本語訳が公開されました。
http://developer.apple.com/jp/documentation/Cocoa/Conceptual/ObjCTutorial/01Introduction/chapter_1_section_1.html
残念ながらwebページの後半(『識別子、バージョン番号、著作権情報を指定する』以降)はリンク切れの状態です。でもPDFではすべて読む事ができます。またここで解説しているプロジェクトファイルもダウンロードできるので完成状態を確認できます。もちろんチュートリアルなのですから、実際に読みすすめながら自分自身で作ってみる事をおすすめします。
現代の若者なら「チュートリアル」と言えばすぐに通じるのかも知れませんが、私の若い頃〔^_^;〕はこの「チュートリアル」なる言葉に馴染みがありませんでした。
初代Macが登場した1984年の暮れに「MacTutor」なる雑誌がUSで登場しました。表紙も含め全ページがイメージライタの出力をそのまま使っているとすぐにわかる本でした。貴重でディープな開発情報が載っていましたが、この『Tutor』はチュートリアルを教える人の事だそうです。
一般にチュートリアルは予備知識が最小限の読者を想定していて、概要を説明し、初歩の使い方をていねいに指導していてそれを順にこなして行けば一通り体験できる構成の物が多いです。そのためページ数もそれほど多くないイメージを持っていたのですが、この「Cocoaアプリケーションチュートリアル」は82ページもあります。(英語版でも80ページ)
このチュートリアルには「学習の目的」が明示されています。
◆Cocoa とは何か
◆オブジェクト指向環境においてアプリケーション開発プロセスがどのように見えるか
◆Cocoaアプリケーションの作成方法
◆知識の適応により、ここから進むべき方向
普通のチュートリアルであれば「Cocoaアプリケーションの作成方法」だけを(あるいは重点に)説明するところ、予備知識もふんだんに盛り込んでいるためにページ数が増えているのです。
開発ツールよもやま話でご紹介するのは、新しいXcodeとInterface Builderの使い方が具体的に説明されているからですが、Cocoaの本質、モデルの定義、ビューの定義:ユーザインターフェイスの作成、モデルとビューのブリッジ:コントローラ、アプリケーションの設定、基本事項の詳細などの章がそろっています。他のプラットフォームでプログラムの経験を持つ方が新しくMacで開発をはじめる場合に役立つ内容もたくさん書かれています。
逆にこれからプログラムをはじめようとする方には詳し過ぎるかも知れません、多少わからない技術用語などがあっても最後まで読み進んでください。(そして質問はMOSA de BBの掲示板をご活用ください)
チュートリアルは予備知識のない状態で読むわけですから、書いてある内容と実際が一致しないと読者はとても混乱してしまいます。その点レパードで大きくツールのメニューや画面が変わったため、新しいツールに対応したチュートリアルが必要でした。このチュートリアルではさらにObjective-C 2.0の新機能も追加されています。
◆本日のまとめ
「Cocoaアプリケーションチュートリアル」は10.5でCocoaで開発をはじめるときに最適のドキュメント。
ニュース解説 MOSAic
★★★ 開発関連のニュースはwebに掲載中 ★★★
http://www.mosa.gr.jp/?page_id=1017
・1月のニュース
http://www.mosa.gr.jp/?p=1515
◇MOSAからのお知らせと編集後記は割愛します◇