12/18 ネットワークプログラミング


前回までの補足


質問と回答

Q.
今回の課題に関しての質問です。

appletではイメージの読み込みの際に
Toolkit.getDefaultToolkit().getImage()
という方法は使えないということなのですが、Canvasにイメージを
読み込みたい時にはどうすればよいのでしょうか?

授業でやったのはinitのなかでAppletクラスのgetImageメソッド
を使うということだったのですが、Canvasのクラスを別につくって
いる場合どうすればいいのかよくわかりません。
A.
 良い質問ですね.Appletクラス以外はgetImageメソッドを呼べないわけです
が,Canvasの中でイメージを使いたいということであれば,いくつか方法があ
ります.

(1) CanvasのサブクラスのコンストラクタをImage型の引数を取って,インス
タンス変数に代入するように定義しておいて,Appletの initの中でgetImage
したものを渡してCanvasのコンストラクタを呼び出す.

-> 実装は簡単ですが最初に必要なイメージをすべてgetImageしておく必要が
あります.

(2) CanvasのサブクラスのコンストラクタをApplet型の引数を取ってインスタ
ンス変数に代入するように定義しておいて,Appletの initの中で自分を渡し
てCanvasのコンストラクタを呼び出す.Canvasの中でgetImageしたくなったら,
インスタンス変数のgetImageを呼び出す(publicなメソッドなので他のクラス
のメソッドからでも呼べます).

-> 必要に応じてgetImageできます.

(1),(2)に対応するサンプルを載せるので参考にしてください( (2)の方は,
paintが5回呼ばれてはじめて絵がでます.).

----------------------------------------------------------------------
// <applet code=TestApplet width=100 height=100>&;lt/applet>
import java.awt.*;
import java.applet.*;

class MyCanvas extends Canvas{
  Image myImage;
  MyCanvas(Image im){
    myImage=im;
    setSize(100,100);
  }
  public void paint(Graphics g){
    g.drawImage(myImage,0,0,this);
  }
}
public class TestApplet extends Applet{
  public void init(){
    setLayout(new FlowLayout());
    Canvas c=new MyCanvas(getImage(getCodeBase(),"test.gif"));
    add(c);
  }
}
----------------------------------------------------------------------
// <applet code=TestApplet1 width=100 height=100></applet>
import java.awt.*;
import java.applet.*;

class MyCanvas1 extends Canvas{
  Image myImage;
  Applet baseApplet;
  int count=0;
  MyCanvas1(Applet ap){
    setSize(100,100);
    baseApplet=ap;
  }
  public void paint(Graphics g){
    System.out.println("count="+count);
    count++;
    if(count>5 && myImage==null){
      myImage=baseApplet.getImage(baseApplet.getCodeBase(),"test.gif");
    }
    g.drawImage(myImage,0,0,this);
  }
}
public class TestApplet1 extends Applet{
  public void init(){
    setLayout(new FlowLayout());
    Canvas c=new MyCanvas1(this);
    add(c);
  }
}

Q.
ファイルからイメージをロードして、そのイメージのうえにマウスが動く
通りに線か書けるように、円を連続して書いてそれが線になるように
次のようなプログラミングを作ったのですが、線は書けず、円だけに
なってしまいます。線を書くにはどうしたらよいのですか?
また、qをおしても終了になりません。さらに、画面が2つ出てきてしまいます。
どうしたらよいでしょうか?
 

   // appletを使うため
import java.applet.*;
  // AWTを使うため,
import java.awt.*;
  // イベント駆動関係のクラスを用いるため
import java.awt.event.*;
  // Vectorクラスを用いるため
import java.util.*;

  //円のクラスを定義する。  
class  Center{
   //円の中心の x座標, y座標を intで保持する。
  public int x,y;
   //Centerのコンストラクタ
  public Center(int x1,int x2){
    x=x1;
    y=x2;  
  }
}
 
  //外側のFrameに直接paintするのではなく、お絵書き領域を作る。
