広告 |
---|
■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ 2012年02月09日 Java総合講座 - 初心者から達人へのパスポート 2009年11月開講コース 057号 セルゲイ・ランダウ バックナンバー: http://www.flsi.co.jp/Java_text/ ■□■□■□■□■□■□■□■□■□■□■□■□■□■□■ ------------------------------------------------------- ・現在、このメールマガジンは以下の2部構成になっています。 [1] 当初からのコース:vol.xxx(xxxは番号)が振られています。 これは現在、中級レベルになっています。 [2] 2009年11月開講コース:xxx号(xxxは番号)が振られています。 これは現在、初心者向けのレベルになっています。 ・このメールマガジンは、画面を最大化して見てください。 小さな画面で見ていると、不適切な位置で行が切れてしまう など、問題を起すことがあります。 ・このメールマガジンに掲載されているソース・コード及び 文章は特に断らない限り、すべて筆者が著作権を所有してい ます。また、これらのソース・コードは学習用のためだけに 提供しているものです。 ------------------------------------------------------- ======================================================== ◆ 01.グラフィックスのプログラミング ======================================================== さて前回の最後に、DrawingPanelのソース・コードの先頭のほうの private Point startPoint = null; private Point endPoint = null; についてふれましたが、これらのフィールドは、あとで直線や矩形 や楕円などの図形を描けるようにするために先行して定義しておいた ものでした。 今回は、お絵描きソフトにこの直線や矩形、楕円を描けるように 機能を追加していきます。 その前に、前回DrawingToolPanelに貼り付けたJList(strokeList) がちょっと好ましくない振る舞いをすることに気づいたでしょう か。 実は、現時点のこのstrokeListでは、複数選択ができてしまいます。 たとえばstrokeListの1行目をクリックし、Ctrlキーを押しながら 3行目をクリックすると1行目と3行目が同時に選択状態になりますし、 1行目をクリックし、Shiftキーを押しながら3行目をクリックすると 1行目から3行目までのすべてが同時に選択状態になります。 前回のソース・コードの編集内容ではJList上で1つの項目だけが 選択されることを前提にしていますので、複数選択ができてしま っては困ります。 複数選択ができてしまうのは、JListのselectionModeプロパティー がデフォルトでは「MULTIPLE_INTERVAL_SELECTION」になっている からです。 ではDrawingToolPanelのDesignビューを開き、JList(strokeList) をクリックし、Properties欄のselectionModeプロパティーを見て 下さい。 selectionModeプロパティーの値が「MULTIPLE_INTERVAL_SELECTION」 になっていますね。これを「SINGLE_SELECTION」に変更しましょう。 (値「MULTIPLE_INTERVAL_SELECTION」が表示されているところを クリックするとリストが表示されるので、その中の「SINGLE_SELECTION」 を選択する。) 保管して、再度DrawingToolAppletを起動してテストしてみてください。 今度は、複数選択はできなくなりましたね。 ┌補足─────────────────────────┐ JListのselectionModeプロパティーの値には、次の3種類が あります。 SINGLE_SELECTION 選択できるのは一つだけです。 SINGLE_INTERVAL_SELECTION 選択できるのは一つまたは、Shiftキーを押しながら指定で きる連続した範囲一つだけです。 MULTIPLE_INTERVAL_SELECTION 選択できるのは複数(Ctrlキーを押しながら選択すれば複数 指定できる)。またShiftキーを押しながら指定できる連続 した範囲も複数指定できます。 これらはListSelectionModelというjavax.swingパッケージにはい っているインターフェースにint型のフィールドとして定義されて います。(インターフェースのフィールドですからpublicでstatic でfinalです。) └───────────────────────────┘ ======================================================== では、お絵描きソフトに直線や矩形、楕円を描く機能を追加 する作業にはいりましょう。 以前お話しした通り、これらの図形は、それぞれDecoratedLine、 DecoratedRectangle、DecoratedEllipseというクラスで表現する ことにします。 これらDecoratedLine、DecoratedRectangle、DecoratedEllipse もDecoratedFreeCurveクラスと同様にDecoratedShapeのサブクラス として作成します。 さて、直線、矩形、楕円を表現するクラスとして、それぞれ Line2D、Rectangle(またはRectangle2D)、Ellipse2Dという クラスがJavaのAPIに用意されています。 (Line2D、Rectangle2D、Ellipse2Dはjava.awt.geomパッケージに はいっています。またRectangleはjava.awtパッケージにはいって います。) これらは055号でお話ししたShapeインターフェースを実装した 図形のクラスになっています。 したがって、これらもやはりDecoratedShapeクラスで扱うことが できます。 では、DecoratedLine、DecoratedRectangle、DecoratedEllipseを、 それぞれ下記のようなソース・コードにして作成して下さい。 すべて、パッケージjp.co.flsi.lecture.cgに作成します。 [DecoratedLineのソース・コード] -------------------------------------------------------- package jp.co.flsi.lecture.cg; import java.awt.geom.Line2D; public class DecoratedLine extends DecoratedShape { public DecoratedLine() { setShape(new Line2D.Float()); } public DecoratedLine(int x0, int y0, int x1, int y1) { setShape(new Line2D.Float(x0, y0, x1, y1)); } } -------------------------------------------------------- Line2D.Float()というのはコンストラクターで、4つの引数を持つものは、 前の2つの引数が線分の始点のx座標とy座標で、後ろの2つの引数が終点の x座標とy座標を指定するものです。 なお、Float()というのはLine2Dの内部に組み込まれた内部クラスですが、 他にDouble()という内部クラスもあります。そしてLine2Dというクラスは、 float型の座標値を使って図形を作成したいときはFloat()のコンストラク ターを使い、double型の座標値で図形を作成したいときはDouble()のコンス トラクターを使うという使い分け方式でインスタンス生成を行います。 なお、上のソース・コードの場合、引数はint型からfloat型へ暗黙の 型変換が行われますので、int型の変数を引数に与えても大丈夫です。 [DecoratedRectangleのソース・コード] -------------------------------------------------------- package jp.co.flsi.lecture.cg; import java.awt.Rectangle; public class DecoratedRectangle extends DecoratedShape { public DecoratedRectangle() { setShape(new Rectangle()); } public DecoratedRectangle(int x0, int y0, int width, int height) { setShape(new Rectangle(x0, y0, width, height)); } } -------------------------------------------------------- Rectangle()コンストラクターの4つの引数を持つものは、前の2つの引数 がその矩形(長方形や正方形)の始点のx座標とy座標で、後ろの2つの 引数が横幅と高さを指定するものです。なお、始点は矩形の左上の隅に 取られます。 [DecoratedEllipseのソース・コード] -------------------------------------------------------- package jp.co.flsi.lecture.cg; import java.awt.geom.Ellipse2D; public class DecoratedEllipse extends DecoratedShape { public DecoratedEllipse() { setShape(new Ellipse2D.Float()); } public DecoratedEllipse(int x0, int y0, int width, int height) { setShape(new Ellipse2D.Float(x0, y0, width, height)); } } -------------------------------------------------------- Ellipse2D.Float()コンストラクターの4つの引数を持つものは、その楕円 が内接する矩形に対し前の2つの引数がその矩形の始点のx座標とy座標で、 後ろの2つの引数が横幅と高さを指定するものです。なお、始点は矩形の 左上の隅に取られます。 以上、DecoratedLine、DecoratedRectangle、DecoratedEllipseはコンスト ラクターの定義しかなくて、他のメソッドはスーパークラス(DecoratedShape) のものを継承しているだけです。 つまり、これらのクラスは図形が異なることを除けは他の振る舞いはすべて 同じというわけです。 では、これらのクラスを使って図形を描けるようにDrawingPanelと DrawingToolPanelを編集しましょう。 まずは、DrawingPanelのソース・コードを以下のように編集しましょう。 (1) DrawingPanel()コンストラクターの中の -------------------------------------------------------- addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseDragged(MouseEvent e) { if(shapeType == ShapeEnum.FREECURVE) { pts[ptIndex] = new Point(e.getX(), e.getY()); ptIndex++; } repaint(); } }); -------------------------------------------------------- の部分を下記のように編集しましょう。 -------------------------------------------------------- addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseDragged(MouseEvent e) { if(shapeType == ShapeEnum.FREECURVE) { pts[ptIndex] = new Point(e.getX(), e.getY()); ptIndex++; } else { endPoint = new Point(e.getX(), e.getY()); } repaint(); } }); -------------------------------------------------------- elseのブロックが追加されただけですね。 自由曲線の場合はドラッグする途中の点(MouseEventが検出された点) をすべて記憶しておく必要がありますが、直線、矩形、楕円の場合は 始点(startPoint)と終点(endPoint)の2点だけ記憶すれば描けます から、(そのうちのstartPointはmousePressed()で記憶されていますので) endPointの記憶だけを行っています。 (2) paint()メソッド -------------------------------------------------------- public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; Image image = createImage(getSize().width, getSize().height); Graphics2D g2dImage = (Graphics2D) image.getGraphics(); DecoratedShape aShape = null; if(shapeType == ShapeEnum.FREECURVE) { aShape = new DecoratedFreeCurve(); if (ptIndex > 9) { ((GeneralPath)aShape.getShape()).moveTo(pts[0].x, pts[0].y); for(int i = 3; i < ptIndex - 6; i += 9) { ((DecoratedFreeCurve)aShape).addCurve(pts[i].x, pts[i].y, pts[i+3].x, pts[i+3].y, pts[i+6].x, pts[i+6].y); } } aShape.setColor(lineColor); aShape.setStroke(drawStroke); } if (aShape != null) { if (!mousePressed) { shapes.add(aShape); ptIndex = 0; } else { aShape.paintSelf(g2dImage); } } for (int i = 0; i < shapes.size(); i++) { shapes.get(i).paintSelf(g2dImage); } g2d.drawImage(image, 0, 0, getSize().width, getSize().height, null); } -------------------------------------------------------- を下記のように書き換えましょう -------------------------------------------------------- public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; Image image = createImage(getSize().width, getSize().height); Graphics2D g2dImage = (Graphics2D) image.getGraphics(); DecoratedShape aShape = null; if(shapeType == ShapeEnum.FREECURVE) { aShape = new DecoratedFreeCurve(); if (ptIndex > 9) { ((GeneralPath)aShape.getShape()).moveTo(pts[0].x, pts[0].y); for(int i = 3; i < ptIndex - 6; i += 9) { ((DecoratedFreeCurve)aShape).addCurve(pts[i].x, pts[i].y, pts[i+3].x, pts[i+3].y, pts[i+6].x, pts[i+6].y); } } aShape.setColor(lineColor); aShape.setStroke(drawStroke); } else if(endPoint != null) { if (shapeType == ShapeEnum.LINE) { aShape = new DecoratedLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y); } else { Point tempStartPoint; Point tempEndPoint; int drawWidth; int drawHeight; tempEndPoint = new Point(Math.max(endPoint.x, startPoint.x), Math.max(endPoint.y, startPoint.y)); tempStartPoint = new Point(Math.min(endPoint.x, startPoint.x), Math.min(endPoint.y, startPoint.y)); drawWidth = tempEndPoint.x - tempStartPoint.x; drawHeight = tempEndPoint.y - tempStartPoint.y; if(shapeType == ShapeEnum.ELLIPSE) { aShape = new DecoratedEllipse(tempStartPoint.x, tempStartPoint.y, drawWidth, drawHeight); } else if(shapeType == ShapeEnum.RECTANGLE) { aShape = new DecoratedRectangle(tempStartPoint.x, tempStartPoint.y, drawWidth, drawHeight); } } aShape.setColor(lineColor); aShape.setStroke(drawStroke); } if (aShape != null) { if (!mousePressed) { shapes.add(aShape); ptIndex = 0; } else { aShape.paintSelf(g2dImage); } } for (int i = 0; i < shapes.size(); i++) { shapes.get(i).paintSelf(g2dImage); } g2d.drawImage(image, 0, 0, getSize().width, getSize().height, null); } -------------------------------------------------------- このソース・コードは、今までの知識があれば理解できるはずですので、 説明は省略します。 ただ、矩形や楕円を描くときは、始点が左上の隅になりますので、 startPointとendPointの位置関係がそれに合っていない場合は、始点と終点 の入れ替えを行って必ず始点が左上の隅になるようにしなければならない ことに注意してください。 tempStartPointとtempEndPointはその入れ替え後の始点と終点を保管する ための変数として用意しています。 (3) 下記のメソッドを追加しましょう。 (これはshapeTypeフィールドに対するsetterメソッドですが、このように setterメソッドだけを自動生成したいときは、フィールドを選択(その フィールドにカーソルを入れる)した後、メニュー・バーから「Limy」 →「選択したフィールドのSetterメソッドを生成」を選択します。 ただし、これはLimyが組み込まれているEclipseの機能です。) -------------------------------------------------------- public void setShapeType(ShapeEnum shapeType) { this.shapeType = shapeType; } -------------------------------------------------------- これは、どの図形を描く状態であるかを示すフィールドshapeTypeに値を設定変更 するためのsetterメソッドですね。 ところが、このsetterメソッドはちょっと問題があります。 このsetterメソッド自体はpublic指定で外部からアクセスできるにも かかわらず、その引数の型ShapeEnumはprivateなenum型であるため、 外部からはアクセスできません。 結局、このままではこのsetShapeType()メソッドは外部からは使い物 になりません。 これはShapeEnumの定義ミスです。 そこで、ShapeEnumを外部からアクセスできるようにするために、 ShapeEnumの定義をpublic指定に変更してしまいましょう。 DrawingPanelのソース・コードの先頭のほうにある -------------------------------------------------------- private enum ShapeEnum { FREECURVE, LINE, RECTANGLE, ELLIPSE; } -------------------------------------------------------- のprivateをpublicに書き換えて -------------------------------------------------------- public enum ShapeEnum { FREECURVE, LINE, RECTANGLE, ELLIPSE; } -------------------------------------------------------- というふうにしましょう。 このように最初privateにしていたものをpublicに変更するのは容易 です。 しかし、逆に最初publicにしていた場合は、それを後で(この情報は 外部から書き換えられて困る等の理由で)privateに変更しようとする と問題だらけになることがありますので、注意が必要です。 publicにしていた場合は外部からアクセスされている可能性が高く、 その場合、privateに変更しようとすると、外部のクラス等がことごとく エラーになってしまって対処が困難になったりします。 したがって、「公開(public)にすべきかそれとも秘密(private) にすべきか判断できないときは秘密(private)にしておく」のが 鉄則だということを覚えておいて下さい。 では、続いてDrawingToolPanelの編集を行いましょう。 DrawingToolPanelのDesignビューを開いてください。 描く図形を選択できるようにするためにJToggleButtonを4つ(自由曲線、直線、 矩形、楕円の4つ)、strokeListの下に貼り付けて、その変数名とtextプロパティー を次のように変更して下さい。 (1つ目) 変数名は「freeCurveToggleButton」、textプロパティーは「自由曲線」 (2つ目) 変数名は「lineToggleButton」、textプロパティーは「直線」 (3つ目) 変数名は「rectangleToggleButton」、textプロパティーは「矩形」 (4つ目) 変数名は「ellipseToggleButton」、textプロパティーは「楕円」 なお、ボタンを貼り付ける場所が狭い場合は、既に貼り付けてあるボタン類を ドラッグして移動するなどして、場所をあけましょう。 また、ボタンの並び方が不揃いになっていたら、054号で色のボタンを整理したの と同じようにして、これらのボタンのレイアウトを調整し、きれいに整列する ようにしましょう。幅や高さも最適なサイズに調整しましょう。 次にこれらのJToggleButtonを一つのButtonGroupにまとめて、ラジオボタン のように働くようにしましょう。 ソース・コードのDrawingToolPanel()コンストラクターの最後に以下のような コードを追加してください。 -------------------------------------------------------- ButtonGroup shapeGroup = new ButtonGroup(); shapeGroup.add(freeCurveToggleButton); shapeGroup.add(lineToggleButton); shapeGroup.add(rectangleToggleButton); shapeGroup.add(ellipseToggleButton); -------------------------------------------------------- では次に、これらの各ボタンに対してリスナーのactionPerformed()メソッド のプログラミングをしていきましょう。 Designビューで、「自由曲線」のボタン(つまりfreeCurveToggleButton)を 右クリックして、「Add event handler」→「アクション」→「actionPerformed」 を選択します。 すると以下のコードが自動的に追加されますね。 -------------------------------------------------------- freeCurveToggleButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { } }); -------------------------------------------------------- これを以下のように編集しましょう。 -------------------------------------------------------- freeCurveToggleButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawingPanel.setShapeType(DrawingPanel.ShapeEnum.FREECURVE); } }); -------------------------------------------------------- ところで、上記のコードの中のDrawingPanel.ShapeEnumというのは、 先ほどDrawingPanelのソース・コードの中でprivateからpublicに 書き換えたShapeEnumを指していますが、これから何度も使うので 毎回DrawingPanel.ShapeEnumと長ったらしく書くのは面倒くさい し見苦しいですね。 こういう場合は、 import jp.co.flsi.lecture.cg.DrawingPanel.ShapeEnum; というimport文を(DrawingToolPanelのclass文の上のimport文が並んで いるところに)追加して下さい。 そうすれば、DrawingPanel.ShapeEnumと書いていた所をたんにShapeEnum と書くだけで済むようになります。 たとえば、先ほどのコードは -------------------------------------------------------- freeCurveToggleButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawingPanel.setShapeType(ShapeEnum.FREECURVE); } }); -------------------------------------------------------- というふうに書き換えることができます。 このようにクラスの内部に定義したクラス(内部クラス)や、もっと一般的には クラスの内部に定義した型(今回のShapeEnumのようなもの)は、 import パッケージ名.クラス名.型名; という形式のimport文で指定することができるのです。 では、同様にして、lineToggleButton、rectangleToggleButton、 ellipseToggleButtonに対してもリスナーのactionPerformed()メソッド のコードを自動生成させ、それぞれ下記のように編集しましょう。 <lineToggleButtonに対しては> -------------------------------------------------------- lineToggleButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawingPanel.setShapeType(ShapeEnum.LINE); } }); -------------------------------------------------------- <rectangleToggleButtonに対しては> -------------------------------------------------------- rectangleToggleButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawingPanel.setShapeType(ShapeEnum.RECTANGLE); } }); -------------------------------------------------------- <ellipseToggleButtonに対しては> -------------------------------------------------------- ellipseToggleButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { drawingPanel.setShapeType(ShapeEnum.ELLIPSE); } }); -------------------------------------------------------- このようにsetShapeType()メソッドの引数をenum型にしてあると、何を 指定してあるのか一目瞭然で分かりやすいですね(もっともRECTANGLE とかELLIPSEとかいった英語で書いてあるからわかりにくい人もいるかも しれませんが、プログラマーにとっては英語は重要ですからちゃんと勉強 しましょう。)。 もし、これを数字なんかで指定していたら、見てもわかりにくいし、 ときどき間違いをおかすはめになってしまい、プログラミングの生産性 も落ちてしまうのです。 あと、アプレット起動時の最初は自由曲線が選択されている状態ですので、 「自由曲線」ボタンが選択されている状態にしておきましょう。 Designビューに戻って、freeCurveToggleButtonの「selected」プロパティー の値をtrueに変更してください。(blueToggleButtonのときと同様の操作) 以上で、図形を選択して描く機能が完成しました。 保管してDrawingToolAppletを起動してテストしてみてください。 うまく動きましたか。 ここでちょっと気になることがありますね。楕円を描くと線が何だかギザギザ になっていてちょっと格好悪いですね。 直線も斜めの線はギザギザになりますね。 このギザギザを解消するためには、DrawingPanelのpaint()メソッドの中の -------------------------------------------------------- Graphics2D g2dImage = (Graphics2D) image.getGraphics(); -------------------------------------------------------- の行の下に -------------------------------------------------------- g2dImage.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); -------------------------------------------------------- というコードを入れてください。(RenderingHintsはjava.awtパッケージに 入っています。) その後、保管してテストすると線のギザギザが解消されることがわかりますね。 (ちなみにこのギザギザのことを「エイリアシング(aliasing)」と言い、 「ANTIALIASING(アンチエイリアシング)」は「反ギザギザ」のような意味 になります。) なお、このコードを入れるとちょっと余計にCPUを消費するので、遅いCPUを 使っている人は遅さが目立つかもしれません。 このGraphics2DのsetRenderingHint()というメソッドは描画の品質をコント ロールするためのメソッドなのですが、とにかくギザギザを解消するためには このコードを使うということを覚えておきましょう。詳しく知りたい人は自分で API仕様のWebページ http://java.sun.com/javase/ja/6/docs/ja/api/index.html などで調べて下さい。 なお、このコードを入れても自由曲線にはまだ少しぎこちなさが残っていますね。 これはまた後で対処します。 今回はここまで。 (続く) ======================================================== ◆ 02.文法解説 [アプレット] ======================================================== [アプレット(3)「アプレットのパラメーター」] アプレットの起動時にはパラメーターを指定することができます。 パラメーターの値は下記のようにAppletのgetParameter()メソッドを呼び 出すことによって取り出すことができます。 -------------------------------------------------------- String tempStr; tempStr = getParameter("parametername"); -------------------------------------------------------- なお、パラメーターの値が設定されていないときは、getParameter()メソ ッドはnullを返します。 これは例えば次のようにして使います。 パラメーターで与えられた幅、高さのデータを使って矩形を描くアプレット を例に取ります。 -------------------------------------------------------- import java.applet.Applet; import java.awt.Color; import java.awt.Graphics; public class FillRectApplet extends Applet { int width = 100; int height = 50; public void init() { String tempStr; tempStr = getParameter("rectwidth"); if (tempStr != null) width = Integer.parseInt(tempStr); tempStr = getParameter("rectheight"); if (tempStr != null) height = Integer.parseInt(tempStr); } public void paint(Graphics g) { g.setColor(new Color(255, 255, 0)); g.fillRect(10, 10, width, height); g.setColor(new Color(0,255,0)); g.drawRect(10, 10, width, height); } } -------------------------------------------------------- ここで、GraphicsのdrawRect()メソッドは矩形を描くメソッドで、Graphics のfillRect()メソッドは矩形の中を塗りつぶすメソッドです。 (実際にHTMLでパラメーターを指定する方法については後述します。) Eclipseでアプレットを起動するときにパラメーターを指定するには次のよう にします。 (1) 上のアプレット(FillRectApplet)を作成して保管(コンパイル)して おいたとします。 (2) パッケージ・エクスプローラーの中でFillRectAppletを右クリックし、 「実行」→「実行の構成」を選択します。 (3) 「実行構成」ウインドウの中に「メイン」、「パラメーター」、 「引数」、・・・といったタブが並んでいるので、そのうちの「メイン」タブ をクリックし、「プロジェクト」欄と「アプレット」欄の値が正しいことを 確認します。違っていたら、正しい値に変更してください。 (4) 「パラメーター」タブをクリックし、「追加」ボタンをクリックしてパラ メーターの名前と値を追加していきます。一つ目のパラメーターは名前を rectwidth(上のソース・コード内のgetParameter()メソッドに指定した引数 の文字列と一致させる)にし、値を20にしてみましょう。二つ目のパラメー ターは名前をrectheightにし、値を10にしてみましょう。 (一度追加したパラメーターを修正したいときは、パラメーターを選択して から「編集」ボタンをクリックして行います。またパラメーターを削除した いときは、パラメーターを選択してから「除去」ボタンをクリックします。) (5) 「実行」ボタンをクリックするとアプレット・ビューアが起動されて アプレットが実行されます。 なお、「実行構成」ウインドウは実行時の設定内容を記憶してしまい ますので、その後の通常のアプレットの起動でも以前の設定内容が反映され てしまいます。必要に応じて、「実行構成」ウインドウの設定内容を 適時変更してください。 (続く) ================================================ ◆ 03.任意演習問題 ================================================ インターフェースShapeを実装している図形クラスには直線や矩形や楕円以外 にもいくつかのものがあります。これらはともにGraphics2Dのdraw()メソッド で描画することができます。 また、Graphics2Dの描画メソッドには直線や輪郭だけを描くdraw()メソッド 以外に、閉じた図形の内側まで塗りつぶすfill()メソッドというのもあります。 これらをAPI仕様で調べて、DrawingToolPanelに機能を追加してみてください。 (続く) ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ★ホームページ: http://www.flsi.co.jp/Java_text/ ★このメールマガジンは 「まぐまぐ(http://www.mag2.com)」 を利用して発行しています。 ★バックナンバーは http://www.flsi.co.jp/Java_text/ にあります。 ★このメールマガジンの登録/解除は下記Webページでできます。 http://www.mag2.com/m/0000193915.html ★このメールマガジンへの質問は下記Webページにて受け付けて います。わからない所がありましたら、どしどしと質問をお寄 せください。 http://www.flsi.co.jp/Java_text/ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ Copyright (C) 2012 Future Lifestyle Inc. 不許無断複製 |