[an error occurred while processing this directive]
[an error occurred while processing this directive]
(2) 画像をロードして、表示する
画像をアップしたディレクトリのファイル一覧 (
こんなの) を読み込んで、画像のパスを取得します。
リンクなっていて、.jpg または .JPG で終わるファイル一覧を取得し、ロードします。
画像の URL はソースコードに決め打ちです。
前回 から変わったのは、以下の6点です。
- 定数を Env クラスに分離した
- 画像リストを取得する部分が増えた
- アイコンをリストで管理する IconList クラスを追加した
- アイコンの位置を管理する IconPosition クラスと PiledPosition クラスを追加した
- 画像のまわりにアイコンがたくさんあるので、位置を管理する PiledPosition クラスや、たくさんのアイコンをリストで管理する IconList クラスを追加した
- 画像のまわりに透明な枠を描くようにした
[New] Env: 色々な定数を入れるクラス
定数をまとめたクラスです。グローバル変数的に使っています。
class Env {
public static int W, H;
public static double WH_RATIO;
public static String URL;
/** 各種パラメータのデフォルト値を設定 */
static {
W = 800;
H = 600;
WH_RATIO = 1.333333;
URL = "http://funini.com/kei/ivy/narita/";
}
}
Ivylet: メインのアプレットのクラス
アプレットのメインのクラスです。
新しく増えたところは色を変えました。
extractPaths() の引数に URL (例えばHttp://funini.com/kei/ivy/narita/)を入れると、画像のパスのリスト
(例えば ["http://funini.com/kei/ivy/narita/00.jpg", "http://funini.com/kei/ivy/narita/01.jpg",..]
が返ってきます。
extractFiles() は、BufferedReader から一行ずつ読み、得られた画像の URL をfiles に追加していきます。
public class Ivylet extends JApplet {
public void init() {
String[] imgPaths = extractPaths(Env.URL);
IvyPanel tp = new IvyPanel(imgPaths);
setContentPane(tp);
}
/** 指定されたパスから、画像の URL 一覧を取得 */
public String[] extractPaths(String urlStr) {
// urlBase には、URLの / 以前の部分が入る ( http://funini.com/kei/ など)
String urlBase = urlStr.substring(0, urlStr.lastIndexOf("/") + 1);
ArrayList files = new ArrayList();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(
new URL(urlStr).openConnection().getInputStream()));
extractFiles(files, urlBase, br);
} catch (IOException ie) {
ie.printStackTrace();
}
return (String[]) files.toArray(new String[0]);
}
/** br から全体を読み込み、画像の URL 一覧を取得 */
void extractFiles(ArrayList files, String urlBase, BufferedReader br) throws IOException{
Pattern pattern = Pattern.compile("^(.+\\.(jpg|JPG))<.*");
for(;;) {
String line = br.readLine();
if(line == null) break;
String[] targets = line.split(">");
for(int i = 0; i < targets.length; i++) {
Matcher m = pattern.matcher(targets[i]);
if(m.matches()) files.add(urlBase + m.group(1));
}
}
}
}
IvyPanel: メインのパネル
メインのパネルです。
前回から変わったのは、アイコンが 1 つだけだったのが、アイコンのリストになっただけです。
class IvyPanel extends JPanel {
IconList iconList; // 各画像の重ね順です。
public IvyPanel(String[] urls) {
/** コンストラクタ 引数は画像が入っているパス */
setBackground(new Color(0x33, 0x33, 0x33)); // 背景色設定
setPreferredSize(new Dimension(Env.W, Env.H)); // サイズ設定
iconList = new IconList(urls);
}
/** 描画を行う */
public void paintComponent(Graphics g) {
super.paintComponent(g); // ウィンドウを表示
Graphics2D g2 = (Graphics2D) g; // アンチエイリアスの設定など
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for(int i = 0; i < iconList.size(); i++)
iconList.get(i).draw(g2); // 各アイコンを表示
}
}
[New] IconList: アイコンのリスト、重ね順、位置リストなどを保持するクラス
新しく増えたクラスです。アイコンのリストを持ちます。また、後に出てくる PiledPosition (各アイコンの大きさ・場所を持つクラス)のインスタンスを持っていて、
pile() メソッドでそれぞれのアイコンの場所・大きさをセットできます。
全てのアイコンはIcon[] icons という配列に格納されていて、この順番がアイコンの番号になっています。
また、int[] ordersという変数には重なっている順番が入っていて、この順番が描画の順番になっています。(orders[0] に入っている番号のアイコンが一番最初に描画される)
このことは上のIvyPanel.paintComponent() に書いてあります。
class IconList {
int nIcons; // アイコンの数
Icon[] icons; // アイコン (画像1枚につき、一つのアイコンです)
int[] orders;
PiledPosition piledPos; // 重ねた表示の時の各画像の位置
public IconList(String[] imgPaths) {
/** 引数: ロードされた画像リスト */
nIcons = imgPaths.length;
icons = new Icon[nIcons];
for(int i = 0; i < nIcons; i++)
icons[i] = new Icon(imgPaths[i]);
orders = new int[nIcons];
piledPos = new PiledPosition(nIcons);// 一覧表示での位置を計算
pile(); // 初期表示(重ね表示)に移行
}
/** 重ね表示にアイコンを移動 */
public void pile() {
for(int i = 0; i < nIcons; i++) {
// 重ね順を設定。orders は描画順なので、一番新しい画像を最後にする
orders[i] = nIcons - i - 1;
icons[i].setPosition(piledPos.getPos(i));
}
}
/** アイコンの数を返すメソッド */
public int size() { return nIcons; }
/** 重ね順が(下から) i 番目のアイコンを返すメソッド */
public Icon get(int i){ return icons[orders[i]]; }
}
[New] IconPosition: アイコンの位置を持つクラス
アイコンの位置を持つクラスです。アイコン N 個それぞれに対応したx, w, w, h (x y 座標、幅・ 高さ)を保持します。
getPos() メソッドで、指定された番号のアイコンのx, y, w, hを長さ4の配列に入れて返します。
今回はアイコンを重ねて表示するモードしか作っていませんが、後ほど別の表示モードも作るので、まずどんな配置でも
共通なクラスをまとめて IconPosition クラスを作りました。
abstract class IconPosition {
/** 各アイコンの配置を示すクラス */
int[] X, Y; // アイコンの X, Y, W, H
int w, h;
public IconPosition(int n) {
/** 各アイコンの座標、大きさ */
X = new int[n];
Y = new int[n];
}
/** 指定されたインデックスのアイコン位置を返す */
public int[] getPos(int i)
{ return new int[] { X[i], Y[i], w, h }; }
/** 指定された幅/高さ 最大値を超えないように、幅・高さを設定する */
public void setWH(int wMax, int hMax) {
w = wMax; // アイコンの(最大)幅
h = (int) ((double) w / Env.WH_RATIO); // アイコンの(最大)高さ
if(h > hMax) { // 幅を基準にしたら、高さがhMaxをはみ出てしまった場合
h = hMax;
w = (int) (h * Env.WH_RATIO);
}
}
}
[New] PiledPosition: 重ね表示 の時の位置情報を持つクラス
重ね表示の場所を決めています。
等間隔ではなく、手前に来るほど間隔があいて、しかも左上から右下に向けて配置するために
二次関数を使っています。それがX[i] = と Y[i] = という2行です。
class PiledPosition extends IconPosition {
int zw, zh;
/** コンストラクタ (引数: 画像の数) */
public PiledPosition(int n) {
super(n);
setWH(Env.W / 2, Env.H / 2);
X[0] = Env.W / 2 - Env.W / 10; // 一番手前のアイコンのX座標
Y[0] = Env.H / 2 - Env.H / 10; // 一番手前のアイコンのY座標
for(int i = 1; i < n; i++) {
X[i] = X[i - 1] - (int) ((10 - i) * (10 - i) * 0.9);
Y[i] = Y[i - 1] - (int) ((10 - i) * (10 - i) * 0.4 + 20);
}
}
}
Rect: パネルに置く色んな部品の基本クラス
ほぼ前回と同じですが、Color の変数を追加しました。
abstract class Rect {
int[] P; // X,Y座標, 幅、高さ
Image img;
int imgW, imgH; // 画像の幅、高さ
Color col;
public Rect(int x, int y, int w, int h) {
P = new int[] { x, y, w, h };
}
/** 画像をロード。path がhttp:// で始まる場合、HTTPで取得する */
public void loadImage(String path){
img = ImageLoader.load(path);
imgW = img.getWidth(null);
imgH = img.getHeight(null);
}
public void setPosition(int[] P){
for(int i = 0; i < 4; i++)
this.P[i] = P[i];
}
}
Icon: アイコンクラス
描画の部分で、周りに透明な枠を描いて、その中に少し余白をあけて画像を描くように変えました。
透明な枠を描くには、アルファ値を設定した Colorオブジェクトを作っています。new Color(0.85f, 0.85f, 0.75f, 0.3f) という行の一番最後の 0.3f が透明度です。
class Icon extends Rect {
public Icon(String imgPath) {
super(0, 0, 0, 0);
loadImage(imgPath);
col = new Color(0.85f, 0.85f, 0.75f, 0.3f);
}
/** アイコンを描画する */
void draw(Graphics2D g) {
g.setColor(col);
// アイコンの周りの、少し透明な枠を描画する
g.fillRect(P[0], P[1], P[2], P[3]);
// 少し余白をあけて、アイコンを描画する
int marginX = P[2] / 30;
int marginY = P[3] / 30;
g.drawImage(img, P[0] + marginX, P[1] + marginY, P[0] + P[2] - marginX,
P[1] + P[3] - marginY, 0, 0, imgW, imgH, null);
}
}
ImageLoader: 画像を読み込むためのクラス
前回から変更無しです。
class ImageLoader {
/** 画像をロード。path がhttp:// で始まる場合、HTTPで取得する */
public static Image load(String path) {
try {
if(path.startsWith("http://")){
URLConnection urlc = new URL(path).openConnection();
return ImageIO.read(urlc.getInputStream());
}
return ImageIO.read(new File(path));
} catch (IOException ie) { ie.printStackTrace();}
return null;
}
}
[an error occurred while processing this directive]