3月2008

IKImageBrowserViewの使い方

今日はIKImageBrowserViewの使い方を紹介しようと思います。このIKImageBrowserViewは、Leopardから追加されたImageKitに含まれるViewで、とても簡単にiPhotoのようなリッチなイメージブラウザーのインターフェースを作成することができます。実装方法はNSTableViewのように、デリゲートを使う方法と、Cocoa Bindingを使う方法がありますが、今回はCocoa Bindingを使った方法でIKImageBrowserViewを作成しようと思います。

この記事を読む前に、CocoaセミナーのCocoa Bindlingのビデオを見ておくことをお勧めします。基本的にNSTableViewのバインディングと同じです。

IKImageBrowserView

早速作成しようと思いますが、まず作業工程の確認です。最初にInterface Builderでインターフェースとバインディングの設定を行い、その次にコーディングします。

まずは、新規Cocoa Applicationを作成し、MainMenu.nibを開いてInterface Builderを出しましょう。ライブラリのパネルからImageKitの中にあるIKImageBrowserViewをドラッグしてウインドウの中に配置しましょう。インスペクタのAttributesは、TitledとAnimatesにチェックを入れましょう。あとは、ライブラリのCocoaの中からNSSliderとNSSearchFiledをドラッグして配置しましょう。どちらもAttributesのContinuosにチェックを入れます。

追記:2008/04/02
IKImageBrowserViewにスクロールバーを表示するには、IKImageBrowserViewを配置した後、ビューが選択された状態で、メニューからLayout > Embed Objects In > Scroll Viewを選択します。

Interface Builder ImageKit

続いてバインディングの設定です。余計なところをバインディングしても正しく動かないことがるので、注意して
バインディングしていきましょう。

まず、NSArrayControllerをNibにドラッグして作成します。ドラッグしてできたNSArrayControllerの文字のところをクリックすると、名前を変更できるので、ImageControllerと名付けることにします。AttributesのClassを、あとから作成するImageItemクラスに設定します。

次に、IKImageBrowserViewをImageControllerにバインディングします。IKImageBrowserViewのバインディングの項目にある、ContentのバインディングをImageControllerに設定します。Controller KeyはarrangedObjectsに設定します。また、その下にあるSelection IndexesもImageControllerにバインディングします。Controller KeyはselectionIndexesに設定します。

バインディング

とりあえず、これで基本的な機能は使えるので、Xcodeに戻ってコーディングします。コーディングする前に、ImageKitが含まれるQuartzのフレームワークをプロジェクトに追加しておくことを忘れないようにしましょう。

さっきInterface Buiilder側で指定した、ImageItemクラスを作成します。IKImageBrowserViewに表示するアイテムは、IKImageBrowserItemプロトコルの3つのメソッドを実装する必要があります。今回はオプションのメソッドを1つ実装するので、合計4つのメソッドを実装することになります。

必要なメソッドは以下の3つです。

- (NSString *)imageUID;
- (NSString *)imageRepresentationType;
- (id)imageRepresentation;

上から、イメージの識別子、表示するデータタイプ、表示する内容、を返すように設定します。

ImageItemクラスを新規作成し、ヘッダーを次のように記述してください。

#import <Cocoa/Cocoa.h>
#import <quartz/Quartz.h>

@interface ImageItem : NSObject {
	NSURL *imageURL;
}

+ (ImageItem *)imageItemWithContentsOfURL:(NSURL *)aURL;

- (id)initWithContentsOfURL:(NSURL *)aURL;

@end

インターフェースに記述するのは、イニシャライザだけになります。今回はURLで初期化するように作りました。

続いて実装部です。

@implementation ImageItem

+ (ImageItem *)imageItemWithContentsOfURL:(NSURL *)aURL
{
	return [[[ImageItem alloc] initWithContentsOfURL:aURL] autorelease];
}

- (id)initWithContentsOfURL:(NSURL *)aURL
{
	self = [super init];
	if ( self ) {
		imageURL = [aURL copy];
	}
	return self;
}

