2011年5月27日金曜日

Core Graphicsで図形を描く

まーるさんかくしかーくー♪
ってことで、今回は図形を描写します。

まずこれ。簡単な四角形から。





-(void)drawInContext:(CGContextRef)context
{
CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1.0);

CGContextStrokeRect(context, CGRectMake(20.0, 20.0, 100.0, 200.0));

}
CGContextStrokeRect(context, CGRect);で枠だけの四角を描く。

次にこれ
-(void)drawInContext:(CGContextRef)context
{
CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1.0);

CGRect rect = CGRectMake(20.0, 20.0, 200.0, 300.0);
CGContextStrokeRectWithWidth(context, rect,10.0);

}

CGContextStrokeRectWithWidth(context, rect,線の太さ);で線の太さを変更できる四角を描く

次にこれ

-(void)drawInContext:(CGContextRef)context
{
CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1.0);

CGRect rect = CGRectMake(20.0, 20.0, 200.0, 300.0);
CGContextFillRect(context, rect);

}

はい、真っ黒〜
CGContextSetRGBStrokeColorは線の色なので、下の塗りつぶし色の設定を追加します。
CGContextSetRGBFillColor(context, 1.0, 0, 0, 1.0);



再び実行。
まさにRectを塗りつぶした形になります。




次に丸を描いてみます。

CGContextAddEllipseInRect(context,rect);//線の円
CGContextFillEllipseInRect(context,rect);//塗りつぶされた円
CGContextAddEllipseInRect(context,rect);//パスを追加

これも分かりやすいですね。


三角形はどうしょうでしょうか。
特にそれ用の関数は無いので、線を引いてその中を埋めていきます。


CGContextMoveToPoint(context,160.0,10.0);
CGContextAddLineToPoint(context,10.0,200.0);
CGContextAddLineToPoint(context,310.0,200.0);
CGContextFillPath(context);//塗りつぶす


この書き方だと、複数図形があってそれぞれ異なる色で塗りつぶしたり、はたまた線だけの図形を描くときにどうするんだろう?
で、一回一回完結させてみた。

-(void)drawInContext:(CGContextRef)context
{

CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1.0);
CGContextSetRGBFillColor(context, 0, 1.0, 0, 1.0);

CGContextMoveToPoint(context,160.0,10.0);
CGContextAddLineToPoint(context,10.0,200.0);
CGContextAddLineToPoint(context,310.0,200.0);


CGContextFillPath(context);

CGContextStrokeEllipseInRect(context, CGRectMake(10, 200, 100, 100));

CGRect rect = CGRectMake(10,210 , 100, 100);
CGContextAddEllipseInRect(context,rect);
CGContextStrokePath(context);

CGContextSetRGBFillColor(context, 1.0, 1.0, 0, 1.0);
CGContextFillEllipseInRect(context,CGRectMake(200,200,100,200));

}



とりあえず図形についてはこれでおしまい。

Core Graphicsを学ぶ

何となく CoreGraphics 辺りを書きたい気分に。
これを使って何かをしようと思ったことが無いので、個人的にも勉強しながら書いていくというスタンスです。


Core Graphicsは、UIImageとかよりもちょっとだけ低レベルなグラフィックフレームワークだとか。
Cocoa Touchよりもハードウェアよりに位置するので、実行速度も多分速くなるし自由度も増す。
Core何とかと名前がついているAPIは大抵C言語で提供されているんだけれど、Core Graphicsもそうらしい。
ってことは、呼び出しが若干煩雑になるってこと。


とりあえず、プロジェクトに CoreGraphics.frameworkを追加してみる。


1、グラフィックスコンテキスト
書籍なんかでは描画する対象を表すものだとか何とか書かれている。まあ、良くわからんが Core Graphicsを使った描画では、最初にグラフィックスコンテキストを取得しないといけないってことだけは確かだ。

 CGContextRef UIGraphicsGetCurrentContext();
 

とりあえず実践。
すべての描画はdrawRect: メソッドの中に記述するか、この中から呼ぶメソッドに記述しないと動かないらしいので、Viewを一丁つくってdrawRectにメソッドを書いておく。

