「Java謎+落とし穴徹底解明」X-Drawのソースに関するバグ

このページは、拙書「Java謎+落とし穴徹底解明」の p.213からのX-Drawソースに関する正誤表です。

原因を記述しやすいよう、正誤表とは別ページとしました。 このページからダウンロードできるソースでは、バグはFIXされています。

発見の日付順に並んでいます(新しい方が下)。


右ボタンドラッグで変なものが出る(2001/12/24)

Circle, Rectangleを選択してから、右ボタンでドラッグすると、 ラバーバンドだけが表示されます。

訂正箇所:DrawWindow.javaのmouseReleased()メソッド

  if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
      button = DrawWindowListener.BUTTON1;
  } else if ((e.getModifiers() & InputEvent.BUTTON2_MASK) != 0) {
      button = DrawWindowListener.BUTTON2;
  } else {

  if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
      button = DrawWindowListener.BUTTON1;
  } else if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0) {
      button = DrawWindowListener.BUTTON2;
  } else {

UNIXと3ボタンマウスの環境なら、 BUTTON2_MASKが中央ボタンとして解釈されますが、 Windowsの場合右ボタンはBUTTON3_MASKになります。

最初の開発をLinux上で行ない、 あとでWindowsに持っていったときにここだけ直し忘れました。


カーソルを動かしながらボタンを操作すると変なものが出る(2001/12/24)

マウスカーソルを動かしながらボタンを押したり離したりした時、 環境によって、最後の座標(ボタンを押したり離したりした座標)に対して MouseMotionListenerが呼び出されないものがあるようです。

書籍掲載版のX-Drawでは、最後の座標までイベントが来ることを前提として、 最後のラバーバンドの消去を行なわなかった(どうせ確定した図形に 上書きされると考えた)ため、 すばやく図形を描画すると最後のラバーバンドが残ります。

直すには、図形確定の際に最後のラバーバンドを消すようにします。

訂正箇所:
PolylineCommand.javaのmouseButtonPressed()メソッド

  } else if (this.currentMode == DRAWING_MODE) {
      drawRubberBand(d, this.prevX, this.prevY); // 1行追加
      d.drawLine(this.points[this.points.length-1].getX(),

CircleCommand.javaのmouseButtonReleased()メソッド

  if (this.currentMode != DRAGGING_MODE) {
      this.currentMode = INITIAL_MODE;
      return;
  }
  d.setXORMode(true); // 3行追加
  d.drawCircle(this.centerX, this.centerY, this.prevRadius);
  d.setXORMode(false);

  double radius = calcDistance(this.centerX, this.centerY, x, y);

RectangleCommand.javaのmouseButtonReleased()メソッド

  if (this.currentMode != DRAGGING_MODE) {
      this.currentMode = INITIAL_MODE;
      return;
  }
  d.setXORMode(true); // 3行追加
  d.drawRectangle(this.startX, this.startY, this.prevX, this.prevY);
  d.setXORMode(false);
  d.drawRectangle(this.startX, this.startY, x, y);

iimport(2001/12/27)

p.213 の最初が

iimport java.applet.Applet;

となっていますが、これはもちろん

import java.applet.Applet;

の間違いです。

ポリラインをすばやく描くと変なものが出る(2002/1/12)

12/14のバグと原因は同じですが、修正漏れがありました。

ポリラインの途中の点を指示した直後にカーソルが動くとその点に対して MouseMotionListenerが呼び出されないため、

訂正箇所:
PolylineCommand.javaのmouseButtonPressed()メソッド末尾

 if (button == DrawWindowListener.BUTTON2) {
     shapeCollection.addShape(new Polyline(this.points));
     this.currentMode = INITIAL_MODE;
 } else {
     this.currentMode = DRAWING_START_MODE;
 }

第2刷における修正(2002/1/12)

おかげさまで「Java謎+落とし穴徹底解明」の増刷(第2刷)が決まりましたので、 いくつか気になったところを修正しておきます。

XDrawApplet.javaの80行目付近:

  private class XDrawWindowAdapter extends WindowAdapter {

他の箇所に合わせて、privateを付けておきます。

DrawWindow.java冒頭:

class DrawWindow implements Drawable, MouseListener, MouseMotionListener {
    // 座標変換←削除
    private double	xMin;

どうも意味不明のコメントなので、削ってしまいました。 確かに、この周辺のフィールドは座標変換に使われてはいるのですが...

掲示板の方で、内部クラスからその外側のクラスのフィールドを参照する時、 一箇所だけ「XDrawApplet.this.shapeCollection」 という書き方を使っているところがある、とのご指摘をいただきましたが、 これはそのままにしておきます。 p.295で説明している書き方の例ということで。


座標変換に関するバグ(2003/7/6)

デバイス座標系とワールド座標系の変換部分にバグがありました。

サンプルソースでは、ワールド座標系のxMin, yMinを 0にしているため発現しませんが、以下のソースが正解です。 ご迷惑をおかけしました。

    // ワールド座標系からデバイス座標系に変換する
    private int wcToDcX(double wX) {
        return (int)((wX - this.xMin) * scale);
    }
    private int wcToDcY(double wY) {
        return (int)((wY - this.yMin) * scale);
    }
    private int wcToDcLength(double wLength) {
        return (int)(wLength * this.scale);
    }

    // デバイス座標系からワールド座標系に変換する
    private double dcToWcX(int dX) {
        return dX / this.scale + this.xMin;
    }
    private double dcToWcY(int dY) {
        return dY / this.scale + this.yMin;
    }

第4刷では修正されています。


正誤表に戻る | 「Java謎+落とし穴徹底解明」のページに戻る | トップページに戻る