class En extends Frame implements KeyListener, MouseMotionListener{
   //Centerの配列を保持するVectorクラスの変数 circleの宣言。
  Vector circle;
   //円の半径を2とする
  int r=2;
   //Image型の変数 bgの宣言
  Image bg;
   //表示する色を保持する変数を宣言 円の色は黒に。
  Color circleColor=Color.black;
   // コンストラクタの宣言
  public En(){
    super();
    circle =new Vector();   
    // GUI部品と,Event Listenerを関連づける
    setSize(300,300);
    addKeyListener(this);
    addMouseMotionListener(this);
  }
  Image offScreenImage;
  Graphics offScreenGraphics;
  public void update(Graphics g){
    if(offScreenImage==null){
      offScreenImage=createImage(600,450);
    // オフスクリーンイメージを600x450のサイズで作成
      offScreenGraphics=offScreenImage.getGraphics(); 
    // オフスクリーンイメージに描画するための Graphics オブジェクト
   }
    // 次の画面のイメージを作る.
    paint(offScreenGraphics); 
    // イメージを本物のスクリーンに書き込む
    g.drawImage(offScreenImage,0,0,this);
  }
   // offScreenImageの書き直しをする際に呼ばれる
  public void paint(Graphics g){
    int i;
    
     //イメージ bg を (100,100)を左上にして表示する。
   g.drawImage(bg,100,100,this);
      // 色を設定
    g.setColor(circleColor);
    int size=circle.size();
     for(i=0;i< size;i++){
     Center c=(Center)circle.elementAt(i);
      g.fillOval(c.x-r,c.y-r,2*r,2*r);
    }
   }
   // KeyListenerを実装するためのメソッド
  public void keyPressed(KeyEvent e){
     // イベントからキーのコードを取り出す
    int key=e.getKeyChar();
     // デバッグ用の表示
    System.out.println("keyPressed("+e+","+key+")");
     // 入力が 'q'の時は終了する
    if(key=='q') System.exit(0);
  }
   // 要らないイベントに対応するメソッドも中身は空で書いておく必要がある.
  public void keyReleased(KeyEvent e){}
  public void keyTyped(KeyEvent e){}
   // MouseListenerを実装するためのメソッド
  public void mousePressed(MouseEvent e){}
   // MouseMotionListenerを実装するためのメソッド
  public void mouseDragged(MouseEvent e){
     // マウスカーソルの位置を得る
    int mx=e.getX(),my=e.getY();
     // デバッグ用の表示
    System.out.println("mouseDrag("+e+","+mx+","+my+")");
    circle.addElement(new Center(mx,my));
    repaint();
  }
  public void mouseMoved(MouseEvent e){}
}

//アプレットはpublicでなければならない
public class Sen extends Applet{
  En frame;
  public void init(){
    frame=new En();
    frame.bg=getImage(getCodeBase(),"test.gif");
  }
  public void start(){
    frame.setVisible(true);
    //    frame.start();
  }
  public void stop(){
    frame.setVisible(false);
    //frame.stop();
  }
}
A.
 田中哲朗です.

 > ファイルからイメージをロードして、そのイメージのうえにマウスが動く
 > 通りに線か書けるように、円を連続して書いてそれが線になるように
 > 次のようなプログラミングを作ったのですが、線は書けず、円だけに
 > なってしまいます。線を書くにはどうしたらよいのですか?

 センターのUnix環境の appletviewer で実行する場合の動作だと思いますが,
オフスクリーンイメージを使うとpaintに時間がかかるため,次の mouseDrag
が呼ばれるまでの間にマウス座標が激しく動いてしまうということのようです.

 対策はいろいろあります.

・ オフスクリーンイメージをやめる.もしくは,クリッピングにより書き換
え領域を減らす.

・ とびとびの座標になった場合は,paintの中で間を補間してcircleの要素が
ないところにも円を描く.一番簡単なのは1次補間(線分で結ぶ)だが,スプラ
イン曲線で補間する方法もいろいろある.

 > また、qをおしても終了になりません。さらに、画面が2つ出てきてしまいます。
 > どうしたらよいでしょうか?

 Appletの中では System.exit を実行しても無視されます(厳密には security
violationの例外が発生する).終了したように見せたい場合は,
setVisible(false) をする位でしょうか.

 画面が2つ出るというのはわかりません.appletviewer を終了しないうちに,
別の appletviewer を起動してしまった場合はそうなりますが.
Q.
12月4日の課題を今週の火曜日に一応提出したのですが、
もう少し直そうと思って提出方法のところを読むと、

”アプレットとjavaソースプログラム(リンクも可),アプレットで使われるイメージファイルを含んだ説明用のHTMLファイルをUnixシステム上(「file:/home/ユー ザ名/...」でアクセス)かセンターのユーザ情報発信WWWサーバ上 (「http://user.ecc.u-tokyo.ac.jp/~ユーザ名/...」でアクセス)に作成”

とあるのですが、”説明用htmlファイル”というのは通常のhtmlファイルとは違うのですか?
A.
 通常のhtmlファイルです.内容として説明も含めてくださいという意味です.
現在提出されているものでも条件は満たすが,もう少し説明は多めの方がよかっ
たと思います(再提出の必要はありません).
Q.
Netscape中のイメージの色が化ける点はgifでは修正できるのですが,jpegでは駄目ですか?
A.
今のところはだめです.

12/4の課題について

今日の15:00の時点で50名が提出.目についたものをいくつか紹介する.

説明やソースへのリンクがないものは減点する.この場合も,締切りまでに 再提出すれば良い.

締切りは今日の 21:00.


最終課題について

1月20日(日) 21:00までに,冬休みと1月15日の講義時間を利用して,好きな 題材を選んで Java 言語でプログラムを作成し,そのプログラムの説明をする HTML 文書を作成しなさい.その上で,最終回の1月22日(火)に,教卓上のNCを使っ て,発表(デモンストレーションとプログラムの説明)をしてもらい(提出人数 によっては全員ではなくこちらの指定した人だけになると思います),それで 評価します.

今日の課題

report1218@tanaka.ecc.u-tokyo.ac.jp 宛に「最終課題でどんなプログラムを 作りたいか(後で変更をしても全然問題ない).そのためにはどのようなことを 勉強したいか(講義でやらなかった点など)」を200文字以上書いて,メールを 出すこと.
次に進む