これ、コメントを削除したアップルさんのサンプルと一緒w
引数でグラフィックコンテキストも作って渡しちゃう。

-(void)drawRect:(CGRect)rect
{
[self drawInContext:UIGraphicsGetCurrentContext()];
}


呼び出されるメソッドの中身はこれ。
なにやってるかはコメントに記載しました。
-(void)drawInContext:(CGContextRef)context
{
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);//線の色。引数はcontext, R,G,B,アルファ。

CGContextMoveToPoint(context, 20.0, 50.0);//線の始点
CGContextAddLineToPoint(context, 300.0, 50.0);//線の終点から線を生成
CGContextStrokePath(context);//線を引く
}


はい、びしっと線が引けたかと。

じゃあ、これを使って折れ線グラフ的な線も引けるんじゃないかと言うのが人情ですね。
上のやり方でちまちまやってもいいのですが、まとめてやる方法があります。

-(void)drawInContext:(CGContextRef)context
{
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
CGPoint lines[] =
{
CGPointMake(10.0, 90.0),
CGPointMake(70.0, 60.0),
CGPointMake(130.0, 100.0),
CGPointMake(190.0, 70.0),
CGPointMake(250.0, 90.0),
CGPointMake(310.0, 50.0)
};

CGContextAddLines(context, lines, 6);
CGContextStrokePath(context);

}


これで、真っ赤なガタガタ線が引けたかと思います。



最初にCの配列 lines を生成してCGPointをぶっこみにいってます。
CGContextAddLines関数。末尾に”s”が付いてるので複数形ですね。第一引数はcontext、次に接点を保つ配列が第二引数。最後の引数は接点の数です。 
 この最後の引数の「6」ですが、実際のプログラムでは動的に入れたいというケースがほとんどなので、ここを
 sizeof (lines)/ sizeof( lines[0]) とするとスマートです。
sizeof はメモリのサイズを返すので、配列全体のサイズを最初の一個目のサイズで割ると、CGPointひとつひとつで確保しているメモリのサイズは同じなので、配列の数 = 接点の数が算出できるというわけです。obj-Cみたいに[ Array count ] とかできないところがもどかしいですね。


<その他>

太さの設定
CGContextSetLineWidth(context, x);
x は?pxということ。

たばこと丸と四角

・線の端っこの形の設定。
CGContextSetLineCap関数で設定。まさに名前の通りw
 ラインキャップを設定するんですね。キャップは両端にかぶせます。
 
 kCGLineCapButt = 両切りタバコ状態
 kCGLineCapRound = 丸いキャップをするんですね。
 kCGLineCapSquare = 四角いキャップ。
 
 
 CGContextSetLineCap = kCGLineCapRound;
 
 Buttという単語はアメリカ英語だとタバコって意味もあるらしくて、灰皿を Butt tray とかとも言うらしい。でも、アメリカ人以外には通じないらしいw
 
 
 
ジョイントの方法

CGContextSetLineJoin = kCGLineJoinMiter;

miter joint(マイタージョイント)っていうのは、斜めに切った角材を張り合わせた感じの事をいうらしい。
ふむふむ。

kCGLineJoinMiter マイターに
kCGLineJoinRound 丸くつなぐ
kCGLineJoinBevel 角をばつんと落とす。

2011年5月26日木曜日

よく使う文字列操作その2

良く使う文字列操作を書き終わった後に色々思いついちゃったので、続編を書きたいと思います。
そういえば文字列の長さを取得するメソッドとかも書いてなかったし。。。
まあ、だいたいどの言語でもlengthなんでobj-cのルールに乗っ取って書けば [str length]; になりますね。
ちなみに、前回で解説してきたNSMutableStringクラスはNSStringクラスのサブクラスになるので、NSStringクラスで使えるメソッドは使えます。