- (void)dealloc
{
	[imageURL release];
	[super dealloc];
}

- (NSString *)imageUID
{
	return [imageURL absoluteString];
}

- (NSString *)imageRepresentationType
{
	return IKImageBrowserNSImageRepresentationType;
}

- (id)imageRepresentation
{
	return [[[NSImage alloc] initWithContentsOfURL:imageURL] autorelease];
}

- (NSString *)imageTitle
{
	return [[imageURL absoluteString] lastPathComponent];
}

@end

これでImageItemクラスの作成は終了です。あとは、ImageControllerにAddObjectでImageItemを追加していくだけで、IKImageBrowserViewにイメージを追加できるようになります。

例としては、AppControllerクラスにOpen…のアクションを接続し、次のようなメソッドを実装しましょう。imageControllerはImageControllerへのアウトレット接続です。

#import "AppController.h"
#import "ImageItem.h"

@implementation AppController

- (IBAction)open:(id)sender;
{
	NSOpenPanel *panel = [NSOpenPanel openPanel];
	[panel setAllowsMultipleSelection:YES];
	if ( [panel runModalForTypes:[NSImage imageFileTypes]] == NSOKButton ) {
		for ( id aURL in [panel URLs] ) {
			[self addImage:aURL];
		}
	}
}

- (void)addImage:(NSURL *)aURL
{
	ImageItem *item = [ImageItem imageItemWithContentsOfURL:aURL];
	[imageController addObject:item];
}

@end

とりあえずこんな感じでイメージブラウザーが作成できたかと思います。インターフェースだけ作ったズーム機能と折込検索機能の作り方は次回紹介します。バインディングだけで追加できるので、できそうな人は試してみましょう。

続き: IKImageBrowserViewの使い方 – 2

Web インスペクタ for Windows

前回紹介したSafariのWeb Inspectorですが、Windows版のSafariにも付属していました。興味のある方はぜひ使ってみましょう。

WEB インスペクタ

Windows版のWeb インスペクタの表示方法は、メニューから「編集」>「設定…」を選び、「詳細」のパネルの一番下にある、「メニューバーに[開発]を表示」にチェックを入れ、メニューに表示された「開発」から、Web インスペクタを選択します。

ちなみに、Mac版のSafari 3.1から、Windowsと同じように環境設定からデバッグメニューをオンにすることができるようになったようです。環境設定のパネルの「詳細」から、パネルの一番下にある「メニューバーに”開発”を表示」にチェックを入れることで「開発」のメニューを出すことができ、Web インスペクタを使用することができます。


関係ない個人的な話ですが、一昨日カラオケではしゃぎすぎて、昨日朝から体調崩して病院で点滴打ってきました。体調が戻るまで、あと数日かかりそうです。私が体調悪くするときはいつもそんな感じで、何かに夢中になりすぎて体調に気を配っていない時、というよりは、夢中すぎて悪くなったことに気づいていないって感じな気がするので、今後はテンション上がり過ぎてるときには注意したいですね。

とりあえず、ライブラリ開発の方はSystem.Net.IPAddressクラスから手をつけ始めていて、Dnsクラスあたりまで作ったらコミットしようかなぁーとか考えていますが、なんかIPAddressクラスの出来がいまひとつなのと、やはり配列の仕様を早くどうにかした方がいいですね。やはり人任せにしていては早く進まないですね。私も何か打開策を考えた方がいい気がしてきました。

Safariに付属してる結構高機能なWebInspector

ターミナルでSafariのユーザーデフォルトを設定することでデバッグモードにすることができますが、デバッグのメニューの中にWeb Inspectorという結構使えそうなツールが付属しています。

デバッグモードを有効にするには、ターミナルで下のコマンドを実行し、Safariを再起動します。無効にする場合は、trueの部分をfalseにしてコマンドを実行します。

defaults write com.apple.Safari IncludeDebugMenu -bool true

