|
|
StrokeTest 線属性の設定 |
H.Kamifuji . |
Java2D において図形を描画する際の線に関する設定方法について、事例にて説明します。 現在(2021/08)では、JDK-16.0.2 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2021/11)では、JDK-17.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2023/04)では、JDK-20.0.1 にアップされています。一部、上位互換について、見直しを行っていきます。 現在(2024/10)では、JDK-23 にアップされています。一部、上位互換について、見直しを行っていきます。 |
|
描画する時の線に関する設定方法を確認します。線の太さや線の形状などの設定を行うことができます。 線の属性を設定するには図形が描画される前にGraphics2Dクラスで用意されている「setStroke」メソッドを使って線に関する属性を設定します。 setStroke public abstract void setStroke(Stroke s)Graphics2D コンテキストの Stroke を設定します。 パラメータ: s - 描画プロセスで Shape をストロークで 描画するために使われる Stroke オブジェクト 引数にはStrokeインターフェースを実装したクラスのオブジェクトを指定します。 BasicStrokeクラスStrokeインターフェースを実装したクラスとしてBasicStrokeクラスが用意されています。このクラスのオブジェクトに対して様々な線に関する設定を行っていくことになります。BasicStrokeクラスのクラス図は次のようになっています。 java.lang.Object ⇒ java.awt.BasicStroke public class BasicStroke extends Object implements Strokeコンストラクタは次の5つが用意されています。
具体的な利用方法は次のページ以降で詳しく見ていきますが利用方法は次のような感じとなります。 public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D)g; BasicStroke wideStroke = new BasicStroke(4.0f); g2.setStroke(wideStroke); } |
線の太さの設定を行います。次のコンストラクタを使用します。BasicStroke public BasicStroke(float width)指定された線幅と、先端およびライン接合のスタイルのデフォルト値を使って、実線で BasicStroke を構築します。 パラメータ: width - BasicStroke の幅 例外: IllegalArgumentException - width が負の値の場合 1番目の引数に線の太さを表すfloat型の値を指定します。このコンストラクタを使用する場合は線の太さ以外の項目はデフォルトの値が使用されます。 具体的には次のように記述します。 public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D)g; BasicStroke wideStroke = new BasicStroke(4.0f); g2.setStroke(wideStroke); g2.draw(new Line2D.Double(50, 50, 160, 180)); } サンプルプログラム下記のサンプルを実行してみよう。/** * 線の太さの設定 */ import javax.swing.*; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.*; import java.awt.BasicStroke; public class StrokeTest1 extends JPanel{ public static void main(String[] args){ JFrame frame = new JFrame(); StrokeTest1 app = new StrokeTest1(); frame.getContentPane().add(app); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 300, 200); frame.setTitle("タイトル"); frame.setVisible(true); } public void paintComponent(Graphics g){ Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.draw(new Line2D.Double(50, 30, 240, 120)); BasicStroke wideStroke = new BasicStroke(4.0f); g2.setStroke(wideStroke); g2.draw(new Line2D.Double(50, 50, 240, 140)); BasicStroke superwideStroke = new BasicStroke(10.0f); g2.setStroke(superwideStroke); g2.draw(new Rectangle2D.Double(70, 20, 150, 120)); } }上記をコンパイルした後で実行すると次のように表示されます。 ![]() |
線の先端の形状の設定を行います。次のコンストラクタを使用します。BasicStroke public BasicStroke(float width, int cap, int join)指定された属性を持つ実線の BasicStroke を構築します。デフォルト値でかまわない場合や、ライン接合が JOIN_MITER に指定されていない場合は、miterlimit パラメータは不要です。 パラメータ: width - BasicStroke の幅 cap - BasicStroke の両端の装飾 join - 輪郭線セグメントの接合部の装飾 例外: IllegalArgumentException - width が負の値の場合 IllegalArgumentException - cap が CAP_BUTT、CAP_ROUND、または CAP_SQUARE のどれでもない場合 IllegalArgumentException - join が JOIN_ROUND、JOIN_BEVEL、または JOIN_MITER のどれでもない場合 1番目の引数に線の太さを表すfloat型の値を指定します。 2番目の引数に線の両端の形状を表すint型の値を指定します。指定できる値はBasicStrokeクラスで定義されており次のいずれかです。
3番目の引数に線の結合方式を設定しますがこちらは次のページで解説しますので取り合えずデフォルトの「BasicStroke.JOIN_MITER」を指定しておいて下さい。 具体的には次のように記述します。 public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D)g; BasicStroke wideStroke = new BasicStroke(4.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); g2.setStroke(wideStroke); g2.draw(new Line2D.Double(50, 50, 160, 180)); } サンプルプログラム下記のサンプルを実行してみよう。/** * 先端の形状の設定 */ import javax.swing.*; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.*; import java.awt.BasicStroke; import java.awt.Color; public class StrokeTest2 extends JPanel{ public static void main(String[] args){ JFrame frame = new JFrame(); StrokeTest2 app = new StrokeTest2(); frame.getContentPane().add(app); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 300, 200); frame.setTitle("タイトル"); frame.setVisible(true); } public void paintComponent(Graphics g){ Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); BasicStroke buttStroke = new BasicStroke(25.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); g2.setStroke(buttStroke); g2.draw(new Line2D.Double(50, 30, 230, 30)); BasicStroke roundStroke = new BasicStroke(25.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER); g2.setStroke(roundStroke); g2.draw(new Line2D.Double(50, 80, 230, 80)); BasicStroke squareStroke = new BasicStroke(25.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER); g2.setStroke(squareStroke); g2.draw(new Line2D.Double(50, 130, 230, 130)); /* BasicStroke normalStroke = new BasicStroke(2.0f); g2.setStroke(normalStroke); g2.setPaint(Color.WHITE); g2.draw(new Line2D.Double(50, 30, 230, 30)); g2.draw(new Line2D.Double(50, 80, 230, 80)); g2.draw(new Line2D.Double(50, 130, 230, 130)); */ } }上記をコンパイルした後で実行すると次のように表示されます。 ![]() 先端部分がどの部分なのか分かるようにそれぞれの直接の同じ位置に太さを変え先端の装飾がない直線を引いてみます。先ほどのサンプルでコメントとなっている部分を外して実行して下さい。 ![]() |
線の結合方式の設定を行います。結合方式とは線が連続して描画される時に線と線の結合する部分の形状を指定します。次のコンストラクタを使用します。BasicStroke public BasicStroke(float width, int cap, int join)指定された属性を持つ実線の BasicStroke を構築します。デフォルト値でかまわない場合や、ライン接合が JOIN_MITER に指定されていない場合は、miterlimit パラメータは不要です。 パラメータ: width - BasicStroke の幅 cap - BasicStroke の両端の装飾 join - 輪郭線セグメントの接合部の装飾 例外: IllegalArgumentException - width が負の値の場合 IllegalArgumentException - cap が CAP_BUTT、CAP_ROUND、または CAP_SQUARE のどれでもない場合 IllegalArgumentException - join が JOIN_ROUND、JOIN_BEVEL、または JOIN_MITER のどれでもない場合 1番目の引数に線の太さを表すfloat型の値を指定します。 2番目の引数に線の両端の形状を表すint型の値を指定します。 3番目の引数に線の結合方式を表すint型の値を指定します。指定できる値はBasicStrokeクラスで定義されており次のいずれかです。
具体的には次のように記述します。 public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D)g; BasicStroke wideStroke = new BasicStroke(4.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); g2.setStroke(wideStroke); g2.draw(new Line2D.Double(50, 50, 160, 180)); } サンプルプログラム下記のサンプルを実行してみよう。/** * 線の結合方式の設定 */ import javax.swing.*; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.*; import java.awt.BasicStroke; public class StrokeTest3 extends JPanel{ public static void main(String[] args){ JFrame frame = new JFrame(); StrokeTest3 app = new StrokeTest3(); frame.getContentPane().add(app); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 300, 200); frame.setTitle("タイトル"); frame.setVisible(true); } public void paintComponent(Graphics g){ Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); BasicStroke joinStroke = new BasicStroke(20.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); g2.setStroke(joinStroke); GeneralPath polygon = new GeneralPath(); polygon.moveTo(20, 150); polygon.lineTo(50, 50); polygon.lineTo(80, 150); g2.draw(polygon); polygon.reset(); BasicStroke miterStroke = new BasicStroke(20.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); g2.setStroke(miterStroke); polygon.moveTo(120, 150); polygon.lineTo(150, 50); polygon.lineTo(180, 150); g2.draw(polygon); polygon.reset(); BasicStroke roundStroke = new BasicStroke(20.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND); g2.setStroke(roundStroke); polygon.moveTo(220, 150); polygon.lineTo(250, 50); polygon.lineTo(280, 150); g2.draw(polygon); } }上記をコンパイルした後で実行すると次のように表示されます。 ![]() |
線の結合方式としてJOIN_MITERを設定した場合、線の結合角度が小さい場合に結合部分の突起の箇所が非常に長くなってしまう場合があります。そこであまり長くなってしまう場合にはJOIN_MITERの代わりにJOIN_BEVELが利用されるように設定する事ができます。 設定は線の太さの何倍までの長さなら突起をJOIN_MITERとして表示するという設定になります。次のコンストラクタを使用します。BasicStroke public BasicStroke(float width, int cap, int join, float miterlimit)指定された属性を持つ実線の BasicStroke を構築します。 パラメータ: width - BasicStroke の幅 cap - BasicStroke の両端の装飾 join - 輪郭線セグメントの接合部の装飾 miterlimit - 接合トリミングの制限値 例外: IllegalArgumentException - width が負の値の場合 IllegalArgumentException - cap が CAP_BUTT、CAP_ROUND、または CAP_SQUARE のどれでもない場合 IllegalArgumentException - miterlimit が 1 より小さく、 join が JOIN_MITER の場合 IllegalArgumentException - join が JOIN_ROUND、JOIN_BEVEL、または JOIN_MITER のどれでもない場合 1番目の引数に線の太さを表すfloat型の値を指定します。 2番目の引数に線の両端の形状を表すint型の値を指定します。 3番目の引数に線の結合方式を表すint型の値を指定します。今回はJOIN_MITERを指定します。 4番目の引数に線の太さの何倍までであれば突起部分を表示するかを表すfloat型の値を指定します。デフォルトは10.0倍となっており倍率は1.0よりも少ない数値は指定できません。 具体的には次のように記述します。 public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D)g; BasicStroke wideStroke = new BasicStroke(4.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f); g2.setStroke(wideStroke); g2.draw(new Line2D.Double(50, 50, 160, 180)); } サンプルプログラム下記のサンプルを実行してみよう。/** * JOIN_MITERの時の接合制限値の設定 */ import javax.swing.*; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.*; import java.awt.BasicStroke; public class StrokeTest4 extends JPanel{ public static void main(String[] args){ JFrame frame = new JFrame(); StrokeTest4 app = new StrokeTest4(); frame.getContentPane().add(app); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 300, 200); frame.setTitle("タイトル"); frame.setVisible(true); } public void paintComponent(Graphics g){ Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); BasicStroke miterStroke1 = new BasicStroke(20.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 3.0f); g2.setStroke(miterStroke1); GeneralPath polygon = new GeneralPath(); polygon.moveTo(20, 150); polygon.lineTo(40, 50); polygon.lineTo(60, 150); g2.draw(polygon); polygon.reset(); BasicStroke miterStroke2 = new BasicStroke(20.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 5.0f); g2.setStroke(miterStroke2); polygon.moveTo(120, 150); polygon.lineTo(140, 50); polygon.lineTo(160, 150); g2.draw(polygon); polygon.reset(); BasicStroke miterStroke3 = new BasicStroke(20.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f); g2.setStroke(miterStroke3); polygon.moveTo(220, 150); polygon.lineTo(240, 50); polygon.lineTo(260, 150); g2.draw(polygon); } }上記をコンパイルした後で実行すると次のように表示されます。 ![]() 左の2つは制限値を超えているので突起部分は表示されていません。(JOIN_BEVELとして表示されます)。 |
線の表示方法として実線の代わりに破線を表示する方法を確認します。色々な破線パターンが用意されているのではなく破線のパターンを自分で定義します。次のコンストラクタを使用します。BasicStroke public BasicStroke(float width, int cap, int join, float miterlimit, float[] dash, float dash_phase)指定された属性を持つ新しい BasicStroke を構築します。 パラメータ: width - この BasicStroke の幅。値は 0.0f 以上でなければならない。幅 が 0.0f に設定されている場合、ストロークは対象のデバイス上のもっと も細いラインとして描画される。 また、このときアンチエイリアス設定 が使用される cap - BasicStroke の両端の装飾 join - 輪郭線セグメントの接合部の装飾 miterlimit - 接合トリミングの制限値。miterlimit は 1.0f 以上でなければならない dash - 破線パターンを表す配列 dash_phase - 破線パターン開始位置のオフセット 例外: IllegalArgumentException - width が負の値の場合 IllegalArgumentException - cap が CAP_BUTT、CAP_ROUND、または CAP_SQUARE のどれでもない場合 IllegalArgumentException - miterlimit が 1 より小さく、 join が JOIN_MITER の場合 IllegalArgumentException - join が JOIN_ROUND、JOIN_BEVEL、または JOIN_MITER のどれでもない場合 IllegalArgumentException - dash_phase が負の値で、 dash が null でない場合 IllegalArgumentException - dash の長さが ゼロの場合 IllegalArgumentException - 破線の長さがすべてゼロの場合 1番目の引数に線の太さを表すfloat型の値を指定します。 2番目の引数に線の両端の形状を表すint型の値を指定します。 3番目の引数に線の結合方式を表すint型の値を指定します。今回はJOIN_MITERを指定します。 4番目の引数に線の太さの何倍までであれば突起部分を表示するかを表すfloat型の値を指定します。 5番目の引数に破線パターンを表すfloat型の配列を指定します。そして6番目の引数に5番目の引数で指定した破線パターンの開始オフセットをfloat型の値で指定します。詳細は後述します。 具体的には次のように記述します。 public void paintComponent(Graphics g) { Graphics2D g2 = (Graphics2D)g; float dash[] = {10.0f, 3.0f}; BasicStroke dashStroke = new BasicStroke(4.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f); g2.setStroke(dashStroke); g2.draw(new Line2D.Double(50, 50, 160, 180)); } 破線パターン破線のパターンを1つしか指定していない場合は、表示部分としない部分が繰り返されます。下記の場合は、長さ3.0fの部分が繰り返されます。float dash[] = {3.0f}; ***___***___***___***___***___***___***破線のパターンを2つ指定した場合は、1番目に指定した長さを表示し、2番目に指定した長さだけ表示しない部分が繰り返されます。下記の場合は、長さ4.0fの表示部分と長さ2.0fの表示されない部分が繰り返されます。 float dash1[] = {4.0f, 2.0f}; ****__****__****__****__****__****__****__破線のパターンをより複雑にした場合も今までと同様です。表示される部分とされない部分が配列に指定した値の数だけ繰り替えされます。 float dash1[] = {8.0f, 2.0f, 2.0f, 3.0f}; ********__**___********__**___********__**___ 破線のオフセット破線のパターンを定義した後で、どの位置から表示を開始するかをオフセットで指定します。例えば下記のような破線パターンがあった場合で考えてみます。 float dash1[] = {4.0f, 2.0f}; ****__****__****__****__****__****__****__オフセットを変更することで表示される破線は次のように変化します。 dash_phase=0.0f ****__****__****__****__****__****__****__ dash_phase=1.0f ***__****__****__****__****__****__****__* dash_phase=2.0f **__****__****__****__****__****__****__** サンプルプログラム下記のサンプルを実行してみよう。/** * 破線パターンの設定 */ import javax.swing.*; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.*; import java.awt.BasicStroke; public class StrokeTest5 extends JPanel{ public static void main(String[] args){ JFrame frame = new JFrame(); StrokeTest5 app = new StrokeTest5(); frame.getContentPane().add(app); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(10, 10, 300, 200); frame.setTitle("タイトル"); frame.setVisible(true); } public void paintComponent(Graphics g){ Graphics2D g2 = (Graphics2D)g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); float dash1[] = {10.0f, 3.0f}; BasicStroke dsahStroke1 = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 3.0f, dash1, 0.0f); g2.setStroke(dsahStroke1); g2.draw(new Line2D.Double(50, 30, 230, 30)); BasicStroke dsahStroke2 = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 3.0f, dash1, 3.0f); g2.setStroke(dsahStroke2); g2.draw(new Line2D.Double(50, 80, 230, 80)); float dash2[] = {10.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f}; BasicStroke dsahStroke3 = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 3.0f, dash2, 0.0f); g2.setStroke(dsahStroke3); g2.draw(new Line2D.Double(50, 130, 230, 130)); } }上記をコンパイルした後で実行すると次のように表示されます。 ![]() |
|