文字列の比較。
これは [str isEqualToString:str2]; です。
例えば、
NSString *str = [NSString stringWithString:@"山田”];
if ( [str isEqualToString:@"田中"]) {
NSLog(@"%@!この野郎!",str);
}

って感じで、strが田中だった場合は、何だかぶっそうな展開になります。
上の例では isEqualToString:メソッドの戻り値はNO(Boolean)で返ってくるので、特に修羅場にはなりません。


パスからディレクトリ名などを切り出す。

まず、バンドルのリソースファイルを取得します。

NSString *path;
path = [bundle pathForResource:@"background" ofType:"@png"];

NSLog(@"%@",path);

これの実行結果が" /user/document/background.png" だとします。

//ファイルの拡張子を取得
NSString *extension;
extension = [path pathExtension];

NSLog(@"%@",extension);
//実行結果:png

//ファイル名を取得
//例ではファイル名入れてpathForResourceしてるんですが、まあ練習ということで (^^;)

NSString *fileName;
fileNamee = [path lastPathComponent];
NSLog(@"%@",fileName);
//実行結果: background


//ファイルが存在するディレクトリを取得
NSString *directory;
directory = [path stringByDeletingLastPathComponent];
NSLog(@"%@",directory);

//実行結果: /user/document


そうそう、忘れていました!型変換でもつまずく型は結構いるんじゃないでしょうか。

他の言語なら、異なる型で宣言した変数に入りさえすれば。。。ふふふ、なんて事にもなりますが、obj-cではそうはいきません。
無理矢理キャストというのも無いみたいです。
NSString *str = [NSString stringWithString:@"123"];
NSInteger int = 35 + (NSInteger) str;
なんてやったら確実に怒られますw

[str intValue];
でinteger に型変換できます。ダブルの場合は
[str double];
です。


Obj-Cのメソッドの名前って覚えずらいですよね。
何かを見ながらコード書くより声に出してみた方が案外覚えられることに最近気づきました。僕だけかもしれませんが。

2011年5月25日水曜日

良く使う文字列変換をまとめてみる

Objective-Cに慣れちゃったという人は読み飛ばしてください。
今回はかなりの初級編。

Excelの関数から始まり、VBAでプログラムデビューした自分にとってObj-Cの文字列変換ってどうにも親しみづらいイメージがありました。
ネットや本であれこれ調べて、最近はようやく慣れましたが。
そこで、良く使うパターンをまとめちゃいます☆


NSStringってクラスはご存知ですか?
Obj-cの文字を扱うクラスです。一度設定したら変更できないですね。

例えば。。。
NSString *str = @"str";
str = @"str2";

とかは怒られてしまいます。
なので、変更可能なクラスである NSMutableStringを個人的には多用します。
まあ、変更する必要がなければNSStringの方がプログラムの効率が良いのですがね。


文字列変換でやりたい事って、大体決まってますよね。
文字列連結に文字列置換に文字列取り出しってところでしょうか。おまけで型変換。特にC言語のStringにしたいってケースは良くあるかも。

生成を含めてズバリしたの5つ

文字列生成 > [NSMutableString stringWithFormat:str];
文字列連結 > [NSMutableString appendString:str];
文字列置換 > [NSMutableString stringByReplacingOccurrencesOfString:str1 withString:str2]
文字列取り出し > [str substringWithRange:NSMakeRange(0,1)];
UTF8に変換 > [str UTF8String];



まずは良く使う形。
NSMutableString *str1 = [NSMutableString stringWithFormat:@"SELECT * FROM TABLE WHERE id = %d",100];

stringWithFormatメソッド。これは文字列が格納された変数を生成するときによく使います。
最初の@””に囲まれた文字列が格納したい本体。%dには数字(Integerなど)を表す変数みたいなもの。
C が書ける人にはおなじみですね。
で、カンマで区切ってその「%d」の中に入れる数字が続きます。この「100」の部分は変数でもいいです。
VBのformat関数みたいなものですね。


少し発展させるとこんな感じになります。

NSString *str = [NSString stringWithFormat:@"%02d:%02d",Number/60,Number % 60];

変数Numberには数字が入っています。まあ、秒数だとしましょう。
上のコードは秒数から「00:00」に表記を変えるコードです。
%02dは二桁の数字という意味です。 1 = 01 ,11 = 11 ってな感じです。
%02dがコロンを挟んで二つならんでいると思います。そしてカンマで区切られた式が二つ。
分かりやすく構造だけ書くと下のようになります。

[NSString stringWithFormat:@"%d%d", (一つ目の%dに対応) , (二つ目の%dに対応) ];

要するに%何とかの個数が増えれば、それに対応させてカンマで区切られた値なり式が増えるんですね。
実際にSQLなんかを合成させてみるとこんな感じになります。
%dの代わりに使われている%@には文字列を格納しています。
一行目のコードで生成した文字列に appendString:メソッドで文字列を連結しています。
連結する文字列は stringWithFormat: で別途生成したも文字列になります。
末尾の NSLog関数で生成したSQLの内容をコンソールに表示させています。
NSLogの使い方は、ほぼStringWithFormatと同じ書式です。

NSMutableString *str1 = [NSMutableString stringWithFormat:@"%@",@"INSERT INTO Data1 VALUES"];
[str1 appendString:[NSMutableString stringWithFormat:@" (%d,'%@',%d,%d,%d,'%@','%@','%@');"
,[Array count]
,[Name_ stringByReplacingOccurrencesOfString:@"'" withString:@"''"]
,Number_
,info_
,SoundType_
,[soundName_ stringByReplacingOccurrencesOfString:@"'" withString:@"''"]
,infoSoundName_
,itemCode_
]];
NSLog(@"%@",str1);

文字列連結は
[NSMutableString appendString:@"文字列”]; です。
このメソッドを使うと、末尾に任意の文字列を連結できます。
 
NSMutableString *str = [NSMutableString stringWithFormat:@"今日は%d月%d日です。”,12,25];
[str appendString:@"なんだクリスマスじゃないか!”];
[str appendString:[NSMutableString stringWithFormat:@" じゃあ%d円くらいなら、おごってあげるよ。"]];

と、連結しまくりです。
上のコードでは文字列置換もやっています。痴漢じゃないですよ。置換。
この部分。
[Name_ stringByReplacingOccurrencesOfString:@"'" withString:@"''"]

Nameに含まれるシングルクォートをエスケープして['']シングルクォート二つに変更しています。
今時はみなさんCoreDataを使っているでしょうが、もしSqliteを使っているならば
生成したSQLに文字列が含まれるようなものを扱っているならば、シングルクオートをエスケープしとかないと
ユーザーがシングルクォーテーション付きの文字列を入れて登録〜っとやった瞬間にエラーぶっこきますよw

と、余談はさておき、

文字列置換は
[NSMutableString stringByReplacingOccurrencesOfString:str1 withString:str2]
となっていて、str1とstr2を入れ替えるんですね。

NSMutableString *hatugen = @"今回のプロジェクトは田中君にまかせることになった。がんばりたまえ”;

もし、田中が気に入らなくて鈴木さんに変更したいのならばこうだ。
[hatugen stringByReplacingOccurrencesOfString:@"田中” withStirng:@"鈴木"];


最後に文字列取り出し。
obj-cはVBとかエクセルの関数みたいにLeftとかMidとかじゃないんだけど、
にたようなものがあるのでそれを使う。

NSString *str = [NSString stringWithFormat:@"%02d:%02d",Second/60,Second % 60];
n1.text = [str substringWithRange:NSMakeRange(0,1)];//一文字目
n2.text = [str substringWithRange:NSMakeRange(1, 1)];//二文字目
n3.text = [str substringWithRange:NSMakeRange(3, 1)];//三文字目
n4.text=[str substringWithRange:NSMakeRange(4, 1)];//四文字目

NSMakeRange( 開始位置, 文字数) なので [str substringWithRange:メソッドを使えば、
エクセルの関数のMid(ミドル)的に取り出せる。


後は、変換した文字列の使い道としては、UILabelか UIButton かといったところでしょうか。
UILabel は Label.text = @"ラベルだどぉ";
UIButtonは [button setTitle:@"ボタンタイトルです。" forState:UIControlStateNormal];
って感じです。


今回は「良く使う文字列変換」についてでした~