読者です 読者をやめる 読者になる 読者になる

うさぎ駆動開発

UWP, Xamarin.Macを中心によしなしごとを書いていきます。

<週刊 自分のごちうサーチを作る> #4 Xcode の世界と C# の世界をつなぐ

前回記事はこちら。

aile.hatenablog.com

今回のお品書き。

  • ビューのカスタムクラスをつくる
  • コントローラにプロパティを生やす
  • ユーティリティメソッドを作る

この記事からいよいよ C#+Cocoa の世界に入っていきます。

NSImageView を継承したビューを作る

画像をドラッグ&ドロップされたときの処理を書くために,継承ビューを作っていきます。NSImageView にはイベントが定義されていないので,継承ビュー内にて自分で定義していく必要があります。

Cocoa の世界では伝統的にDelegate (非delegate in C#)でアクションに対する応答を行っています。たとえばNSTableView という表形式のビューを提供するコントロールでは,NSTableViewDelegate を使って項目のドラッグ&ドロップや項目の追加削除再表示などの処理を注入します。NSImageView には外部から注入できるDelegate が定義されていないため,継承していくことになります。

Xcode を開いている場合はいったんXcode を終了します。Xamarin Studio でMyGochiusearch プロジェクトに Views フォルダを作ります。

f:id:ailen0ada:20160521144453p:plain

作ったViews フォルダを右クリックしてして,New File... を選択します。 f:id:ailen0ada:20160521144600p:plain

General から Empty Class を選択し,適当に名前を付けて作成します。ここではAcceptDropImageViewとしました。 f:id:ailen0ada:20160521150259p:plain

ここでは細かい実装は行わず,ビューのカスタムクラスとしてXcodeで選択できるようにします。このように実装します。

8行目のFoundation.Register 属性で,Cocoa に公開するクラス名を定義しています。自由に指定できますが,ここではnameofを使ってC#側クラス名をそのまま反映しています。

コンストラクタはそれぞれXIBからの構築時(IntPtr),実行中のUI構築時(CGRect)に呼ばれます。ここではXIBを結びつけていませんが,Xcodeからカスタムクラスとして指定するために必要です。

ここまでできたらXcodeに戻りましょう。MainWindow.xib を開いて作業しやすいようにXcodeのメインウィンドウ側で開きなおします。MainWindow内のImageWellを選択します。ImageCellまでポップアップしますが,こちらではありません。 f:id:ailen0ada:20160521151434p:plain

右のインスペクタをIdentity Inspector に切り替え(左から3つめ),カスタムクラスに先ほど作ったクラスを指定します。 f:id:ailen0ada:20160521151533p:plain

これでカスタムクラスを指定することができました。

C#側からコントロールにアクセスできるようにする

AssistantEditor を開きます。Xcode の右上に並んでいるいくつかのボタンのうち,○が二つ重なったようなアイコンです。 f:id:ailen0ada:20160521151915p:plain

MainWindowController.m が開かれると思いますが,今回は使いません。MainWindowController.hに切り替えます。 f:id:ailen0ada:20160521152029p:plain

コントローラの定義をひとつずつここに追加していきます。まずは「自動的にニコニコ動画を開く」チェックボックスを選択し,Ctrl+ドラッグでAssistant Editor に引っ張って,Insert Outlet or Actionとなったところで離します。

f:id:ailen0ada:20160521152401p:plain

ポップアップで名前を付けて,Connect をクリックします。 f:id:ailen0ada:20160521152503p:plainf:id:ailen0ada:20160521152511p:plain

これで接続できました。同様の手順で,検索レベルのポップアップボタン,カスタムクラスを指定したイメージウェルを接続します。 f:id:ailen0ada:20160521152736p:plain

テキストビューは注意して接続する必要があります。このコントロールは以下のような構成になっているからです。 f:id:ailen0ada:20160521152924p:plain

Bordered Scroll View内にTextViewを内包したClipViewがある,という状態です。これでスクロールした部分だけをクリップして表示することでスクロール可能なテキストビューを実現しています。必要なのはTextViewへの接続です。正しいコントロールを接続していれば,ポップアップはこのように出現します。 f:id:ailen0ada:20160521153118p:plain

ついでなので,テキストを編集できないようにしておきます。インスペクタでEditableをオフにします。 f:id:ailen0ada:20160521153215p:plain

ここまでできたら,Xcode を終了します。

AppDelegate.cs

まずはウィンドウを閉じたとき,アプリケーションが終了するようにしましょう。AppDelegate.csを開いて,適当な場所に override appterm と入力します。 f:id:ailen0ada:20160521153606p:plain

ApplicationShouldTerminateAfterLastWindowClosed メソッドtrue を返せば,アプリケーションはウィンドウがひとつもなくなった時点で終了します。ということで return true; などとしておきます。もちろんこう書くことも。

public override bool ApplicationShouldTerminateAfterLastWindowClosed(NSApplication sender) => true;

MainWindowController.cs

MainWindowController.csoverride WindowDidLoad メソッドを作成します。これはウィンドウのロード後,コントロールの初期化を始める直前に呼ばれます。このへんに作成するとわかりやすいです。 f:id:ailen0ada:20160521154121p:plain

ユーティリティメソッドを作る

ここでは今後使うであろう3つのユーティリティメソッドを作っておきます。

  • ウィンドウにメッセージボックスを表示する
  • テキストビューになにか出力する
  • テキストビューの内容をクリアする

MainWindowController クラスのどこかに,下記のように作成します。

ResultView は先ほど接続したテキストビューの名前に適宜置き換えてください。これらが何をするものなのかはまた別途解説します…が,使ってみればなんとなくわかるはずです。さっそくメッセージボックスを表示しましょう。

メッセージを表示してみる

先ほど作成したWindowDidLoad内で,次のように記述します。このメソッド内で何かする場合は,必ずbase.WindowDidLoad()の後に書きます。

デバッグ実行すると,メッセージが表示され,ウィンドウを閉じるとアプリケーションが終了します。 f:id:ailen0ada:20160521154940p:plain

上手にできました。

次回予告

Stay tuned...