さまざまなメニューがあるのですが、その中でもWeb Inspectorというのが今日紹介するツールです。

web inspector

見ての通り、ページの構造を詳しく表示してくれます。選択した部分をハイライトしてくれる機能もあり、どのタグがどこを指しているのか一目瞭然です。右側にはそのタグの詳しい属性が載っており、HTMLを書いていて思い通りに表示されないときなど使えそうな機能です。隠れて見えませんが、こういう属性も視覚的に表示してくれます。

matrics

Web Inspectorは、上の小さなボタンで、アウトラインビュー表示かソースそのままの表示にするか切り替えることができます。ソース表示の場合、明らかに間違ったHTMLが書かれているとXcode風に警告を表示してくれます。ちなみに、一番左下のウィンドウの端のボタンで、Web InspectorをSafariに埋め込んで表示するか、独立したウィンドウで開くかを切り替えられるようです。

error

最後に、左下のNetworkに用意されている機能がこれです。

network

ページの各リソースの読み込みが、どれだけの時間がかかっているかを視覚的に表示してくれます。また、下にあるグラフでは各リソースの割合が表されています。

いろいろとクリックすると、さらに詳しい情報が表示されるようです。

detail

WEBサイトを制作する際に覚えておきたい機能ですね。デバッグモードにあるのがもったいないです。

ネットワーク勉強中…

ActiveBasicのライブラリ開発で、ようやくSystem.IOの主要な部分の実装がほぼ終わり、今度はネットワークあたりに手を出そうと考えています。ネットワークのプログラミング経験は、2年前に簡単なチャットプログラムをソケットレベルで作っただけしかないので、昔興味があって買ってしまった下の本でネットワークの勉強をしています。

4274065847 基礎からわかるTCP/IP ネットワーク実験プログラミング―Linux/FreeBSD対応
村山 公保
オーム社 2004-10

by G-Tools

結構詳しいところまで載っていて、充実した一冊です。

iPhone SDKをPPC Macにインストールする方法

追記(2008/4/13);
iPhone SDK beta2, 3の場合は、iPhone SDK beta3をPPCで動かす方法もご覧ください。

iPhone SDKのreadmeには、”NOTE: iPhone SDK will run on Intel-based Macs running Mac OS X v10.5.2 and later. “と書いてありますが、ググってみるとPPC MacでもSDKをインストールする方法が見つかりました。

Don’t Have An Intel Machine But Want To Code For The iPhone Anyway? Follow These Steps

実際iPhone SDKをインストールしてもXcode 3.1だけインストールされて、iPhone SDKはインストールされないのですが、ダウンロードしたiphone_sdk.dmgの中に入っているPackagesフォルダの中の”Aspen..”から始まる名前のインストーラーを個別に実行していけば、iPhone SDKをインストールすることができます。

全部で5つAspen…のインストーラーがありますが、インストールする際の場所の設定は、iPhone SDKをインストールした場所を指定します。デフォルトでは/Developerです。Xcode3.1を別の場所にカスタムインストールした人は、そのフォルダを選択しましょう。

無事にインストールが終了すると、Xcodeの新規プロジェクトのリストにiPhoneが追加されます。PPC Macしか持っていなくてがっかりした人は、ぜひ試してみてください。

iPhone Simulator

ライブラリ開発の計画

最近ライブラリ開発を再開しつつある私ですが、ようやくSystem.IO、主にファイルを操作するクラス群がだいたい完成しそうです。山本さんがいつの間にか実装されたXMLクラス群も、基本的な機能はそろってるはずなので、アプリケーションで使うデータ操作の基本的なものは用意されたと思います。

さて、個人的にAB5リリース前に最低限欲しいと思っているライブラリは、ウィンドウ周りのFormsでしょうか、あとは、できればネットワーク関連のライブラリも用意したいところではあります。

