...

2 章 Android グラフィックスによる Java 入門

by user

on
Category: Documents
6

views

Report

Comments

Transcript

2 章 Android グラフィックスによる Java 入門
2章
Android グラフィックスによる Java 入門
Android アプリを作るためには Java と XML の知識が必要になります。Java や XML を
本格的に学ぶにはそれぞれ入門書が必要になります。本書では Android アプリを作りなが
ら Java も XML も手っ取り早く学べるように工夫してあります。そこでまず、Android グ
ラフィックスを利用して画面に文字、直線、イメージなどを描画するプログラムを例に Java
の基本的な言語仕様について学びます。Android グラフィックスを例にしたのは、Android
グラフィックスでは XML の知識は必要ないこと、視覚的にも興味のある結果が得られ学習
のモチベーションが上がることです。
この章では Android アプリを作る上で当面必要な Java の基礎知識として以下の内容を説
明します
・オブジェクト指向言語特有の概念
クラス、インスタンス(オブジェクト)、コンストラクタ、メソッド
・C 言語などの基本言語と共通の概念
変数、演算子、for 文や if 文などの流れ制御文、配列
・Android グラフィックスに特有な概念
描画メソッド、ビットマップ
「注」この章のプログラムリストについて
最初の例題のみ全リストを掲載してありますが、その後の例題は GView クラス内のみが
変更されるので、GView クラスだけをリストとして掲載してあります。最初の例題を
Graph1 としています。その後の例題は Graph2、Graph3・・などと別なプロジェクトを
新たに作ってもよいですが、Graph1 の onDraw 内だけを変更してもよいです。ただしこの
場合は前に作ったプログラムは無くなってしまいますので注意してください。
2-1 Android グラフィックスの基礎
最初の例は「Android」という文字をグラフィックスで表示します。Android グラフィッ
クスは View クラスを元にして行います。描画処理は onDraw メソッドの中に記述します。
描画に当たっては、まず Paint クラスのメソッドを使って描画色やテキストサイズを指定
し、次に Canvas クラスのメソッドを使ってテキストの描画を行います。
1.
View クラス
グラフィックスを描画する画面は View クラスを継承して作ります。以下は GView とい
う名前のユーザ定義クラスを作っています。コンストラクタの GView はスーパークラスの
コンストラクタを呼び出す部分でこれが定型です。ユーザが行う描画処理は onDraw メソ
ッド内に記述します。
onDraw メソッドが呼び出されたときに Canvas クラスの引数 canvas
に描画オブジェクトが渡されますので、この canvas に対し描画メソッドを使ってグラフィ
ックス処理を行います。onDraw メソッドの仮引数を「Canvas canvas」としていますが、
仮引数の名前はなんであってもよいので「Canvas c」などとしても構いません。
private class GView extends View { ←View クラスを継承したユーザ定義クラス Gview
public GView(Context context) { ←コンストラクタ
super(context);
}
protected void onDraw(Canvas canvas) { ←onDraw メソッド
描画内容を記述
↑Canvas クラスの引数 canvas
}
}
この GView クラスを実際に画面に設定するには、「setContentView(R.layout.main);」
の代わりに「setContentView(new GView(this));」とします。前者はウイジェットを配置
したレイアウトを表示し、後者はグラフィックス画面を表示します。
2.
Paint クラスとオブジェクト(インスタンス)
Paint クラスは描画色や文字サイズなどの描画情報を扱うクラスです。クラスからインス
タンスを生成するには new 演算子を用いて、以下のように宣言します。コンストラクタは
クラス名と同じ名前の特別なメソッドで初期化を行うものです。これで paint という名前の
Paint クラスのオブジェクトが生成されます。以後 paint に対しメソッドを適用します。
↓クラス名
↓コンストラクタ
Paint paint=new Paint();
↑オブジェクト(インスタンス)
「注」オブジェクトとインスタンス
クラスはオブジェクトを生成するための金型(テンプレート)のようなものと考えるこ
とができます。オブジェクト指向言語では、金型から実際に生成された実体をオブジェク
トと言い、クラスからオブジェクトを作ることをインスタンス化(instantiation)と言い
ます。C++ではクラスを実体化したものをオブジェクトと呼び、Java ではインスタンス化
したオブジェクトをインスタンスと呼びます。この場合インスタンス=オブジェクトと考
えてよいです。本書では「インスタンス」という言葉が適切な場合以外は「インスタンス」
と「オブジェクト」を使い分けずに「オブジェクト」と呼ぶことにします。
3.
Paint クラスのメソッド
描画色を緑、フォントのサイズを 40 ピクセルに設定するには、paint オブジェクトに対
し setColor メソッド、setTextSize メソッドを使って以下のようにします。
「Color.BLUE」
は青色を示す Color クラスの定数です。
paint.setColor(Color.BLUE); ←青色
paint.setTextSize(40); ←テキストのサイズを 40 ピクセル
4.
Canvas クラスの描画メソッド
onDraw メソッドの引数 canvas に対し描画を行うには drawText メソッドを用います。
指定する x,y 座標はテキストの左下隅の座標です。
canvas.drawText("Android", 10,50, paint);
↑描画位置の x,y 座標
Android
↑左下隅の座標を表示位置として指定
「注」メソッドとは
メソッドはある処理を行う機能単位で、ユーザは引数というデータをこのメソッドに渡
して目的の処理を行います。
「注」メソッドの種類
onDraw と drawText はどちらもメソッドですが、呼び出し方(呼び出され方)が異なり
ます。通常 onXXX メソッドはシステムから呼び出されるメソッドで、処理内容をユーザが
定義します。たとえば、onDraw メソッドは画面に描画を行う必要が生じたときに呼び出さ
れます。これに対し「オブジェクト.メソッド(引数,・・・)」の形式で呼び出すメソッドは
ユーザが直接メソッドを呼び出します。
「注」インデント
プログラムのブロック構造を分かりやすくするため内側のブロックになるほど書き出す
位置を右にずらすことをインデント(字下げ)と言います。Eclipse では自動的に 4 文字幅
のインデントをとります。
「例題 2-1」以上をまとめた全リストを示します。それぞれの位置関係を確認してください。
・MainActivity.java
package com.example.graph1;
import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.os.Bundle;
import android.view.View;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new GView(this));
}
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setTextSize(40);
canvas.drawText("Android",10,50,paint);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
「注」onCreateOptionsMenu メソッドは削除しても構いません。
「注」背景色
古い開発環境(2012 年 6 月頃までの Android SDK)ではデフォルトの背景色は黒背景で
したが、新しい開発環境では白背景です。デフォルトの背景色を変えるには onDraw メソ
ッドの先頭で以下のように背景色を設定します。背景白にするには Color.WHITE とします。
Protected void onDraw(Cavas canvas){
canvas.drawColor(Color.BLACK);
「注」Android Lint Checks
古い開発環境では以下のように onDraw メソッド内で Paint オブジェクトを取得しても
警告エラーになりませんでした。
protected void onDraw(Canvas canvas) {
Paint paint=new Paint();
paint.setColor(Color.BLUE);
paint.setTextSize(40);
canvas.drawText("Android",10,50,paint);
}
新しい開発環境では「Paint paint=new Paint();」のところで「Avoid object allocations
during draw/layout operations (preallocate and reuse instead)」という警告エラーがでま
す。これは onDraw が呼ばれるたびに Paint オブジェクトを生成するという無駄を止め、
GView 内で一度生成したものを使いまわしなさいということです。このような厳しいチェ
ックを「Android Lint Checks」と言います。
このため、本書では paint をメソッド外で宣言し、GView コンストラクタ内で Paint オ
ブジェクトを生成し、onDraw メソッドで paint を使用するという多少煩雑な方法をとって
います。
private class GView extends View {
private Paint paint; ←paintの宣言
public GView(Context context) {
super(context);
paint=new Paint(); ←Paintオブジェクトの生成
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE); ←paintの使用
paint.setTextSize(40);
canvas.drawText("Android",10,50,paint);
}
}
警告エラーを無視するなら上のように onDraw 内に全てまとめる方が簡単です。
2-2 for 文による繰り返し
Java に限らずどのようなプログラム言語においてもプログラムの流れを制御する制御文
があります。Java は C 系の言語と同じ流れ制御文を使います。たとえば繰り返しを行う for
文や while 文、条件判定を行う if 文、else if 文、switch 文などです。この章ではこれらの
制御文の使い方を説明します。switch 文については 3-9 で説明します。
1.
for 文
for 文は決められた回数の繰り返しに使います。たとえば、次の例は、変数 i を 1 から始
め、10 以下の間、i を+1 しながら、{と}で囲まれた範囲(ブロック)を繰り返します。{ }
内に書く文が1つのときは{ }を省略できます。繰り返しのことをループと呼びます。for
文の繰り返しを制御している変数のことをループ変数と呼びます。
↓初期値
for (i=1;i<=10;i++){
・
↑ ↑増減式
・
終了条件式
}
「例」
for (i=5;i<=10;i++)
・・・i を 5 から始め i を+1 しながら 10 まで繰り返す。6 回繰り返すことになります。
for (i=10;i>0;i--)
・・・i を 10 から始め、i を-1 しながら 0 より大きい間繰り返す。10 回繰り返すことにな
ります。
for (x=-2.0;x<=2.0;x+=0.5)
・・・x を-2.0 から始め,+0.5 しながら 2.0 になるまで繰り返します。
「例題 2-2」Android という文字を 5 個縦に描きます。表示するテキストの x 座標を 10 と
し、y 座標を 40、80、120、160、200 と変化します。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setTextSize(40);
for (int y=40;y<=200;y+=40){
canvas.drawText("Android",10,y,paint);
}
}
}
「練習問題 2-2」例題 2-2 と同じことをループ変数 i を 1~5 まで変化させて行いなさい。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setTextSize(40);
for (
①
){
canvas.drawText("Android",10,
}
}
}
② ,paint);
2-3 変数の役割
変数はプログラムの進行によってその値が変わります。この意味から「変わる数=変数」
と呼びます。これに対し 10 や"hello"などの変化しないものを定数と呼びます。
1.
変数の宣言
変数は使用する前に、
「int i;」のように宣言します。これで int 型(integer:整数型)の
変数 i が宣言されました。複数の変数を一緒に宣言するには各変数をコンマ(,)で区切り、
「int i,j;」のように宣言します。
for 文で使うループ変数は for 文の外で
int i;
for (i=0;i<=10;i++)
のように宣言してもよいですが、次のように for 文の中で宣言することもできます。
for (int i=0;i<=10;i++)
2.
変数名の付け方
変数に付ける名前を変数名と呼びます。変数名には名前付け規則がありますが、おおよ
その規則は以下です。
・英字で始まる英数字。a1 や sum など。
・英大文字と英小文字を区別する。SUM,Sum,sum はいずれも異なる変数名となる。
・予約語を使用してはいけないが、それを含むことはできる。たとえば、for は認められな
いが force は認められる。
変数名はユーザが決めれば良いわけですが、ある程度の共通ルールに従った方がプログラ
ムを読みやすくします。
・for などのループ変数には i,j,k などを使う
・変数の役割を連想できる変数名を使う。合計なら sum など。
3.
演算子
データを加減乗除するものを演算子と呼びます。i++は変数 i の内容を+1 します。i--は変
数 i の内容を-1 します。++を増分演算子(インクリメント演算子)
、--を減分演算子(デク
リメント演算子)と呼びます。i++は i=i+1 と同じ意味、i--は i=i-1 と同じ意味です。i+1 の
+は加算演算子、i-1 の-は減算演算子です。
x+=0.5 は x の内容を+0.5 します。x=x+0.5 と同じ意味です。+=を複合代入演算子と呼び
ます。
4.
文字列の連結
文字列は「"」で囲って、"Android"のように表します。文字列は「+」演算子を使って連
結することができます。"123"+"45"は"12345"となります。「文字列+数値」または「数値
+文字列」の場合は数値が文字列に変換されて連結されます。
「 例題 2-3」 ループ 変数の i を使 って「 "Android"+i」 とするこ とで、 "Android1" 、
"Android2"・・・、"Android5"という文字列を作り出します。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setTextSize(40);
for (int i=1;i<=5;i++){
canvas.drawText("Android"+i,10,i*40,paint);
}
}
}
「練習問題 2-3」1+2+・・・+99+100 の合計値を変数 sum に求め表示しなさい。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setTextSize(40);
int sum=0;
for (int i=1;i<=100;i++){
①
}
canvas.drawText("合計="+ ② ,10,40,paint);
}
}
2-4 イメージの表示
Android では PNG や JPG(JPEG)などのイメージを View 画面に表示することができ
ます。デフォルトで res/drawable に ic_launcher.png というイメージファイルが用意され
ているので、これを表示する方法を説明示します。
1.
リソースからビットマップを作製する
res/drawable にある ic_launcher.png をリソースとして管理するときのリソース ID(識
別番号)は「R.drawable.ic_launcher」です。イメージリソースからグラフィックス描画を
行うためのビットマップを作るには BitmapFactory クラスの decodeResource メソッドを
使います。decodeResource メソッドの第 1 引数にはアプリケーションのリソースを管理し
ているリソース管理オブジェクトを指定します。このオブジェクトは
「getContext().getResources()」または「getResources()」で取得できます。第 2 引数には
イメージに割り当てられたリソース ID を指定します。
↓リソース管理オブジェクト
Bitmap img = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
↑リソース ID
2.
ビットマップの描画
ビットマップを描画するには Canvas クラスの drawBitmap メソッドを使います。最後
の引数は Paint クラスのオブジェクトを指定して描画モードを設定しますが、ビットマッ
プをそのままのイメージで描画する場合は「null」を指定します。表示位置の(x,y)はイメー
ジの左上隅の座標となります。
↓ビットマップ
canvas.drawBitmap(img,x,y,null);
↑表示位置(x,y)
「例題 2-4」R.drawable.ic_launcher で示すイメージを(0,0)位置に描画します。
private class GView extends View {
private Bitmap img;
public GView(Context context) {
super(context);
img=BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
}
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(img,0,0,null);
}
}
「注」Android Lint Checks
Paint オブジェクトの場合と同様に、onDraw 内で Bitmap リソースを取得すると警告エ
ラーとなります。
protected void onDraw(Canvas canvas) {
Bitmap img = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
canvas.drawBitmap(img,0,0,null);
}
「注」ic_launcher.png のサイズ
res/drawable-hdpi に格納されている ic_launcher.png のサイズは 72×72 ピクセルです。
「練習問題 2-4」R.drawable.ic_launcher で示すイメージを 4 か所に描画しなさい。
private class GView extends View {
private Bitmap img;
public GView(Context context) {
super(context);
img=BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
}
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(img,0,0,null);
canvas.drawBitmap(img,
① ,null);
canvas.drawBitmap(img,
② ,null);
canvas.drawBitmap(img,72,72,null);
}
}
2-5 イメージリソースの配置
ic_launcher.png はデフォルトで配置されていますが、ここでは white.png(60×60 ピク
セル)というイメージファイルを「res/drawable-hdpi」フォルダに置きます。
white.png
ビットマップ・イメージ img の幅 w と高さ h を取得するには次のようにします。
int w=img.getWidth();
int h=img.getHeight();
「例題 2-5」white.png を横に 5 つ並べて描画します。イメージの横幅 w を取得し、その値
を元に表示する x 座標を i*w で求めます。
private class GView extends View {
private Bitmap img;
public GView(Context context) {
super(context);
img=BitmapFactory.decodeResource(getResources(),
R.drawable.white);
}
protected void onDraw(Canvas canvas) {
int w=img.getWidth();
for (int i=0;i<5;i++){
canvas.drawBitmap(img,i*w,30,null);
}
}
}
「練習問題 2-5」white.png イメージを横に 5 列、縦に 2 行で描画しなさい。
private class GView extends View {
private Bitmap img;
public GView(Context context) {
super(context);
img=BitmapFactory.decodeResource(getResources(),
R.drawable.white);
}
protected void onDraw(Canvas canvas) {
int w=img.getWidth();
int h=
①
for (int i=0;i<5;i++){
canvas.drawBitmap(img,i*w,30,null);
canvas.drawBitmap(img,i*w, ② ,null);
}
}
}
1.
扱えるイメージフォーマット
Android で扱えるイメージフォーマットは BMP(Bitmap)、JPG(JPEG)、PNG、GIF で
す。この中で PNG が推奨とされています。写真画像などは JPG を使うことがよくありま
すので、通常は PNG と JPG を使うことが多いでしょう。
2.
drawable リソースの種類
drawable はイメージのリソースですが、異なる解像度やディスプレイサイズに対応する
ために xhdpi(eXtra High)、hdpi(High)、mdpi(Middle)、ldpi(Low)の 4 種類の dpi
(dot per inch)リソースが用意されていて、実行している端末に合った dpi のフォルダか
ら自動的に画像を取得します。
このため drawable リソースを示す ID は「R.drawable-hdpi.white」のように dpi を特定
して指定せず「R.drawable.white」のようにします。ちなみにデフォルトで配置されてい
る ic_launcher.png のサイズは 96×96、72×72、48×48、36×36 です。画面が WVGA の
場合は drawable-hdpi フォルダのイメージが使われます。
3.
null
null はオブジェクトがどこも参照していないということを示す特別な定数です。たとえ
ば「Bitmap img;」のように Bitmap クラスの img を宣言した場合、img にはオブジェクト
が生成されていないので、この時点での img は「null」という値を保持しています。この
場合は「if (img==null)」のような使い方をします。
null の別な使い方はメソッドの引数に指定する場合です。この場合は null を指定した引
数はデフォルトの処理をすることになります。たとえば、drawBitmap(img, 0,0,null);の最
後の引数に null を指定しています。最後の引数には Paint クラスのオブジェクトを指定し
て描画モードを指定することになっているのですが、デフォルトの処理でよいときには null
を指定します。
4.
インスタンス・メソッドと static メソッド
「canvas.drawBitmap」と「BitmapFactory.decodeResource」という 2 つのメソッドは
種類が異なります。前者をインスタンス・メソッド(通常これを単にメソッドと呼ぶ)、
後者を static メソッドと呼びます。
「Canvas canvas」
の Canvas はクラス、
canvas は Canvas
クラスのインスタンスです。drawBitmap メソッドは canvas というインスタンスに対して
その操作を行います。これに対し BitmapFactory はクラス名ですが、この場合の
BitmapFactory は BitmapFactory クラスの唯一のインスタンスと考えることができ、この
唯一のインスタンスに対し、decodeResource メソッドはその操作を行います。インスタン
ス・メソッドはインスタンスごとに生成されるので、そこで扱うデータはインスタンスご
とに固有のものです。これに対し static メソッドはいちいちインスタンスを生成せずに、
デフォルトで生成されいる静的なインスタンス(クラス名のインスタンス)に対して行う
ため、データは共有されます。static メソッドの代表的なものに、Math クラスの sin、cos
メソッドがあります。
「注」ここでは「インスタンス・メソッド」という Java の用語の関係でインスタンスとい
う言葉を使用していますが、オブジェクトと同じ意味です。
2-6 if else 文による条件判定
条件を判定し、その判定に応じて実行する処理を変えるには if else 文を使います。
1.
if else 文
if else 文は以下のように書きます。条件式を満たせば「文 1」を実行し、満たさなければ
「文 2」を実行します。else 節に書くものがなければ else 節全体を省略します。{ }内に書
く文が 1 つの時は{ }を省略することができます。
if (条件式) {
文 1 ←条件を満たしたときに実行される文
}
else {
文 2 ←条件を満たさないときに実行される文
}
条件式としては、次のようなものを書きます。条件式を満たしたときを真、満たさなか
ったときを偽と呼びます。
a>1
変数 a が 1 より大きいとき真
a==1
変数 a が 1 のとき真
a==1 && b==1
変数 a が 1 でかつ変数 b が 1 のとき真
a==1 || b==1
変数 a が 1 または変数 b が 1 のとき真
2.
比較演算子
条件式において、大きい、小さい、等しいなどの大小比較を行う演算子を比較演算子と
呼び次の 6 つがあります。等しいは==と=を 2 つ書くことに注意してください。
比較演算子
意味
>
左辺の値が右辺の値より大きい。
>=
左辺の値が右辺の値より大きいか等しい。
<
左辺の値が右辺の値より小さい。
<=
左辺の値が右辺の値より小さいか等しい。
==
左辺の値と右辺の値が等しい。
!=
左辺の値と右辺の値が等しくない。
3.
論理演算子
1 つの条件式の真と偽を否定(反転)する!演算子、2 つの条件式を組み合わせて真・偽を
判定する&&演算子、||演算子を論理演算子と呼びます。
論理演算子
意味
!
否定(NOT)
。真なら偽、偽なら真。
&&
かつ(AND)
。2 つの条件式の両方が真のとき真。
||
または(OR)。2 つの条件式のどちらかが真のとき真。
「例題 2-6」白石と黒石を交互に 4 組み描画します。「i%2==0」が条件を満たすのは i が
0,2,4,6 のときです。
private class GView extends View {
private Bitmap white,black;
public GView(Context context) {
super(context);
white=BitmapFactory.decodeResource(getResources(),
R.drawable.white);
black=BitmapFactory.decodeResource(getResources(),
R.drawable.black);
}
protected void onDraw(Canvas canvas) {
int w=white.getWidth();
for (int i=0;i<8;i++){
if (i%2==0)
canvas.drawBitmap(white,i*w,30,null);
else
canvas.drawBitmap(black,i*w,30,null);
}
}
}
「注」 剰余演算子
%は整数値の除算の余りを求める演算子です。「10%3」は 10 を 3 で割ったときの余り
の「1」になります。剰余を使えば変数 i の値が偶数か奇数か判定できます。「i%2==0」な
ら i は偶数と判定できます。
「練習問題 2-6」1 段目は白石、2 段目は黒石から初めて例題 2-6 と同様に描画しなさい。
private class GView extends View {
private Bitmap white,black;
public GView(Context context) {
super(context);
white=BitmapFactory.decodeResource(getResources(),
R.drawable.white);
black=BitmapFactory.decodeResource(getResources(),
R.drawable.black);
}
protected void onDraw(Canvas canvas) {
int w=white.getWidth();
int h=white.getWidth();
for (int i=0;i<8;i++){
if (i%2==0){
canvas.drawBitmap(white,i*w,30,null);
canvas.drawBitmap(black,i*w,30+h,null);
}
else {
}
canvas.drawBitmap(
①
,null);
canvas.drawBitmap(
②
,null);
}
}
}
2-7 2 重ループ
ループの中にループが何重にも入る構造を多重ループと呼びます。for 文の 2 重ループは
以下のような構造です。
for (int i=1;i<=2;i++){
for (int j=1;j<=3;j++){
A
}
}
ループ変数 i が外ループ、ループ変数 j が内ループを管理します。この 2 重ループは次の
ように動作します。
外側のループを開始し、i が 1 のまま内側のループの j を 1~3 まで繰り返します。内側
ループの繰り返しが終了すると外側のループ変数 i が 2 となり、再び内側のループを繰り返
します。
上の二重ループにおいて、A 部におけるループ変数 i と j の値をトレースすると次のよう
になります。
i
j
1
1
2
3
2
1
2
3
「例題 2-7」リバーシーの盤面を示す 8×8 のマスを green.png で描きます。ループ変数の
y が縦方向(y 方向)、ループ変数の x が横方向(x 方向)を管理します。(y,x)位置の表
示座標は(y*h,x*w)となります。実際にはタイトルバーから 10 ピクセル離すように y*h+10
で表示します。x が内側のループになっているので、横方向にイメージが表示されていきま
す。
private class GView extends View {
private Bitmap green;
public GView(Context context) {
super(context);
green=BitmapFactory.decodeResource(getResources(),
R.drawable.green);
}
protected void onDraw(Canvas canvas) {
int w=green.getWidth();
int h=green.getHeight();
for (int y=0;y<8;y++){
for (int x=0;x<8;x++){
canvas.drawBitmap(green,x*w,y*h+30,null);
}
}
}
}
「注」座標と行列
一般の数学の座標では(x,y)位置のように x を先に記述しますが、プログラムでは a[i][j]
のような配列の添字の使い方をして、行を示す i を先に記述します。この配列の行列を座標
に対応させると行が y、列が x となるため、(行,列)という指定でいくと、(i,j)位置や(y,x)
位置のような表現をすることがあります。
「練習問題 2-7」8×8 のマスの対角線位置だけに green.png で描画しなさい。対角線の条
件は「x==y 」または「 x+y==7」です。
private class GView extends View {
private Bitmap green;
public GView(Context context) {
super(context);
green=BitmapFactory.decodeResource(getResources(),
R.drawable.green);
}
protected void onDraw(Canvas canvas) {
int w=green.getWidth();
int h=green.getHeight();
for (int y=0;y<8;y++){
for (int x=0;x<8;x++){
if (
①
)
canvas.drawBitmap(green,x*w,y*h+30,null);
}
}
}
}
2-8 else if 文
if else 文は 2 方向の選択を行いますが、else if 文は多方向選択を行います。else if 文は if
else 文の else 節に if がネストしたものと考えられます。条件式 1~条件式 m までが上から
順次評価され、一致したところの文を実行し else if 文から抜けます。一致する条件がなか
ったときは else 節の文が実行されます。else 節に書くものがなければ省略できます。文が
単文の場合は{ }を省略することもできます。
if (条件式 1) {
文1
}
else if (条件式 2) {
文2
}
・
・
else if (条件式 m) {
文m
}
else {
文n
}
「例題 2-8」白石と黒石を中央にクロスして置きます。白石は(3,3)と(4,4)位置、黒石は(3,4)
と(4,3)位置になります。この条件で白石または黒石を判定し、いずれでもなければ緑盤面
とします。i が縦(y 座標),j が横(x 座標)を表します。
private class GView extends View {
private Bitmap white,black,green;
public GView(Context context) {
super(context);
white=BitmapFactory.decodeResource(getResources(),R.drawable.white);
black=BitmapFactory.decodeResource(getResources(),R.drawable.black);
green=BitmapFactory.decodeResource(getResources(),
R.drawable.green);
}
protected void onDraw(Canvas canvas) {
int w=green.getWidth();
int h=green.getHeight();
for (int i=0;i<8;i++){
for (int j=0;j<8;j++){
if (i==3 && j==3 || i==4 && j==4)
canvas.drawBitmap(white,j*w,i*h+30,null);
else if(i==3 && j==4 || i==4 && j==3)
canvas.drawBitmap(black,j*w,i*h+30,null);
else
canvas.drawBitmap(green,j*w,i*h+30,null);
}
}
}
}
「練習問題 2-8」N の文字を表すように石を描画しなさい。その際左端と右端は白石、対角
線は黒石としなさい。
private class GView extends View {
private Bitmap white,black,green;
public GView(Context context) {
super(context);
white=BitmapFactory.decodeResource(getResources(),R.drawable.white);
black=BitmapFactory.decodeResource(getResources(),R.drawable.black);
green=BitmapFactory.decodeResource(getResources(),
R.drawable.green);
}
protected void onDraw(Canvas canvas) {
int w=green.getWidth();
int h=green.getHeight();
for (int i=0;i<8;i++){
for (int j=0;j<8;j++){
if (
①
)
canvas.drawBitmap(white,j*w,i*h+30,null);
else if(
②
)
canvas.drawBitmap(black,j*w,i*h+30,null);
else
canvas.drawBitmap(green,j*w,i*h+30,null);
}
}
}
}
2-9 配列
たくさんのデータを効率よく管理するための便利なしくみ(データ構造)に、配列があ
ります。配列は配列名と添字(そえじ)を用いて配列の各要素を参照します。配列は扱う
添字の個数により 1 次元配列、2 次元配列などがあります。
1.
配列の宣言と参照
1 次元配列は配列名と 1 つの添字で構成します。
↓配列名 ↓確保する要素の個数
int[] a=new int[10];
↑
↑型名またはクラス名
これにより a[0],a[1],・・・a[9]という 10 個の要素からなる 1 次元配列が用意されます。配
列の基底要素は 0 から始まりますので 0 から 9 までの 10 個の要素が用意されます。a[10]
という要素は用意されていないことに注意してください。i 番目の要素は a[i]で参照できま
す。従って、配列の全ての要素を 0 にするには次のようにします。「a.length」で配列 a[ ]
の要素数(この例では 10)を取得します。
for (int i=0;i<a.length;i++)
a[i]=0;
2.
配列の初期化
配列の各要素に初期値を与えるには、配列の宣言時に{ }内に初期化するデータをコンマで
区切って指定します。初期化データがある場合は new 演算子は省略できます。
int[] a={0,1,2,3,4,5,6,7,8,9};
これで a[0]に 0、a[1]に 1,・・・a[9]に 9 が初期化されます。
3.
drawLines メソッド
M の文字を構成する 4 本の直線のそれぞれの始点 x,y 座標、終点 x,y 座標を配列 p[ ]に格
納しておき、「canvas.drawLines(p,paint);」とすると M の文字が描画されます。
4.
座標移動
「canvas.translate(sx,sy);」とすることで座標原点を現在位置から(sx,sy)だけ移動しま
す。
「例題 2-9」M の文字を座標を移動しながら 20 個描画します。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
float[] p =
{30,210,30,30,30,30,120,120,120,120,210,30,210,30,210,210};
for (int i=0;i<20;i++){
canvas.translate(3,3);
canvas.drawLines(p,paint);
}
}
}
「練習問題 2-9」fruits[ ]配列に格納されている文字を描画しなさい。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setTextSize(40);
①
fruits={"Apple","Orange","Strawberry"};
for (int i=0;i<3;i++){
canvas.drawText(
}
}
}
②
,10,(i+1)*40,paint);
2-10 2 次元配列
成績表のような表データは、行と列を要素とする縦横の表で、これは 2 次元配列で表現
することができます。2 次元配列は次のように行要素と列要素を指定して宣言します。
int[][] m=new int[5][3];
↑↑列要素の個数
行要素の個数
上図の斜線部の要素は m[3][2]と表せます。2 次元配列の宣言時に初期化要素を置くこと
もできます。
int[][] m={{80,70,60},
{60,90,70},
{80,80,70},
{70,60,50},
{80,90,90}};
int[][] m=new int[5][3];という 2 次元配列の行要素数、列要素数は length プロパティー
を使って以下のように取得できます。
m.length
行要素数の 5 を返す。
m[0].length
列要素数の 3 を返す。
「例題 2-10」2×2 のマスを示す 2 次元配列 m[ ][ ]の要素が 1 なら白石、2 なら黒石を描画
します。
private class GView extends View {
private Bitmap white,black;
public GView(Context context) {
super(context);
white=BitmapFactory.decodeResource(getResources(),R.drawable.white);
black=BitmapFactory.decodeResource(getResources(),R.drawable.black);
}
protected void onDraw(Canvas canvas) {
int[][] m={{1,2},{2,1}};
int w=white.getWidth();
int h=white.getHeight();
for (int i=0;i<2;i++){
for (int j=0;j<2;j++){
if (m[i][j]==1)
canvas.drawBitmap(white,j*w,i*h+30,null);
else
canvas.drawBitmap(black,j*w,i*h+30,null);
}
}
}
}
「練習問題 2-10」8×8 のマスを示す 2 次元配列 m[ ][ ]の要素が 1 なら白石、2 なら黒石、
0 なら緑を描画しなさい。
private class GView extends View {
private Bitmap white,black,green;
public GView(Context context) {
super(context);
white=BitmapFactory.decodeResource(getResources(),R.drawable.white);
black=BitmapFactory.decodeResource(getResources(),R.drawable.black);
green=BitmapFactory.decodeResource(getResources(),R.drawable.green);
}
protected void onDraw(Canvas canvas) {
int[][] m={
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,1,2,0,0,0},
{0,0,0,2,1,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0}
};
int w=white.getWidth();
int h=white.getHeight();
for (int i=0;i<8;i++){
for (int j=0;j<8;j++){
if (
①
)
canvas.drawBitmap(white,j*w,i*h+30,null);
else if (
②
)
canvas.drawBitmap(black,j*w,i*h+30,null);
else
canvas.drawBitmap(green,j*w,i*h+30,null);
}
}
}
}
2-11 データ型
Java で使用できる基本データ型として以下があります。
型名
サイズ
意味、値の範囲
byte
8 ビット
バイト整数。-128~127。
short
16 ビット
短長整数。-32768~32767。
int
32 ビット
自然長整数。-2147483648~2147483647。
long
64 ビット
倍長整数。-9223372036854775808~9223372036854775807。
float
32 ビット
単精度浮動小数点数。±3.4E-38~±3.4E+38。有効桁 6~7。
double
64 ビット
倍精度浮動小数点数。±1.79E-308~±1.79E+308。有効桁 15。
char
16 ビット
文字型。Unicode。
boolean
8 ビット
論理型。true/false。
基本データ型は単純なデータ型ですが、クラスと呼ばれる複雑なデータ型があります。
以下はこの章で使用しているクラスです。クラス名の先頭は大文字になっています。
クラス
意味
Canvas
描画キャンバス。
Paint
描画を行うペン。
Bitmap
ビットマップイメージ。
String
文字列。
「例題 2-11」Bitmap クラスの配列 m[ ][ ]に white、black の Bitmap データを初期化し、
そのデータを元にイメージを描画します。
private class GView extends View {
private Bitmap white,black;
public GView(Context context) {
super(context);
white=BitmapFactory.decodeResource(getResources(),
R.drawable.white);
black=BitmapFactory.decodeResource(getResources(),
R.drawable.black);
}
protected void onDraw(Canvas canvas) {
Bitmap[][] m={{white,black},{black,white}};
int w=white.getWidth();
int h=white.getHeight();
for (int i=0;i<2;i++){
for (int j=0;j<2;j++){
canvas.drawBitmap(m[i][j],j*w,i*h+30,null);
}
}
}
}
「練習問題 2-11」String クラスの配列に"♂"、"♀"の文字列データを初期化し、そのデータ
を描画します。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setTextSize(60);
String[][] m={{"♂","♀"},{"♀","♂"}};
for (int i=0;i<2;i++){
for (int j=0;j<2;j++){
canvas.drawText(
①
,(i+1)*60,paint);
}
}
}
}
2-12 while 文
for 文は繰り返し回数が決まっている繰り返しですが、while 文は繰り返し回数が決まっ
ていない繰り返しです。( )内の式が真の間{ }内の文を繰り返します。
while (式) {
文
}
「例題 2-12」M を示す 5 点の座標データが x[ ]と y[ ]に格納されています。配列データの終
わりの印として「-1」を置いてあります。LPX,LPY には直線を描く際の始点データを格納
します。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
float[] x={30,30,120,210,210,-1};
float[] y={210,30,120,30,210,-1};
float LPX=x[0],LPY=y[0]; // 最初の点
int i=1; // 2番目の点から
while (x[i]!=-1){
canvas.drawLine(LPX,LPY,x[i],y[i],paint);
LPX=x[i];LPY=y[i];
i++;
}
}
}
「練習問題 2-12」例題 2-12 では i を 1 から始めていましたが、0 から開始して、while 文
の中で i が 0 でないときだけ直線を描くようにしなさい。LPX,LPY の初期化は必要です。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
float[] x={30,30,120,210,210,-1};
float[] y={210,30,120,30,210,-1};
float LPX=0,LPY=0;
int
①
while (x[i]!=-1){
if (
②
)
canvas.drawLine(LPX,LPY,x[i],y[i],paint);
LPX=x[i];LPY=y[i];
i++;
}
}
}
2-13 ユーザ定義メソッド
今までは各クラスですでに定義されているメソッドについて説明しましたが、ここでは
ユーザ定義のメソッドを作ります。ユーザ定義メソッドの定義と呼び出しは次のように行
います。メソッドが呼び出し元にデータを返さない場合はメソッドの型を「void」とし
「return 式;」はありません。
メソッド名(実引数,実引数,・・・); // メソッドの呼び出し
型 メソッド名(型 仮引数, 型 仮引数,・・・) { // メソッドの定義
return 式;
}
「例題 2-13」引数で与えられたテキストと個数の星を表示するユーザ定義メソッド star を
作ります。star メソッドは Canvas オブジェクト(Canvas canva)、表示 y 座標(int y)、
表示する文字列(String msg)、表示する星の数(int n)を引数に持ちます。結果を返さ
ないメソッドなので void 型とします。またアクセス属性は private とします。
private class GView extends View {
private Paint paint;
private Bitmap star;
public GView(Context context) {
super(context);
paint=new Paint();
star=BitmapFactory.decodeResource(getResources(),R.drawable.star);
}
protected void onDraw(Canvas canvas) {
star(canvas,10,"価格:",3);
star(canvas,40,"品質:",5);
}
private void star(Canvas canvas,int y,String msg,int n){
paint.setColor(Color.BLUE);
paint.setTextSize(30);
canvas.drawText(msg,0,y+23, paint);
for (int i=0;i<n;i++)
canvas.drawBitmap(star,i*30+90,y,null);
}
}
「練習問題 2-13」star メソッドの引数に描画色を示す「Paint paint」引数を追加しなさい。
private class GView extends View {
private Paint paint;
private Bitmap star;
public GView(Context context) {
super(context);
paint=new Paint();
star=BitmapFactory.decodeResource(getResources(),R.drawable.star);
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setTextSize(30);
star(canvas,paint,10,"価格:",3);
paint.setColor(Color.RED);
star(canvas,paint,40,"品質:",5);
}
①
private void star(Canvas canvas,
canvas.drawText(msg,0,y+23,
②
,int y,String msg,int n){
);
for (int i=0;i<n;i++)
canvas.drawBitmap(star,i*30+90,y,null);
}
}
2-14 メンバ変数
メソッド内で宣言した変数(オブジェクト)はそのメソッド内でのみ使用できます。こ
れをローカル変数と呼びます。複数のメソッドで共通に使う変数(オブジェクト)はクラ
ス定義の先頭で、メソッドの外で宣言します。これをメンバ変数と呼びます。
private class クラス名 {
メンバ変数(オブジェクト)の宣言
private メソッド名 1() {
ローカル変数の宣言
}
private メソッド名 2() {
ローカル変数の宣言
}
}
メンバ変数のアクセス属性は通常「private」指定します。
private float LPX=0,LPY=0; // メンバ変数
private 指定しなくても private として扱われますが、本書では「private」指定を明示し
ています。private は外部に対し非公開、public は外部に対し公開を意味します。ローカル
変数にはアクセス属性は指定しません。
「注」アクセス属性
メソッドやオブジェクトの使用権限を private や public といったアクセス属性により指
定できます。
アクセス属性
意味
public
どこからでも使用できる。
protected
このメソッドまたはオブジェクトを定義しているクラスとサブクラスか
ら使用できる。
private
このメソッドまたはオブジェクトを定義しているクラスのみから使用で
きる。
「注」paint はすでにメンバ変数として使用してきました。
「例題 2-14」描画現在位置を移動する moveTo メソッドと現在位置から指定点まで直線を
描く lineTo メソッドを作り、これらを使用して M の文字を描きます。現在位置を示す座標
の LPX と LPY をメンバ変数とします。
private class GView extends View {
private Paint paint;
private float LPX=0,LPY=0; // メンバ変数
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
float[] x={30,30,120,210,210,-1};
float[] y={210,30,120,30,210,-1};
int i=0;
while (x[i]!=-1){
if (i==0)
moveTo(x[i],y[i]);
else
lineTo(canvas,x[i],y[i]);
i++;
}
}
private void moveTo(float x,float y){
LPX=x;LPY=y;
}
private void lineTo(Canvas canvas,float x,float y){
paint.setColor(Color.BLUE);
canvas.drawLine(LPX,LPY,x,y,paint);
LPX=x;LPY=y;
}
}
「練習問題 2-14」lineTo メソッドの canvas 引数をメンバ変数で代替えしなさい。
private class GView extends View {
①
private
private Paint paint;
private float LPX=0,LPY=0; // メンバ変数
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
mCanvas= ②
paint.setColor(Color.BLUE);
float[] x={30,30,120,210,210,-1};
float[] y={210,30,120,30,210,-1};
int i=0;
while (x[i]!=-1){
if (i==0)
moveTo(x[i],y[i]);
else
lineTo(x[i],y[i]);
i++;
}
}
private void moveTo(float x,float y){
LPX=x;LPY=y;
}
private void lineTo(float x,float y){
mCanvas.drawLine(LPX,LPY,x,y,paint);
LPX=x;LPY=y;
}
}
2-15 配列引数
メソッドに配列引数を渡すには、実引数は配列名のみを指定し、仮引数は要素数を指定
しない配列宣言を指定します。たとえばの disp に一次元配列 x[ ]を渡すには以下のように
します。仮引数の名前は x でなく別の名前でもよいです。受け取った配列の要素数は
「x.length」で取得できます。
float[] x={30,30,120,210,210};
disp(x);
private void disp(float[] x){
}
「例題 2-15」M の各点の座標データの x[ ]と y[ ]を lines メソッドに渡して描画します。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
float[] x={30,30,120,210,210};
float[] y={210,30,120,30,210};
paint.setColor(Color.BLUE);
lines(canvas,paint,x,y);
}
private void lines(Canvas canvas,Paint paint,float[] x,float[] y){
int n=x.length;
for (int i=0;i<n-1;i++){
canvas.drawLine(x[i],y[i],x[i+1],y[i+1],paint);
}
}
}
2 次元配列を渡すには以下のようにします。受け取った配列の行要素数は「p.length」
、
列要素数は「p[0].length」で取得できます。
float[][] p={{30,210},{30,30},{120,120},{210,30},{210,210}};
disp(p);
private void disp(float[][] p){
}
「練習問題 2-15」M のデータを{x,y}を要素とする 2 次元配列で表し、このデータを lines
に渡して描画します。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
float[][] p={{30,210},{30,30},{120,120},{210,30},{210,210}};
paint.setColor(Color.BLUE);
lines(canvas,paint, ①
);
}
private void lines(Canvas canvas,Paint paint,
②
){
int n=p.length;
for (int i=0;i<n-1;i++){
canvas.drawLine(p[i][0],p[i][1],p[i+1][0],p[i+1][1],paint);
}
}
}
2-16 Math クラス
Math クラスは三角関数、指数関数、対数関数、平方根などの数値計算を行うための Java
の標準クラスです。
java.lang パッケージに含まれるため import 文は必要ありません。Math
クラスのメソッドは static メソッドで構成されています。このため、個々のオブジェクト
を生成せずにデフォルトで生成されいる静的なインスタンス(クラス名のインスタンス)
の Math に対して「Math.sin」や「Math.cos」のように使用します。
Math クラスの主な static メソッドとして以下があります。
メソッド
機能
double sin(double x)
x のサイン。
double cos(double x)
x のコサイン。
double tan(double x)
x のタンジェント。
double asin(double x)
x のアークサイン。
double acos(double x)
x のアークコサイン。
double atan(double x)
x のアークタンジェント。
double exp(double x)
x の指数。ex。
double sqrt(double x)
x の平方根。√x。
double log(double x)
x の自然対数。logex。
double pow(double x,double y)
x の累乗。xy。
double IEEEremainder(double
x÷y の余り。
x,double y)
double ceil(double x)
x を数直線上で右方向へ整数化した値を返す。切り上げ。
double floor(double x)
x を数直線上で左方向へ整数化した値を返す。切り下げ。
double round(double x)
x を四捨五入した値を返す。
double random()
0.0~1.0 未満の乱数を 1 つ返す。
PI
πの値。PI はメソッドでなくフィールド。
1.
三角関数とラジアン
三角関数の sin,cos,tan,asin,acos,atan に与えるデータは度でなくラジアンという単位を
使います。ラジアンという単位は、半径 1 の単位円において、角度に対応する円弧の長さ
を指します。半径 1 の円の 180°がπラジアンに相当しますので、x°をラジアンに直すに
は「x*Math.PI/180」とします。
「例題 2-16-1」(150,150)を中心に半径 120 の円周を想定します。この円周上を 20°ごとに
取った点と中心を直線で結びます。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
float x,y;
for (int i=0;i<360;i+=20){
x=(float)(120*Math.cos(i*Math.PI/180)+150);
y=(float)(120*Math.sin(i*Math.PI/180)+150);
canvas.drawLine(150,150,x,y,paint);
}
}
}
「練習問題 2-16-1」y=sin(x)のサインカーブを描きなさい。x を 0°~360°まで 5°おきに
変化させたときの(x,y)の各点を直線で結びます。sin の値は-1.0~1.0 の範囲なので 120 倍
した値を y 座標とします。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
float x,y,LPX=0,LPY=0;
for (x=0;x<=360;x+=5){
y=(float)(150-120*Math.sin(x*Math.PI/180));
if (
①
)
canvas.drawLine(
LPX=x;LPY=y;
}
}
}
②
,paint);
2.
乱数
Math.random()は 0.0~1.0 未満の乱数を 1 つ返します。0~400 未満の乱数を x に取得す
るには以下のようにします。random()が返す値は double 型なので、float 型の x に代入す
るには(float)でキャストする必要があります。
x=(float)(400*Math.random());
「注」キャスト
キャストとはオペランドの型を、それが評価されるときだけ一時的に変えることをいい
ます。キャストは一時的に変えたい型を()で囲んでオペランドの前に指定します。
(型)オペランド
「例題 2-16-2」乱数で円の中心位置と半径を求めて、30 個の円を描画します。円は
drawCircle メソッドで描画します。paint.setStyle(Style.STROKE);を設定しなければ円の
中が塗られます。Style.STROKE を使用するため「import android.graphics.Paint.Style;」
が必要です。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setStyle(Style.STROKE);
float x,y,r;
for (int i=0;i<30;i++){
x=(float)(400*Math.random());
y=(float)(400*Math.random());
r=(float)(50*Math.random());
canvas.drawCircle(x,y,r,paint);
}
}
}
「練習問題 2-16-2」中心(230,230)、半径 160 の円周上に 20°おきに乱数で半径を求めた円
を描きなさい。
「import android.graphics.Paint.Style;」が必要です。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setStyle(Style.STROKE);
float x,y,r;
for (int i=0;i<360;i+=20){
x=(float)(160*
①
+230);
y=(float)(160*
②
+230);
r=(float)(50*Math.random());
canvas.drawCircle(x,y,r,paint);
}
}
}
☆応用サンプル ダイアモンドリング
半径 r の円の円周を N 等分し、各点をすべて結ぶとダイアモンドリングと呼ばれる図形
が得られます。円周上の i 番目の点の座標は次式で求められます。
x1=(float)(cx+r*Math.cos(i*2*Math.PI/N)); // 始点
y1=(float)(cy-r*Math.sin(i*2*Math.PI/N));
N 等分したときの角は 2π/N となります。cx,cy は円の中心座標とします。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
int N=16; // 分割数
float x1,y1,x2,y2,cx=200,cy=200,r=180;
paint.setColor(Color.BLUE);
for (int i=0;i<N-1;i++){
x1=(float)(cx+r*Math.cos(i*2*Math.PI/N)); // 始点
y1=(float)(cy-r*Math.sin(i*2*Math.PI/N));
for (int j=i+1;j<N;j++){
x2=(float)(cx+r*Math.cos(j*2*Math.PI/N)); // 終点
y2=(float)(cy-r*Math.sin(j*2*Math.PI/N));
canvas.drawLine(x1,y1,x2,y2,paint);
}
}
}
}
☆応用サンプル モンテカルロ法によるπ
0~1 の一様乱数を2つ発生させ、それらを x,y とします。こうした乱数の組をいくつか
発生させると、1×1 の正方形の中に(x,y)で示される点は均一にばらまかれると考えられま
す。したがって、正方形の面積と 1/4 円の面積の比は、そこにばら撒かれた乱数の数に比
例するはずです。今、1/4 円の中にばらまかれた乱数の数を a、円外にばらまかれた乱数
の数を b とすると、次の関係が成立します。
π/4:1=a:a+b
∴π=4a/(a+b)=4a/n
n は発生した乱数の総数。
「import android.graphics.Paint.Style;」が必要です。
private class GView extends View {
private Paint paint;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
paint.setStyle(Style.STROKE);
int sum=0,N=5000;
float x,y,pai;
canvas.drawRect(0,10,150,160, paint);
for (int i=0;i<N;i++){
x=(float)Math.random();
y=(float)Math.random();
if (x*x+y*y<1){
sum++;
canvas.drawPoint(150*x,160-150*y, paint);
}
}
pai=(float)4*sum/N;
paint.setTextSize(30);
canvas.drawText("π="+pai,0,200,paint);
}
}
☆応用サンプル タートルグラフィックス
長さと角度を与えて直線を引くメソッド move と現在角を回転するメソッド turn を作り
ます。このような move や turn を使って描く図形をタートル・グラフィックスと呼びます。
・move メソッド
描画の現在位置を(LPX,LPY)、現在角を ANGLE とすると、そこから長さ leng の直
線を引く場合の終点座標(x,y)は以下の計算式から得られます。ANGLE 度をラジアンに変換
するために「Math.PI/180」を乗じます。cos、sin は Math クラスの static メソッドです。
float x=LPX+(float)(leng*Math.cos(ANGLE*Math.PI/180));
float y=LPY-(float)(leng*Math.sin(ANGLE*Math.PI/180));
・turn メソッド
現在角 ANGLE を a°回転します。ANGLE の値が 0~360°に入るように
ANGLE=Math.IEEEremainder(ANGLE,360.0);
という式で補正します。
private class GView extends View {
private Paint paint;
private float LPX,LPY,ANGLE;
public GView(Context context) {
super(context);
paint=new Paint();
}
protected void onDraw(Canvas canvas) {
paint.setColor(Color.BLUE);
for (int n=3;n<=9;n++){
LPX=180;LPY=400;ANGLE=0;
for (int i=1;i<=n;i++){
move(canvas,120f,paint);
turn(360.0f/n);
}
}
}
private void move(Canvas canvas,float leng,Paint paint) {
float x=(float)(LPX+leng*Math.cos(ANGLE*Math.PI/180));
float y=(float)(LPY-leng*Math.sin(ANGLE*Math.PI/180));
canvas.drawLine(LPX,LPY,x,y, paint);
LPX=x;LPY=y;
}
private void turn(float a) {
ANGLE+=a;
ANGLE=(float)Math.IEEEremainder(ANGLE,360.0);
}
}
Fly UP