第25週目課題

課題2501

下記のような表示を行う Swing のコンポーネント JapaneseFlag クラスをパッケージ j2.lesson12 に作成しなさい (表示される画像は多少の差異があってもよい)。


上記の画像には薄く透かしが入っているが、これは再現しないこと。

また、このクラスには引数をとらないコンストラクタを用意し、このコンポーネントの推奨サイズは、幅 300, 高さ 200 とすること。

j2.lesson12.JapaneseFlag クラスには main メソッドを用意し、main メソッドを起動することによってこのコンポーネントのみを貼り付けたウィンドウを表示すること。

手順

指定した箇所で必ずテストを行うこと。

  1. 詳細な擬似コードを作成する
  2. パッケージ j2.lesson12 にクラス JapaneseFlag を作成
  3. main メソッドを作成する
  4. アクションを記述するために必要なクラスが他にあれば、そちらも作成する
  5. テスト項目「JapaneseFlagに対する骨格テスト」をパス
  6. 各コンストラクタやメソッドにプログラムを書く
  7. テスト項目「JapaneseFlagに対する単体テスト」をパス

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), static メンバを作る際に static の指定がない
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

機能テスト

メッセージ 詳細
<機能テストの項目名> <機能テストの項目名> で、FAIL ボタンを押した

機能テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
起動直後のウィンドウ コンポーネントを貼り付けたウィンドウを表示した直後
起動直後のウィンドウにエッジ強調を行った 起動直後の状態にエッジ強調を行った画像を表示

課題2502

下記のような表示を行う Swing のコンポーネント FunctionPlotter クラスをパッケージ j2.lesson12 に作成しなさい (表示される画像は多少の差異があってもよい)。

下記の波形は、sin x [0 <= x <= 2π] を表している。


このコンポーネント上でマウスをクリックすると、次のように表示されている波形 (cos x [0 <= x <= 2π] を表示) が変化する。


さらにこの状態でクリックすると、クリックするたびに表示される画像が次のように変化していく (-sin x => -cos x)。



上記が表示されている状態でさらにマウスをクリックすると、最初の表示に戻る。


つまり、最初に sin x の波形を表示し、クリックされるたびに cos x, -sin x, -cos x, sinx, ... といった具合に変化させる。

上記の画像にはそれぞれ薄く透かしが入っているが、これは再現しないこと。

また、このクラスには引数をとらないコンストラクタを用意し、このコンポーネントの推奨サイズは 幅 240, 高さ 220 とすること。

j2.lesson12.FunctionPlotter クラスには main メソッドを用意し、main メソッドを起動することによってこのコンポーネントのみを貼り付けたウィンドウを表示すること。

手順

指定した箇所で必ずテストを行うこと。

  1. 詳細な擬似コードを作成する
  2. パッケージ j2.lesson12 にクラス FunctionPlotter を作成
  3. main メソッドを作成する
  4. アクションを記述するために必要なクラスが他にあれば、そちらも作成する
  5. テスト項目「FunctionPlotterに対する骨格テスト」をパス
  6. 各コンストラクタやメソッドにプログラムを書く
  7. テスト項目「FunctionPlotterに対する単体テスト」をパス

ヒント

y = f(x) で表されるような関数を画面上に表示するには、次のように Graphics オブジェクトを扱えばよい。

  1. 定義域 (x のとりうる範囲) を n 個に細かく分割し、順に x1 .. xn とおく
  2. (xi, f(xi)) から (xi+1, f(xi+1)) に直線を引く
  3. 2 を i = 1..n-1 まで繰り返す

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), static メンバを作る際に static の指定がない
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

機能テスト

メッセージ 詳細
<機能テストの項目名> <機能テストの項目名> で、FAIL ボタンを押した

機能テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
起動直後のウィンドウ コンポーネントを貼り付けたウィンドウを表示した直後
1 回目のクリックをした直後 起動直後の状態から、マウスを 1 回クリックした際に表示されるコンポーネント
2 回目のクリックをした直後 起動直後の状態から、マウスを 2 回クリックした際に表示されるコンポーネント
3 回目のクリックをした直後 起動直後の状態から、マウスを 3 回クリックした際に表示されるコンポーネント
4 回目のクリックをした直後 起動直後の状態から、マウスを 4 回クリックした際に表示されるコンポーネント
5 回目のクリックをした直後 起動直後の状態から、マウスを 5 回クリックした際に表示されるコンポーネント
6 回目のクリックをした直後 起動直後の状態から、マウスを 6 回クリックした際に表示されるコンポーネント
7 回目のクリックをした直後 起動直後の状態から、マウスを 7 回クリックした際に表示されるコンポーネント
8 回目のクリックをした直後 起動直後の状態から、マウスを 8 回クリックした際に表示されるコンポーネント
起動直後のウィンドウにエッジ強調を行った 起動直後の状態にエッジ強調を行った画像を表示

課題2503 (optional)