ということで、今実装中のFile,FileInfoクラスが終わったら、イグトランスさんが進めているFormsの方の様子見つつ、ネットワーク関連について少し探りを入れていこうと思います。基本的なデータ構造、ファイル操作、GUI、ネットワーク、これくらい揃えば、それなりのアプリケーションを作れるようになるのではないかと思っています。

Core Data:サンプルがアプリケーションになる程度の能力

Core Dataに慣れるためにサンプルアプリケーションを作っていた訳ですが、Core Dataを使うとサンプルアプリケーションが立派なアプリケーションになってしまうようです。CocoaプログラマはCore Dataを習得するべきでしょう。

Core Data Application

この前のNSPredicateの記事で使ったアプリケーションに追加して作りました。左下の「+」「-」は、コメントファイル(ニコニコ動画)の追加と削除です。追加すると、上の画像のように表示されます。Core Dataアプリケーションのテンプレートは、アプリケーションの終了時に、自動的にデータモデルを保存、アプリケーション開始時に復元を行ってくれるので、上の画像のようにデータがある状態でアプリケーションを終了すると、次立ち上げた時もそのままの状態で立ち上がります。

このアプリケーションのデータモデルは次のようになっており、XCode付属のツールで編集します。

Data Model

各種ビューはすべてバインディングを使っているので、全くコードを書かずに作成できました。ソート機能もバインディングした際に自動的に作成され、一番右下に表示されている、テーブルビューにあるアイテムの個数を表す数字も、コレクション演算子という特殊な記法を使ってバインディングすることで、コードをいっさい書かずに作成できます。

そういうわけなので、テンプレートのAppDelegateにchatsController,threadControllerの二つのアウトレットと、以下のコードを追加するだけでコーディングは終了します。

@interface Core_Data_AppDelegate (AppController)

- (IBAction)add:(id)sender;
- (void)addDocument:(NSURL *)fileURL;
- (IBAction)predicate:(id)sender;
- (IBAction)delete:(id)sender;

@end
@implementation Core_Data_AppDelegate (AppController)

- (IBAction)add:(id)sender
{
	NSOpenPanel *panel = [NSOpenPanel openPanel];
	[panel setAllowsMultipleSelection:YES];
	if ( [panel runModal] == NSOKButton ) {
		for ( NSURL *URL in [panel URLs] )
		{
			[self addDocument:URL];
		}
	} else {
		NSLog(@"cancel.");
	}
}

