シェアウェア、やって良い事、悪い事

11/19のCocoa勉強会で発表予定の資料。

十年以上前の以下の記事を元に現在のアプリビジネスとプログラム開発を話します。

上記の勝手翻訳資料は会場にてお渡しします。

ProxyResponder nibファイルを超えたTarget/action

11/14のCocoa勉強会で発表予定だった資料。 nibの外にあるObjectにactionを送り込む手法の説明。

代理オブジェクトをnib上に作成して、メソッドforwardInvocation:を利用して外部のobjectへメソッドを転送しています。

資料はここ。( ProxyResponder.zip )

NSTableViewのUIを改良する、その2

一歩後退して、NSTextField周りを調べたのでメモる。

NSTextFieldの描画領域のマージン

NSTextFieldの描画領域boundsと[NSAttributedString boundingRectWithSize:options:context]が返す描画領域は一致しない。 NSAttributedStringの描画領域と一致するのは、[NSCell drawingRectForBounds:]の値の方。

[NSCell drawingRectForBounds:]は、NSControl中のNSCellの描画領域を計算するメソッド。

おそらく、ControlとCellの差は、フォーカスリング分の差と思われる。

テキストの分量に応じて、NSTextFieldの描画サイズを可変にするときに、上記のControlとCellの差を考慮に入れて計算する必要がある。

詳しくはソースコードの[NSTextField interSpacing]と[NSTextField calcBoundingHeightWithFixedCurrentWidth]を参照すること。

NSTextField間の移動をカーソルキーで行う

[NSTextFieldDelegate control:textView: doCommandBySelector:]に記述するのは基本。

左右の矢印キーを押すと、”moveRight:”や”moveLeft:”のセレクタが来る。

この時に、キャレットが文末や文頭にあった場合にnextKeyViewやpreviousKeyViewにフォーカスを移動する。 これだけだと、フォーカスが移動しツァキのNSTextFieldのテキストが、全て選択されてしまう。

以下のように、currentEditorにmoveToEndOfDocument:を投げることで移動先のキャレットを移動すると良い。

NSTextField* theTextFiled = (NSTextField*)control.previousKeyView;

[theTextFiled becomeFirstResponder];
[theTextFiled.currentEditor moveToEndOfDocument:nil];

キャレット位置の判定や移動方法はソースコードを参照のこと。

現状のソースコードの欠点は、キャレットの縦方向移動開始時にX軸の値を保存していないため、NSTextField間の移動時後にキャレットのX軸がズレることがある。

ソースコードはここ。( TextClassTester.zip )

ライフゲーム その3

最小限のセル編集機能つきのライフゲームの作成。

方針は、以下の2つ。

  • 今までと同じモデルクラスを使う
  • 表示編集はフレームワーク既存のクラスを組み合わせてでっち上げる。

GUIの見た目はこんな感じになります。

../../../_images/lifeGameGUI.png

GUIパーツの配置と接続

XIBファイルの追加はこんな感じで画面を作ります。

../../../_images/lifeGameIB.png

中央のNSSCrollViewの中身は、NSButtonCellを含んだNSMatrixです。

Nibのoutletの接続は、以下のようになります。

../../../_images/lifeGameObj_outlet.png

Nibのactionの接続は以下のようになります。

../../../_images/lifeGameObj_action.png

ViewControllerだけの図にした方がわかりやすかったかもしれませんが、面倒なので修正はしません。

ViewControllerでモデルクラスと対話させる

各種ボタンが呼び出している、機能は単純にモデルクラスの機能を呼び出しているだけです。

runメソッドを呼び出すと行われる、自動で次の世代へ行くのはNSTimerを使っています。

分かりにくい物は、NSMatrix周りのメソッドです。

nibの読み込み時に、NSMatrix中のCellのprototypeをNSOnOffButtonに変更しています。 これは、見た目はラジオボタンだけと、昨日はOnOffボタンに変更するためです。

- (void)viewDidLoad
{
   [super viewDidLoad];

   NSButtonCell* theCell = self.matrix.prototype;
   [theCell setButtonType:NSOnOffButton];

NSMatrixがクリックされると以下のメソッドが呼ばれます。 マトリクス中のどのNSButtonCellがクリックされたか区別できなかったので(詳しく調べればわかるはず)強引にNSMatrixの値をモデルの値に同期させています。

- (IBAction) toggleCell:(id)sender;

これ以外のメソッドは単純で解説の必要はないと思われます。

ソースコードはここ。( LifeGameOnMac_02.zip )

こんな感じでだいたい終わり。