シェルピンスキーのギャスケット (下図を参照) を表示する Swing のコンポーネント FractalTriangle クラスをパッケージ j2.lesson12 に作成しなさい。

このコンポーネントは、ウィンドウに貼り付けられた際に次のような表示を行う。


上記の画像には薄く透かしが入っているが、これは再現しないこと。

また、このクラスには引数をとらないコンストラクタを用意し、このコンポーネントの推奨サイズは 幅 400, 高さ 300 とすること。

必要ならば、下記のクラスを使用してもよい

package j2.lesson12;

import java.awt.Graphics;

public class PlotterTurtle {

    private double x;
    private double y;
    private double direction;
    
    /**
     * インスタンスを生成する。
     * 初期値は、(x, y) に真上を向いた状態になっている。
     * @param x 初期位置 (x)
     * @param y 初期位置 (y)
     */
    public PlotterTurtle(double x, double y) {
        super();
        this.x = x;
        this.y = y;
        // 初期値は真上を向いている
        this.direction = Math.PI / 2;
    }
    
    /**
     * このインスタンスの現在位置を指定する。
     * @param x 現在位置 (x)
     * @param y 現在位置 (y)
     */
    public void setPosition(double x, double y) {
        this.x = x;
        this.y = y;
    }

    /**
     * このインスタンスの向いている方向をラジアンで指定する。
     * @param direction 方向 (ラジアン)
     */
    public void setDirection(double direction) {
        this.direction = direction;
    }
    
    /**
     * このインスタンスの向いている方向を時計回りに指定した角度 (ラジアン) だけ回転する。
     * @param angle 変更する角度
     * @return 回転後の自分自身
     */
    public PlotterTurtle turnRight(double angle) {
        this.direction += angle;

        // 方向を 0 以上 2*pi 未満の範囲に収める
        while (this.direction < 0) {
            this.direction += 2 * Math.PI;
        }
        while (this.direction >= 2 * Math.PI) {
            this.direction -= 2 * Math.PI;
        }
        return this;
    }
    
    /**
     * このインスタンスの向いている方向を反時計回りに指定した角度 (ラジアン) だけ回転する。
     * @param angle 変更する角度
     * @return 回転後の自分自身
     */
    public PlotterTurtle turnLeft(double angle) {
        return turnRight(-angle);
    }
    
    /**
     * このインスタンスを現在の向きへ、指定した長さだけ移動させる。
     * @param length 移動する長さ
     * @return 移動後の自分自身
     */
    public PlotterTurtle forward(double length) {
        double dx = length * Math.cos(this.direction);
        double dy = -length * Math.sin(this.direction);
        this.x += dx;
        this.y += dy;
        return this;
    }
    
    /**
     * このインスタンスを現在の向きとは逆の方向へ、指定した長さだけ移動させる。
     * @param length 移動する長さ
     * @return 移動後の自分自身
     */
    public PlotterTurtle back(double length) {
        return forward(-length);
    }
    
    /**
     * このインスタンスを現在の向きへ指定した長さだけ移動し、移動時の経路に線を引く。
     * @param g 描画のためのオブジェクト
     * @param length 移動する長さ
     * @return 移動後の自分自身
     */
    public PlotterTurtle draw(Graphics g, double length) {
        double dx = length * Math.cos(this.direction);
        double dy = -length * Math.sin(this.direction);
        
        g.drawLine(
            (int)this.x,
            (int)this.y,
            (int)(this.x + dx),
            (int)(this.y + dy));
        
        this.x += dx;
        this.y += dy;
        return this;
    }
}

上記は、コンポーネント上を動き回る亀のようなオブジェクトを表すクラスで、次のようなことができる。

PlotterTurtle クラスを使った例を示す。

package j2.lesson12;

import java.awt.*;

import javax.swing.*;

public class FractalTree extends JComponent {

    protected void paintComponent(Graphics g) {
        g.clearRect(0, 0, getWidth(), getHeight());
        
        // 中央の一番下から枝を生やす
        PlotterTurtle t = new PlotterTurtle(getWidth() / 2, getHeight() - 1);
        // 最初の枝の長さは 高さ / 3
        treeDrawBranch(t, g, getHeight() / 3);
    }
    
    // 枝と、そこから分岐する枝を描く
    private void treeDrawBranch(PlotterTurtle t, Graphics g, double length) {
        // 枝の長さが1未満になったら終了
        if (length < 1) {
            return;
        }
        // length だけ枝を描く
        t.draw(g, length);
        // 右に40度回って再帰呼び出し
        t.turnRight(Math.PI / 9 * 2);
        treeDrawBranch(t, g, length * 0.7);
        // 左に80度回って再帰呼び出し
        t.turnLeft(Math.PI / 9 * 4);
        treeDrawBranch(t, g, length * 0.7);
        // 右に40度回って後ろにlength だけ戻る
        t.turnRight(Math.PI / 9 * 2).back(length);
    }

    public Dimension getPreferredSize() {
        return new Dimension(400, 300);
    }
    
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setUndecorated(true);
        frame.setTitle("fractal tree");
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(new JScrollPane(new FractalTree()));
        frame.pack();
        frame.setVisible(true);
    }
}