- (void)addDocument:(NSURL *)fileURL
{
	NSError *error;
	NSXMLDocument *document = [[[NSXMLDocument alloc] initWithContentsOfURL:fileURL
																	options:NSXMLDocumentValidate
																	  error:&error] autorelease];
	if ( document ) {
		NSManagedObject *thread = [NSEntityDescription insertNewObjectForEntityForName:@"Thread" inManagedObjectContext:managedObjectContext];
		[thread setValue:[[[fileURL absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] lastPathComponent] forKey:@"title"];
		NSArray *nodes = [document nodesForXPath:@"/packet/chat" error:nil];
		for ( id node in nodes ) {
			NSManagedObject *chat = [NSEntityDescription insertNewObjectForEntityForName:@"Chat" inManagedObjectContext:managedObjectContext];
			[chat setValue:[node stringValue] forKey:@"text"];
			[chat setValue:[[node attributeForName:@"user_id"] stringValue] forKey:@"identify"];
			[chat setValue:[[node attributeForName:@"mail"] stringValue] forKey:@"mail"];
			[chat setValue:[NSNumber numberWithInt:[[[node attributeForName:@"vpos"] stringValue] intValue]] forKey:@"vpos"];
			[[thread valueForKey:@"chats"] addObject:chat];
		}
		[threadController addObject:thread];
	} else {
		[[NSAlert alertWithError:error] runModal];
	}

}

- (IBAction)predicate:(id)sender
{
	if ( ![[sender stringValue] isEqualToString:@""] ) {
		NSPredicate *predicate = [NSPredicate predicateWithFormat:[sender stringValue]];
		[chatsController setFilterPredicate:predicate];
	} else {
		[chatsController setFilterPredicate:nil];
	}
}

- (IBAction)delete:(id)sender
{
	[managedObjectContext deleteObject:[[threadController selectedObjects] objectAtIndex:0]];
}

@end

ニコニコ動画のコメント解析アプリケーションを作る訳ではなかったのですが、このまま進めれば簡単に作れてしまいそうですね。これだけでも、NSPredicateの記法を知っている人ならば、そこそこ解析に使えると思います。

プロジェクトをzipで用意しましたので、興味のある方は持っていってください。

Core_Data.zip(2.3MB)

ちなみに、Core Dataが自動的にアプリケーションデータを保存する場所は、Application Support/プロジェクト名です。アプリケーションを終了した際、勝手に保存されますので、邪魔な方はゴミ箱に捨てましょう。プロジェクト名はCore Dataです。

Mono

みなさんはMonoプロジェクトをご存知でしょうか?Monoは、オープンソースのマルチプラットフォーム.NET互換環境を開発しているプロジェクトです。現在はまだ、Windows.Formsが動くかどうかというあたりまで進行しているプロジェクトですが、今後の動向が気になるプロジェクトです。

さて、そのMonoですが、当然Mac OS XのMonoも存在し、今日はこれでちょっと遊んでみました。ダウンロードはここからできます。興味のあるWindowsのユーザーの方、Macのユーザーの方、その他のOSの方もダウンロードして試してみましょう。Monoにはいくつかのコンパイラが搭載されているらしく、Monoをダウンロードすれば.NETアプリケーションを作成することもできます。というよりは、まだMonoは.NETの一部分しかサポートしていないので、自作のアプリケーションでなければ動かないでしょう。

今回は、最近よく目にするSystem.IO関連のDirectory.GetFiles()を使ってみました。コードはMono付属の何かでコンパイルできるC#だったと思います。

using System;
using System.IO;
using System.Collections;

public class HelloWorld
{
	static public void Main ()
	{
		foreach ( String s in Directory.GetFiles(Environment.CurrentDirectory) )
		{
			Console.WriteLine(s);
		}
	}
}

OS Xでのコンパイルの仕方は、mcsコマンドにファイルパスを渡します。問題なくコンパイルできたら、.exeの実行ファイルが作成されるので、今度はmonoコマンドに実行ファイルのパスを渡せば実行できます。実行結果は次の通り、問題なく動作します。

/Users/********/Desktop/.DS_Store
/Users/********/Desktop/.localized
/Users/********/Desktop/Google、コラボレーションツール「Google Sites」立ち上げ - ITmedia News.webloc
/Users/********/Desktop/Start - Mono.webloc
/Users/********/Desktop/hello.exe
/Users/********/Desktop/novi's Blog iPod touch に W-SIM を接続してみた.webloc
/Users/********/Desktop/temp
/Users/********/Desktop/ 人間に興味があるんじゃなくて,どちらかというと知識に興.textClipping
/Users/********/Desktop/「2ちゃんねる」と「ニコニコ動画」のひろゆき氏が語...webloc

これだけじゃつまらないので、試しにこのMono for Mac OS Xでコンパイルした実行ファイルを、Windowsにそのまま持っていって実行してみました。驚くことに、というか当たり前ではありますが、そのままの実行ファイルでWindowsでも問題なく動作します。WindowsにはMonoが入っている必要はなく、.NET Frameworkが入っていさえすれば動作します。実行結果は次の通りです。

C:¥Documents and Settings¥aaa¥.unicode_cache_283a1d41.dat
C:¥Documents and Settings¥aaa¥.unicode_cache_7ffe4658.dat
C:¥Documents and Settings¥aaa¥hamcore.se2
C:¥Documents and Settings¥aaa¥ntuser.dat
C:¥Documents and Settings¥aaa¥ntuser.dat.LOG
C:¥Documents and Settings¥aaa¥ntuser.ini
C:¥Documents and Settings¥aaa¥PUTTY.RND
C:¥Documents and Settings¥aaa¥ReafMe.txt
C:¥Documents and Settings¥aaa¥reglog.txt
C:¥Documents and Settings¥aaa¥vpnserver.exe
C:¥Documents and Settings¥aaa¥vpnsmgr.exe
C:¥Documents and Settings¥aaa¥vpn_server.config

これができるのなら、今度はWindowsのVisual Studioを久しぶりに立ち上げて、どこでビルドすればいいのか操作にしばし迷いつつ、なんとか実行ファイルを生成したところで、WindowsからMac OS Xにそのまま実行ファイルを持っていき、monoコマンドで実行してみたくなるわけです。

結果は、これも問題なく動作しました。さすが.NETと言ったところでしょうか、Windowsプラットフォームが普及したように、.NET環境も同じように普及する可能性が見えますね。

というわけで、今後もMonoプロジェクトにはかなり期待をしています。今後は.NET Frameworkを使ったアプリケーションが多く作られることが予想されますし、そのアプリケーションがWindowsだけでなく、そのままMac OS Xでも動くとなれば、Windowsより圧倒的にソフトの少ないMac OS Xにとっても非常に有益なことです。Paint.NETとかMac OS Xで動かしたいです。

ちなみに、MonoのWindows.Formsはある程度実装されているようなので、インストールすれば実行できると思うのですが、インストールが難しかったので途中で挫折しました。

NSPredicate

10/11/28 追記:新しい記事書きました。NSPredicate の使い方

最近ActiveBasic5.0の配列についてどうしようかという話がありましたが、先の意見におおむね賛成ですと、特に書くことなくてなんと書いていいのやらって事態に陥るんですよね。というわけで、空気を読まず、CocoaのNSPredicateについて紹介しましょう。

NSPredicateは、データ集合に対して検索するときの検索クエリーを表すクラスです。例えば、バインディングに設定しているNSArrayControllerに対して、setFilterPredicateでNSPredicateを設定することで、集合に対して任意の条件でフィルターをかけることができます。具体的に見てみると、次のような配列がバインディングされているテーブルビューがあります。ちなみに、ニコニコ動画のコメントファイルがちょうど良さそうな集合だったので、その一部をテーブルビューに表示しています。

Table View

これに対して、NSPredicateを次のようにNSArrayControllerに設定して、フィルターをかけてみます。

predicate

mailが184項目だけ表示されるようになりました。次はもうちょっと複雑なPredicateを設定してみましょう。

predicate

mailが”184″かつtextに”w”が含まれていない、という条件です。他にもいろいろな条件を指定することができます。興味のある方はPredicate Format String Syntaxをご覧ください。

このように、NSArrrayControllerとNSPredicateを使うことにより、織り込み検索的なインターフェースを手軽に作成することができます。NSPredicateはこの他に、Core Dataなどでも利用されており、ぜひ使い方をマスターしておきたいクラスです。

いろいろと

  • 前に言っていた仕様書らしきものを書き直してみる
  • Core Dataの説明がもはや日本語に見えない
  • File,FileInfoクラスを実装中…,途中でもコミットするか迷う…
  • 山本さんが最近実装されたXML関連のクラスを試してみたい
  • Codaが欲しい
  • ニコニコがH.264対応してもiBookのスペック的にどうだろうか
  • しかし最近回線速度50kb/sしか出ないのでH.264に期待
  • 正直、もう著作権は駄目かもしれない。mixiの件
  • 久しぶりに携帯見たら高すぎて買う気になれない
  • 次買うことがあるならばiPhone
  • 本屋行ったらPCの棚のところで地方テレビの撮影しててPCの本がみれなかった
  • Wiiが欲しいけど、人が集まったときにしか使わなそう
  • iPod touchが欲しいけど、結局おもちゃ
  • 個人的にATOKよりことえりだった

Coda:
coda