上記のプログラムを実行すると、次のような模様が表示される。


j2.lesson12.FractalTriangle クラスには main メソッドを用意し、main メソッドを起動することによってこのコンポーネントのみを貼り付けたウィンドウを表示すること。

手順

指定した箇所で必ずテストを行うこと。

  1. 詳細な擬似コードを作成する
  2. パッケージ j2.lesson12 にクラス FractalTriangle を作成
  3. main メソッドを作成する
  4. アクションを記述するために必要なクラスが他にあれば、そちらも作成する
  5. テスト項目「FractalTriangleに対する骨格テスト」をパス
  6. 各コンストラクタやメソッドにプログラムを書く
  7. テスト項目「FractalTriangleに対する単体テスト」をパス

ヒント

シェルピンスキーのギャスケットは、次のような三角形である。

  1. 最初に、一番大きな三角形を書く
  2. 三角形の中点を結ぶ各辺が半分の三角形を描く
  3. 2 で描いた三角形によって新しくできた 4 つの三角形のうち、中央のものを除いた 3 つの三角形に対して 2, 3 を適用する

「シェルピンスキーのギャスケット」で検索をすれば多数の情報を得られる。

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), static メンバを作る際に static の指定がない
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

機能テスト

メッセージ 詳細
<機能テストの項目名> <機能テストの項目名> で、FAIL ボタンを押した

機能テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
起動直後のウィンドウ コンポーネントを貼り付けたウィンドウを表示した直後
起動直後のウィンドウにエッジ強調を行った 起動直後の状態にエッジ強調を行った画像を表示

課題2504 (optional)

ボタンのような動作をする Swing のコンポーネント CustomButton クラスをパッケージ j2.lesson12 に作成しなさい。

このコンポーネントは、コンストラクタの引数に "test" という文字列を渡してインスタンスを生成し、それをウィンドウに貼り付けると次のように表示される (test と表示する位置はコンポーネント内であれば任意でよい)。


そして、このコンポーネント上でマウスのボタンを押すと、次のように色が変化する。


マウスのボタンを離すと、次のように色が最初の状態に戻る。


この「コンポーネント上でマウスのボタンを押して離す」という動作をした場合、ActionEvent が発生する。このイベントを受信するリスナを登録するためのメソッド addActionListener(ActionListener) を用意すること。

また、このコンポーネントの推奨サイズは、幅 100, 高さ 30 とする (ボタンに表示する文字列によってサイズを決定してもよいが、難しいので 100x30 に固定してよい)。

詳しく書くと、このクラスは次のようなコンストラクタやメソッドを持つ。

javax.swing.AbstractButton を継承すれば簡単に作成できるが、今回はこのクラスを作成しないこと。

また、このコンポーネントの推奨サイズは、幅 100, 高さ 30 とすること。

j2.lesson12.CustomButton クラスには main メソッドを用意し、main メソッドを起動することによってこのコンポーネントのみを貼り付けたウィンドウを表示すること。

手順

指定した箇所で必ずテストを行うこと。

  1. 詳細な擬似コードを作成する
  2. パッケージ j2.lesson12 にクラス CustomButton を作成
  3. main メソッドを作成する
  4. アクションを記述するために必要なクラスが他にあれば、そちらも作成する
  5. テスト項目「CustomButtonに対する骨格テスト」をパス
  6. 各コンストラクタやメソッドにプログラムを書く
  7. テスト項目「CustomButtonに対する単体テスト」をパス

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), static メンバを作る際に static の指定がない
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

機能テスト

メッセージ 詳細
AbstractButton javax.swing.AbstractButton を継承している (今回の課題では間接的にでも継承しないこと)
アクションイベントが発生した回数が異なります (1) アクションを発生させないボタンを押した直後
アクションイベントが発生した回数が異なります (2) (1) からアクションを発生させるボタンを押した直後
アクションイベントが発生した回数が異なります (3) (2) からアクションを発生させないボタンを押した直後
アクションイベントが発生した回数が異なります (4) (3) からアクションを発生させるボタンを押した直後
アクションイベントが発生した回数が異なります (5) (4) からアクションを発生させないボタンを押した直後
アクションイベントが発生した回数が異なります (6) (5) から両方のボタンを押した直後
<機能テストの項目名> <機能テストの項目名> で、FAIL ボタンを押した

機能テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
起動直後のウィンドウ コンポーネントを上下に2つ ("何もしない", "アクション") 貼り付けたウィンドウを表示した直後
アクションを受信しないボタン (上部のボタン) を押した 上部のボタンを押した状態の表示
アクションを受信しないボタン (上部のボタン) を離した 上部のボタンを押した後に離した状態の表示
アクションを受信するボタン (下部のボタン) を押した 下部のボタンを押した状態の表示
アクションを受信するボタン (下部のボタン) を離した 下部のボタンを押した後に離した状態の表示