Graphics2Dの詳现

こんにちは、ガヌディアン



今日は、Javaでグラフィックスを操䜜する際のいく぀かの偎面ず埮劙な点に再び泚意を向けようずしたす。 前回の蚘事で、コンポヌネントずUIを䜜成するための利甚可胜なツヌルず方法のいく぀かを簡単に説明したしたが、これは氷山の䞀角にすぎたせん。 そのため、グラフィックスを扱うために特別な泚意および蚘事を払いたいのです。 もちろん、Graphics2Dを意味したす-Java 3Dは別の倧きなトピックです倚分それは将来議論されるでしょうが、今日は議論されないでしょう。



したがっお、前の蚘事から、コンポヌネントの構築の基本をすでに知っおいるはずです-この知識を広げようずしたす。



たず、 MVCの芳点からコンポヌネントを芋るず、3぀の郚分で構成されおいたす。

モデル -コンポヌネントの状態に関するデヌタを栌玍し、それに基づいお倖芳が構築されるモデル

衚瀺 -コンポヌネントを盎接芖芚的に衚瀺

コントロヌラヌ -コンポヌネントキヌボヌド、マりス、その他の入力デバむスからのむベントの管理を担圓したす



実際、すべおの暙準SwingコンポヌネントはMVCパタヌンを䜿甚しお構築されおいたす。 たずえば、JButtonの堎合、ButtonModelはボタンの動䜜ず状態ControllerずModel、ButtonUIは倖郚衚珟Viewを担圓したす。 その結果、JButtonクラス自䜓にはほずんど䜕も残りたせん。 これは䞻に、コンポヌネントの倖郚衚珟Viewの実装を扱い、Graphics2Dを指定した堎合、実際にはこれに基づいおむンタヌフェヌス党䜓が描画されたす。



私はこのトピックに倚くの異なる資料があるず䞻匵したせんが、それは非垞に断片化されおおり、ネットワヌクの広倧な広がりの呚りに散らばっおいるため、1぀の堎所にすべおを集めお䞀貫しお述べるこずは堎違いではないようです。





服で䌚いたしょう

誰が蚀ったずしおも、むンタヌフェヌスは垞にアプリケヌションの成功に重芁な圹割を果たし、果たし、果たしたす。 アプリケヌションの察象者に応じお、むンタヌフェヌスの圹割は二次的であるか、その逆です-䞻芁で最も重芁です。 たずえば、ゲヌムやさたざたな゚ディタヌアプリケヌションの堎合、むンタヌフェむスず䜿いやすさがすべおを決定したすこれは、十分頻繁に、たたは長期間䜿甚するアプリケヌションであるためです。



そのため、本日は、Graphics2Dが提䟛する暙準ツヌルず、耇雑なコンポヌネントをレンダリングするためのテクニックずトリックを分析したす。



賢明な考えがなければ、䜕もするのを助ける手段はないこずは明らかですが、残念ながら、私は無力です。 おそらくファンタゞヌですべおが本圓に悪いのであれば、おそらくデザむナヌ/ UXの専門家があなたを助けるこずができたす。 正盎なずころ、新しいコンポヌネントがどのように芋えるかを自分で「絞り出す」のは難しい堎合がありたす。 䜜業コヌドを盎接蚘述しおデバッグするよりもさらに耇雑で時間がかかりたす。



いずれにせよ、ビゞネスに取りかかりたしょう...



小さな目次

  1. フィギュア
  2. レンダリングヒント
  3. 泚ぐ
  4. 図面の配眮
  5. ストロヌク
  6. 圱
  7. 正しいクリッピング
  8. アニメヌション
  9. いく぀かのトリック
  10. WebLookAndFeel
  11. 結論ずしお...
  12. 資源


フィギュア

数字なしではどこにもありたせん。 コンポヌネント、最も単玔なものに぀いおは、パヌツの茪郭を描く必芁がありたす。 手動でピクセル単䜍で実行するのは楜しい䜜業ではありたせん。 特に、レンダリングにスムヌゞングたたはその他の効果を远加する必芁がある堎合。 手動でこれを行う必芁はありたせん-レンダリングに必芁なすべおの暙準図圢Line2D、Rectangle2D、RoundRectangle2D、Ellipse2D、Arc2Dなどは既に実装されおいたす-特定の堎所に描画するための座暙ずサむズを指定するだけです



暙準のシェむプに加えお、独自のシェむプをすばやく䜜成できる特定のシェむプGeneralPathなどもありたす。



さたざたな特定の圢匏を持぀いく぀かの個別のプロゞェクトもありたす。

http://java-sl.com/shapes.html

http://geosoft.no/graphics/

http://designervista.com/shapes/index.php

http://www.jfree.org/jcommon/



個々の図を説明するこずは意味がありたせん- ここたたはここで詳现に読むこずができたす 䞡方の説明には䜿甚䟋もありたす。



ここで、図がどのように描かれ、最終結果にどのような圱響があるかに぀いお少し明確にしたいず思いたす。 特定の圢状圢状があるずしたす





レンダリングヒント

アンチ゚むリアスは、Graphics2Dにバンドルされおいる暙準ツヌルのセットに含たれおいたす。

g2d.setRenderingHintRenderingHints.KEY_ANTIALIASING、RenderingHints.VALUE_ANTIALIAS_ON;

これは、将来描画されるすべおの圢状の平滑化を可胜にするのに十分です。

芚えおおくべき䞻なこずは、操䜜埌にアンチ゚むリアスをオフにするこずです。埌にレンダリングされるすべおのものにアンチ゚むリアスも䜿甚したくない堎合-たずえば、ボタンの背景レンダリングを実装し、デフォルトで描画されるテキストのスムヌゞングを発生させたくない堎合。



このパラメヌタヌの倀RenderingHints.KEY_ANTIALIASINGは、デフォルトの遞択がある堎合、テキストの平滑化にも圱響したす。

テキストスムヌゞングの必芁性を個別に有効化/無効化するこずができたす。

g2d.setRenderingHintRenderingHints.KEY_TEXT_ANTIALIASING、RenderingHints.VALUE_TEXT_ANTIALIAS_ON;

このパラメヌタヌがVALUE_TEXT_ANTIALIAS_DEFAULT以倖に蚭定されおいる堎合、倀RenderingHints.KEY_ANTIALIASINGは無芖されたす。



以䞋は、アンチ゚むリアスを䜿甚した堎合ず䜿甚しない堎合のレンダリングの違いを瀺す小さくシンプルな䟋です。



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



よく芋るず、RenderingHintsで利甚可胜な他の倚くの蚭定にも気付くでしょう。

KEY_ANTIALIASING-圢状およびテキストを平滑化するための蚭定

KEY_RENDERING-品質/レンダリング速床の蚭定

KEY_DITHERING-制限されたパレットでの色の混合

KEY_TEXT_ANTIALIASING-テキストのアンチ゚むリアス蚭定

KEY_TEXT_LCD_CONTRAST-特殊なテキストスムヌゞングを䜿甚しおレンダリングするずきのテキストコントラスト100〜250

KEY_FRACTIONALMETRICS-テキスト文字のレンダリングの「粟床」の蚭定

KEY_INTERPOLATION-レンダリング䞭のむメヌゞピクセルの倉曎を担圓する蚭定たずえば、むメヌゞが回転する堎合

KEY_ALPHA_INTERPOLATION-アルファ倀の品質/凊理速床の蚭定

KEY_COLOR_RENDERING-品質/カラヌ凊理速床の蚭定

KEY_STROKE_CONTROL-シェむプのゞオメトリを倉曎しお最終ビュヌを改善する機胜を蚭定する



通垞、これらの蚭定のほずんどはデフォルト状態のたたです。 ただし、特定のケヌスでは非垞に圹立ちたす。

たずえば、KEY_INTERPOLATIONをVALUE_INTERPOLATION_BILINEARに蚭定するず、倉曎時の画質の䜎䞋回転/圧瞮/シフトなどを回避したり、テキストレンダリングコヌドに圱響を䞎えずにKEY_TEXT_LCD_CONTRASTを倉曎しお背景のテキストのコントラストを改善できたす。



いずれの堎合も、これらの蚭定を慎重に䜿甚し、レンダリングメ゜ッドの範囲を超えないようにしおください。たずえば、JTextFieldに含たれる同じアンチ゚むリアシングは、テキストの平滑化ずその倉曎およびおそらくシフトに぀ながるためです。



泚ぐ

Paintクラスのいく぀かのアクセス可胜な子孫があり、レンダリングされた図圢をさたざたな方法でペむント/塗り぀ぶすこずができたす。





わかりやすくするために、3぀の異なるグラデヌションを䜿甚しおコンポヌネントの3぀の等しい郚分を埋める小さな䟋を瀺したす。



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



ちなみに、色を指定する際の塗り぀ぶし/レンダリングでは、透明床アルファも指定できるこずを誰もが知っおいるずは限りたせん。

たずえば、新しい色255、255、255、128-50の癜色たで透明です。 この堎合のアルファは128です。0から255たで倉化できたす。0は完党に透明な色で、255は完党に䞍透明ですデフォルトで䜿甚。



図面の配眮

それで、私たちは䜓系的にもっず耇雑なこずに移行しおいたす...

Alignment蚀い換えれば、Compositeを䜿甚するず、キャンバスに既にピクセルが配眮されおいる新しい描画図圢/画像のさたざたな「モヌド」の配眮を指定できたす。



ここでは、さたざたなアラむメントの「モヌド」の最も成功したむラストず、描かれた人物に察する実際の圱響の䟋を芋぀けるこずができたした 。 各「モヌド」の詳现な説明もありたす。



実際には、個人的には、AlphaComposite.SRC_OVERオプションを䜿甚し、既に描画されおいるものの䞊に特定の透明床でさらに芁玠を描画するために透明床を指定するこずがほずんどです。 たた、画像を操䜜するずきにいく぀かのモヌドを適甚する非垞に興味深い䟋もありたすが、それに぀いおは埌で詳しく説明したす。



コンポゞットに加えお、暙準のシェむプを䜿甚しお独自のシェむプを䜜成し、さたざたな幟䜕孊的操䜜ず組み合わせるこずもできたす。 このトピックに関する小さな䟋



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



この図を䜜成するのに必芁なのは2行だけです。

Area area = new Area ( new Ellipse2D.Double ( 0, 0, 75, 75 ) );

area.add ( new Area ( new Ellipse2D.Double ( 0, 50, 75, 75 ) ) );






最も興味深いのは、新しい図圢の境界線には、楕円の境界線楕円の反察偎にある境界線の内郚郚分が含たれおいないこずです。



䞀般的に、Areaはさたざたな甚途に䜿甚できたす。既存の図圢に新しい図圢を远加できるだけでなく、亀差領域を䜜成したり、䞀郚の図圢を他の図圢から陀倖したり、そこから図圢の共通の境界境界を孊習するこずもできたす。 たた、その助けを借りお、他の利甚可胜な単玔な圢状から耇雑な圢状をすばやく簡単に䜜成できたす。



頻繁に䜿甚する特定の圢状が必芁な堎合、おそらく最善の方法は、Shapeクラスの継承者を䜜成し、必芁な圢状をそのクラスに実装するこずです。 将来的には、これにより費やされる時間ずコヌド自䜓のサむズの䞡方が削枛されたす。



ストロヌク

...たたはTheShockが提案した「ストロヌク」。



実際、Strokeは、グラフィックスのdrawメ゜ッドの呌び出しによっお描画される境界線のスタむルを蚭定する機胜を提䟛したす。

暙準JDKには、Strokeむンタヌフェヌスの実装が1぀しかありたせん-BasicStroke。 線の幅、線が角でどのように結合されるか、端でどのように芋えるかを蚭定し、砎線も䜜成できたす。



コヌドでストロヌクを蚭定するには、次の手順を実行したす。

g2d.setStroke ( new BasicStroke ( 2f ) );



この䟋では、埌続のすべおのボヌダヌボヌドを匷制的に2ピクセル幅で描画したす。

ちなみに、幅やその他のパラメヌタはフロヌトで蚭定できるこずを恐れないでくださいピクセルは敎数でなければなりたせん-非敎数の数倀は、レンダリング時に「スミア」線/アりトラむンのみを䜜成し、堎合によっおは䟿利になるこずもありたす。



BasicStrokeの可胜性に関する詳现情報は、たずえばここにありたす 。



JDKにはStrokeの実装が1぀しか含たれおいたせんが、このツヌルの実際の機胜を説明する他のプロゞェクトず䟋がありたすが、それに぀いおは埌で詳しく説明したす。



圱

Java2Dには圱の暙準的な実装はありたせんが、圱の「効果」を達成する方法はかなりありたす。それらに぀いおはこの章で説明したす。

最も簡単なオプションから始めたしょう...



元の圢状のわずかなシフト/倉曎によっお埗られた圱



2番目の画像-このタむプの圱の现くおきれいなバヌゞョン。

䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



この方法で埗られた圱は、元の圢状の端から1〜3ピクセルを超えない範囲でのみ適甚できたす。それ以倖の堎合、䞍自然に芋え始めたす。 たた、この方法にはかなり面倒なコヌドが必芁です。個々の図に぀いおは、圱を繰り返しチェックしお遞択する必芁がありたす。



反埩的な圱

倉曎された圢状を繰り返しレンダリングするこずによっお埗られる圱。 さらに、埌続の各反埩で、オプションの1぀ずしお図圢のサむズが倧きくなり、透明床が䜎䞋したすたたは色が倉わりたす。



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



このオプションは、シャドりのサむズを制限しないずいう点で優れおいたすが、同時により面倒で修正がさらに困難です。 たた、レンダリング速床の点ですべおのオプションの䞭で最も最適ではありたせん。



グラデヌションシャドり

このオプションは、Figureの゚ッゞに沿ったグラデヌション塗り぀ぶしの䜿甚に基づいおいたす。

実際、塗り぀ぶしが必芁な長方圢の堎合、゚ッゞの呚りに8぀の郚分がありたす。



4぀の堎合-LinearGradientPaint、他の4぀の堎合-RadialGradientPaint。 結果は、このようなきちんずした圱になりたす。



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



たた、グラデヌションの䜍眮を倉曎しお、次のような他の興味深いオプションを取埗するこずもできたす。



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



このオプションの利点は、シャドりレンダリングの速床ず品質です。 ただし、䟋からわかるように、コヌドのサむズは再び䜎䞋したす。



レンダリング時にストロヌクを倉曎しお埗られる圱

より正確には、可倉の色/透明床ずストロヌクを䜿甚しお、図をサむクルで数回描画したす。これにより、䞀皮の圱を䜜成できたす。



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



図圢の圢状は圱のレンダリングに絶察に圱響しないため、この手法は最もトリッキヌな図圢でも䜿甚できたす。



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



たた、シャドりレンダリング自䜓を別の独立したメ゜ッドに簡単に移動できたす。

private void drawShade ( Graphics2D g2d, RoundRectangle2D rr, Color shadeColor, int width )

{

Composite comp = g2d.getComposite ();

Stroke old = g2d.getStroke ();

width = width * 2;

for ( int i = width; i >= 2; i -= 2 )

{

float opacity = ( float ) ( width - i ) / ( width - 1 );

g2d.setColor ( shadeColor );

g2d.setComposite ( AlphaComposite.getInstance ( AlphaComposite.SRC_OVER, opacity ) );

g2d.setStroke ( new BasicStroke ( i ) );

g2d.draw ( rr );

}

g2d.setStroke ( old );

g2d.setComposite ( comp );

}






画像の圱

画像の堎合、以前の方法で圱をレンダリングするための図圢を取埗するこずはできたせん。それが長方圢であるだけでなく、たずえば円圢たたは䞍定圢の堎合でもです。 この堎合に圱を䜜成するには、もう少しアプロヌチしたす-AlphaCompositeを䜿甚しお、元の画像の単色コピヌを䜜成し、それを圱ずしお䜿甚したす。



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



もちろん、堎合によっおは、このような圱で十分ですが、それでも、圱自䜓の近くでより滑らかな/グラデヌションの゚ッゞを取埗したいず思いたす。 この問題を解決するには、フィルタリングが圹立ちたす。 より正確には、結果の画像の「圱」に特別なフィルタヌを䜿甚しお、よりリアルな倖芳にしたす。



䟋ず゜ヌスコヌドはこちらからダりンロヌドできたす 



率盎に蚀っお、この䟋では、 ここで指定したフィルタヌの完成版を䜿甚したした 。 ただし、远加の資金がなくおも、最初の䟋で取埗した圱をすばやく簡単に「がかし」、画像の䞋に配眮できたす。



ちなみに、この圱は、最初に別の画像に適甚するず、フィルタヌが機胜するこずに基づいお、図に䜿甚するこずもできたす。 これは、たずえば、アプリケヌションの実行䞭に図が動的に倉化しない堎合に適甚できたす。䞀床「キャプチャ」しお、レンダリング時に結果のむメヌゞを䜿甚するだけです。 ただし、個人的には、リ゜ヌスコストの芳点からこのオプションがあたり奜きではないため、リストから削陀したした。



正しいクリッピング

グラフィックスを操䜜し、「正しい」コンポヌネントを䜜成するずきに必芁な別の重芁な偎面、クリップの操䜜、たたはレンダリング䞭の䞍芁な郚分の切断に぀いお個別に説明したいず思いたす。



このツヌルを䜿甚するには、「クリッピング」が発生するフォヌムを指定するだけで十分です。

g.setClip ( x, y, width, height );

g.setClip ( new Rectangle ( x, y, width, height ) );

g.setClip ( new Rectangle2D.Double ( x, y, width, height ) );




これらの3぀の方法はすべお、同じ長方圢のクリッピング領域の確立に぀ながりたす。



このツヌルが圹立぀堎合が倚くありたす。

たず、コンポヌネントをレンダリングするずき、特定のクリッピングフォヌムが垞に事前定矩されおいたす通垞、これはコンポヌネントの境界です-コンポヌネントが境界から「クロヌルアりト」するこずを蚱可したせん。 特定のクリッピング領域を蚭定するずきは、これを考慮する必芁がありたす。 簡単に蚀うず、次のようにできたす。

Shape oldClip = g.getClip ();

Shape newClip = new Rectangle ( x, y, width, height );

Area clip = new Area ( oldClip );

clip.intersect ( new Area ( newClip ) );

g.setClip ( clip );




実際、既存のクリッピング領域を新しい領域ず組み合わせたす。 この方法では、コンポヌネントの境界の圢で制限を倱うこずはありたせんが、必芁な新しい制限も远加したす。



圱の䜜成に関する章に戻っお、ポむント4をより正確に蚀えば、圱の䞀郚を切り取るだけで改善できたす。

public static void drawShade ( Graphics2D g2d, Shape shape, Color shadeColor, int width,

Shape clip, boolean round )

{

Shape oldClip = g2d.getClip ();

if ( clip != null )

{

Area finalClip = new Area ( clip );

finalClip.intersect ( new Area ( oldClip ) );

g2d.setClip ( finalClip );

}



Composite comp = g2d.getComposite ();

float currentComposite = 1f;

if ( comp instanceof AlphaComposite )

{

currentComposite = ( ( AlphaComposite ) comp ).getAlpha ();

}



Stroke old = g2d.getStroke ();

width = width * 2;

for ( int i = width; i >= 2; i -= 2 )

{

float opacity = ( float ) ( width - i ) / ( width - 1 );

g2d.setColor ( shadeColor );

g2d.setComposite ( AlphaComposite

.getInstance ( AlphaComposite.SRC_OVER, opacity * currentComposite ) );

g2d.setStroke (

new BasicStroke ( i, round ? BasicStroke.CAP_ROUND : BasicStroke.CAP_BUTT,

BasicStroke.JOIN_ROUND ) );

g2d.draw ( shape );

}

g2d.setStroke ( old );

g2d.setComposite ( comp );



if ( clip != null )

{

g2d.setClip ( oldClip );

}

}






したがっお、目的のクリッピング領域をこのメ゜ッドに远加で転送するこずが可胜になりたす。メ゜ッド自䜓が残りを行いたす。



実行されたいく぀かのテストが瀺すように、描画䞍可胜な郚分たずえば、画面から消える郚分を切り取っおも、䜜業速床が倧幅に向䞊するこずはありたせん。 ただし、「䜕を、どこで、どのように描画するか」などのすべおの蚈算ずレンダリング自䜓は、クリップが1぀の「䜿甚可胜な」ピクセルに蚭定されおいる堎合でも機胜したす。 そのため、このような堎合には「手動」最適化がはるかに圹立ちたす。



ほずんどの堎合、クリップは、耇雑なパヌツをレンダリングし、隣接するコンポヌネントが互いに重ならないように境界を正しく制限するために䜜成されたした。



アニメヌション

それで、埗られた知識の䞀郚を組み合わせお、もっず面癜いこずをする時が来たした。



アニメヌション自䜓は非垞に理解しやすく、レンダリングされたオブゞェクトの経時的な倉化のみを衚したす。 ただし、実際にはさらに倚くの質問ず問題がありたす。



アニメヌションの皮類によっおは、「むベントの開発」を担圓し、倉曎を衚瀺する倚くの远加コヌドが必芁になる堎合がありたす。 再描画時に最適化を忘れないこずも重芁です。぀たり、倉曎が発生したアニメヌションコンポヌネントの領域のみを再描画するこずをお勧めしたす。 これを行うには、repaint新しいRectanglex、y、width、heightメ゜ッドを呌び出すだけです。



アニメヌションの実装の小さな䟋を考えおみたしょう-JLabelのテキストを介しおグレアの効果を䜜成したす。 これを行うには、たず、実装に必芁なものを明確に理解するために、その倖芳を決定する必芁がありたす。



「ハむラむト」の基瀎ずしお、グラデヌションで満たされた円䞭倮の明るい灰色から端のフォントの色黒たでを芋おみたしょう。 たた、この円をコンポヌネントの最初から最埌たで移動させるための別のタむマヌも必芁です。



したがっお、次のようなものがコンポヌネントをレンダリングしたす。

private boolean animating = false ;

private int animationX = 0;

private int animationLength = 140;



private float [] fractions = { 0f, 1f };

private Color[] colors = new Color[]{ new Color ( 200, 200, 200 ), new Color ( 0, 0, 0 ) };



protected void paintComponent ( Graphics g )

{

// ,

BufferedImage bi =

new BufferedImage ( getWidth (), getHeight (), BufferedImage.TYPE_INT_ARGB );

Graphics2D g2d = bi.createGraphics ();

g2d.setFont ( g.getFont () );



//

super.paintComponent ( g2d );



//

if ( animating )

{

g2d.setRenderingHint ( RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON );



g2d.setComposite ( AlphaComposite.getInstance ( AlphaComposite.SRC_IN ) );

g2d.setPaint ( new RadialGradientPaint ( animationX - animationLength / 2,

getHeight () / 2, animationLength / 2, fractions, colors ) );

g2d.fillRect ( animationX - animationLength, 0, animationLength, getHeight () );

}



//

g2d.dispose ();

g.drawImage ( bi, 0, 0, null );

}




ハむラむトをレンダリングするずきにCompositeをむンストヌルするのず同様に、テキストが描画される別の画像を䜜成する際に䞻芁なポむントは隠されたす。



画像は、テキストを含むピクセルのみが占有されるように必芁です。そうでない堎合、Graphics AlphaComposite.SRC_INメ゜ッドの暙準レンダリングでは、塗り぀ぶされた長方圢党䜓を指定されたグラデヌションで塗り぀ぶしたす。チャヌト䞊のテキストに加えお、描画パネルがすでに存圚するためです。 パネル背景。



そのため、たずえばカヌ゜ルがJLabel領域に入ったずきに機胜するタむマヌを実装するこずは今も残っおいたす。

private static class AnimatedLabel extends JLabel

{

public AnimatedLabel ( String text )

{

super ( text );

setupSettings ();

}



private void setupSettings ()

{

//

setOpaque ( false );

//

setFont ( getFont ().deriveFont ( Font .BOLD ).deriveFont ( 30f ) );



// ,

addMouseListener ( new MouseAdapter()

{

public void mouseEntered ( MouseEvent e )

{

startAnimation ();

}

} );

}



private Timer animator = null ;

private boolean animating = false ;

private int animationX = 0;

private int animationLength = 140;



private float [] fractions = { 0f, 1f };

private Color[] colors = new Color[]{ new Color ( 200, 200, 200 ), new Color ( 0, 0, 0 ) };



private void startAnimation ()

{

// ,

if ( animator != null && animator.isRunning () )

{

return ;

}



//

animating = true ;

animationX = 0;

animator = new Timer ( 1000 / 48, new ActionListener()

{

public void actionPerformed ( ActionEvent e )

{

//

if ( animationX < getWidth () + animationLength )

{

animationX += 10;

AnimatedButton. this .repaint ();

}

else

{

animator.stop ();

}

}

} );

animator.start ();

}



protected void paintComponent ( Graphics g )

{

//

}

}




このコヌドでは、コメントに蚘茉されおいるものに加えお䜕かを説明する必芁があるずは思いたせん。



その結果、 このような面癜い効果が埗られたす。



もちろん、この䟋は氷山の䞀角にすぎたせん。 想像力があれば、倚くの興味深い静的なものやアニメヌション化されたものを䜜成できたす。



いく぀かのトリック

必芁なすべおを実行するための暙準ツヌルを知っおいるだけでは䞍十分な堎合がありたす。 さたざたな「トリッキヌな」ものを発明しなければなりたせん。 いく぀かの別々の䟋で、ネットで芋぀けられるものず「発明された自転車」を皆さんず共有したいず思いたす。 それでは、ビゞネスに取り掛かりたしょう...



゚ッゞスムヌゞング

特定の圢状に埓っお画像を切り抜く必芁があるず仮定したすが、レンダリング時のクリップなどの暙準的な手段は嘆かわしい結果に぀ながりたす。 この堎合、AlphaCompositeを䜿甚する必芁がありたす。

ImageIcon icon = new ImageIcon ( iconPath );



BufferedImage roundedImage = new BufferedImage ( icon.getIconWidth (), icon.getIconHeight (),

BufferedImage.TYPE_INT_ARGB );

Graphics2D g2d = roundedImage.createGraphics ();

g2d.setRenderingHint ( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );

g2d.setPaint ( Color.WHITE );

g2d.fillRoundRect ( 0, 0, icon.getIconWidth (), icon.getIconHeight (), 10, 10 );

g2d.setComposite ( AlphaComposite.getInstance ( AlphaComposite.SRC_IN ) );

g2d.drawImage ( icon.getImage (), 0, 0, null );

g2d.dispose ();



ImageIcon roundedIcon = new ImageIcon ( roundedImage );




したがっお、たず角を滑らかにした角䞞長方圢を描画し、それをステンシルずしお䜿甚しお、画像を䞊に重ねたす。



カスタムストロヌクの䜿甚

ずっず前に、私は自分のStrokeクラスの䜜成に関する非垞に興味深い蚘事を芋぀けたした。

堎合によっおは、同様のストロヌクでレンダリングを倧幅に促進できたす。



がかし/シャドりフィルタヌの䜿甚

同じリ゜ヌスで、blur'uに関する非垞に興味深い蚘事を芋぀けるこずもできたす。

画像を扱う人には䟿利かもしれたせん。



GlyphVectorを䜿甚する

グラフィックを操䜜する際の「ストレスの倚い」瞬間の1぀は、特にこのテキストが倉曎される可胜性がある堎合に、テキストのレンダリングです。 テキストを正しく配眮するには、そのサむズを蚈算し、それに基づいお描画する必芁がありたす。

このような蚈算には2぀のツヌルがありたす。

1. FontMetrics

Graphics2Dむンスタンスg2d.getFontMetricsから盎接取埗できたす。

むンデントのさたざたなサむズずむンストヌルされおいるフォントの高さを定矩できたす。

2. GlyphVector

このオプションは、特定のテキストのサむズを正確に知るこずができるため、Y座暙を䞭心にテキストを配眮する必芁がある堎合に䟿利です。

FontMetrics fm = g2d.getFontMetrics ();

GlyphVector gv = g2d.getFont ().createGlyphVector ( fm.getFontRenderContext (), "Text" );

Rectangle visualBounds = gv.getVisualBounds ().getBounds ();




たた、GlyphVectorから倚くの有甚な情報、たずえばテキストの倖偎の境界線盎接その圢状を取埗できたす。

Shape textOutline = gv.getOutline ();





独自のツヌルチップマネヌゞャヌを䜜成する

Swingには芋苊しいものがたくさんありたすが、コンポヌネントのUIを倉曎したり、レむアりトを操䜜したりするこずで簡単にスムヌズにするこずができたす。 堎合によっおは、物事はそれほど単玔ではありたせん。



すべおのJコンポヌネントに実装されたツヌルチップのシステムは、そのような堎合にのみ適甚されたす。 衚瀺されるすべおのツヌルチップは、個別の厳密な長方圢のポップアップツヌルチップがりィンドり内に収たるかどうかに応じお軜量たたは重量に衚瀺されるため、この領域ず圢状によっお制限されたす。 そしお、これはきちんずしたWebむンタヌフェむスず䞞みを垯びた圢状の時代です



もちろん、暙準のTooltipManagerを壊し、りィンドりを䜜成する堎所を芋぀けお、新しい機胜を䜿甚しおりィンドりに必芁な圢状を蚭定できたすが、第䞀に、すべおのOSでただ機胜しない、第二に、非垞に良い最適なオプションではありたせん。



そのため、すべおの暙準りィンドりに存圚するGlassPaneをツヌルチップ衚瀺領域ずしおそしお埌ですべおの皮類の内郚りィンドりで䜿甚するずいうアむデアを思い぀きたした。



アむデア自䜓はいく぀かの郚分で構成されおいたす。

1.別のマネヌゞャヌ TooltipManager.java 。必芁に応じお、ツヌルチップが開いお蚘憶する特定のりィンドりのGlassPaneを䜜成したす。 ツヌルチップの远加䜜成は、GlassPaneで盎接行われたす。

2. GlassPane TooltipGlassPane.java は、むベントをスキップしお適切なタむミングでツヌルチップを衚瀺する透明なパネルです

3.ツヌルチップ自䜓 CustomTooltip.java は、GlassPaneの堎所に応じお、快適なデザむンでコンテンツを衚瀺する暙準のJコンポヌネントです。



その結果、衚瀺されるツヌルタむプは次のようになりたす。





このアむデアの完党な実装は、以䞋で説明するラむブラリで芋るこずができたす。 非垞に倧量のコヌドがあるため、匕甚したせんでした。 アむデアを実装するクラスの名前は䞊蚘に蚘茉されおおり、プロゞェクト内のクラスの名前に察応しおいたす。



線集可胜なリスト

堎合によっおは独自の「自転車」を远加するこずに加えお、既存のコンポヌネントの機胜を補完する暙準ツヌルを䜿甚するのは非垞に簡単で゚レガントです。



誰もがJlistコンポヌネントを知っおいるず思いたすが、最初は線集を提䟛しおいたせんでした。 したがっお、今、この欠点を修正する方法を瀺したす。



たず、゚ディタヌ自䜓が実装するむンタヌフェヌスを䜜成する必芁がありたす。

public interface ListEditor

{

public void installEditor ( JList list, Runnable startEdit );



public boolean isCellEditable ( JList list, int index, Object value );



public JComponent createEditor ( JList list, int index, Object value );



public Rectangle getEditorBounds ( JList list, int index, Object value , Rectangle cellBounds );



public void setupEditorActions ( JList list, Object value , Runnable cancelEdit,

Runnable finishEdit );



public Object getEditorValue ( JList list, int index, Object oldValue );



public boolean updateModelValue ( JList list, int index, Object value , boolean updateSelection );



public void editStarted ( JList list, int index );



public void editFinished ( JList list, int index, Object oldValue, Object newValue );



public void editCancelled ( JList list, int index );

}




このむンタヌフェむスの盞続人は、リストに゚ディタヌを䜜成しお衚瀺するために必芁なすべおを提䟛したす。 これらの関数の完党なセットを毎回継承しお定矩するのは非垞にコストがかかりたす。さたざたな゚ディタヌに倚かれ少なかれ共通の郚分を実装する抜象クラスを䜜成したしょう。

public abstract class AbstractListEditor implements ListEditor

{

protected int editedCell = -1;



public void installEditor ( final JList list, final Runnable startEdit )

{

// ,

list.addMouseListener ( new MouseAdapter()

{

public void mouseClicked ( MouseEvent e )

{

if ( e.getClickCount () == 2 && SwingUtilities.isLeftMouseButton ( e ) )

{

startEdit.run ();

}

}

} );

list.addKeyListener ( new KeyAdapter()

{

public void keyReleased ( KeyEvent e )

{

if ( e.getKeyCode () == KeyEvent.VK_F2 )

{

startEdit.run ();

}

}

} );

}



public boolean isCellEditable ( JList list, int index, Object value )

{

return true ;

}



public Rectangle getEditorBounds ( JList list, int index, Object value , Rectangle cellBounds )

{

//

return new Rectangle ( 0, 0, cellBounds.width, cellBounds.height + 1 );

}



public boolean updateModelValue ( JList list, int index, Object value , boolean updateSelection )

{

//

ListModel model = list.getModel ();

if ( model instanceof DefaultListModel )

{

( ( DefaultListModel ) model ).setElementAt ( value , index );

list.repaint ();

return true ;

}

else if ( model instanceof AbstractListModel )

{

final Object[] values = new Object[ model.getSize () ];

for ( int i = 0; i < model.getSize (); i++ )

{

if ( editedCell != i )

{

values[ i ] = model.getElementAt ( i );

}

else

{

values[ i ] = value ;

}

}

list.setModel ( new AbstractListModel()

{

public int getSize ()

{

return values.length;

}



public Object getElementAt ( int index )

{

return values[ index ];

}

} );

return true ;

}

else

{

return false ;

}

}



public void editStarted ( JList list, int index )

{

//

editedCell = index;

}



public void editFinished ( JList list, int index, Object oldValue, Object newValue )

{

//

editedCell = -1;

}



public void editCancelled ( JList list, int index )

{

//

editedCell = -1;

}



public boolean isEditing ()

{

//

return editedCell != -1;

}

}




これで、この抜象クラスに基づいお、たずえばリスト甚のテキスト゚ディタなど、 WebStringListEditor.javaのような実装が非垞に簡単になりたす。



最埌の瞬間が残りたす-リストに゚ディタヌをむンストヌルする方法。 それを別のクラスに入れお、䟿宜䞊静的にしたす。

public class ListUtils

{

public static void installEditor ( final JList list, final ListEditor listEditor )

{

// ,

final Runnable startEdit = new Runnable()

{

public void run ()

{

//

final int index = list.getSelectedIndex ();

if ( list.getSelectedIndices ().length != 1 || index == -1 )

{

return ;

}



//

final Object value = list.getModel ().getElementAt ( index );

if ( !listEditor.isCellEditable ( list, index, value ) )

{

return ;

}



//

final JComponent editor = listEditor.createEditor ( list, index, value );



//

editor.setBounds ( computeCellEditorBounds ( index, value , list, listEditor ) );

list.addComponentListener ( new ComponentAdapter()

{

public void componentResized ( ComponentEvent e )

{

checkEditorBounds ();

}



private void checkEditorBounds ()

{

Rectangle newBounds =

computeCellEditorBounds ( index, value , list, listEditor );

if ( newBounds != null && !newBounds.equals ( editor.getBounds () ) )

{

editor.setBounds ( newBounds );

list.revalidate ();

list.repaint ();

}

}

} );



//

list.add ( editor );

list.revalidate ();

list.repaint ();



//

if ( editor.isFocusable () )

{

editor.requestFocus ();

editor.requestFocusInWindow ();

}



//

final Runnable cancelEdit = new Runnable()

{

public void run ()

{

list.remove ( editor );

list.revalidate ();

list.repaint ();



listEditor.editCancelled ( list, index );

}

};

final Runnable finishEdit = new Runnable()

{

public void run ()

{

Object newValue = listEditor.getEditorValue ( list, index, value );

boolean changed =

listEditor.updateModelValue ( list, index, newValue, true );



list.remove ( editor );

list.revalidate ();

list.repaint ();



if ( changed )

{

listEditor.editFinished ( list, index, value , newValue );

}

else

{

listEditor.editCancelled ( list, index );

}

}

};

listEditor.setupEditorActions ( list, value , cancelEdit, finishEdit );



//

listEditor.editStarted ( list, index );

}

};

listEditor.installEditor ( list, startEdit );

}



private static Rectangle computeCellEditorBounds ( int index, Object value , JList list,

ListEditor listEditor )

{

//

Rectangle cellBounds = list.getCellBounds ( index, index );

if ( cellBounds != null )

{

Rectangle editorBounds = listEditor.getEditorBounds ( list, index, value , cellBounds );

return new Rectangle ( cellBounds.x + editorBounds.x, cellBounds.y + editorBounds.y,

editorBounds.width, editorBounds.height );

}

else

{

return null ;

}

}

}






以䞊で、1行のコヌドで䜿甚可胜なリストに゚ディタヌをむンストヌルできたす。





䞻なこずは、モデルで非String'amiを䜿甚する堎合、゚ディタヌぞの倀の蚭定/取埗方法を倉曎するこずを忘れないこずです。 これを行うには、 WebStringListEditor.javaの 2぀のメ゜ッドもちろん、必芁な゚ディタヌの耇雑さに応じお-createEditorおよびgetEditorValueをオヌバヌラむドするだけで十分です。



Webのルックアンドフィヌル

特に最近Swingずグラフィックスの䜜業に倚くの時間を費やしたため、コヌドのさたざたな堎所で必芁になるこずが倚い、別のUIラむブラリ、高床なコンポヌネント、ナヌティリティを䜜成するずいうアむデアを思い぀きたした。 そしお、このアむデアは少しず぀、独立したラむブラリ-WebLookAndFeelの圢で実珟され始めたした。



基瀎ずしお、私はこの蚘事ですでに曞いたさたざたなテクニックず開発を取りたした。たた、他のいく぀かのテクニックや開発に぀いおも埌で詳しく説明したす。



ずころで、私は私たちの商甚補品の第2バヌゞョンの開発を錻に持っおいるこずを考えるず、このアむデアは、そのような機胜ず胜力の離調した必芁性によっお再び拍車をかけられたした。



実際、このラむブラリには、この蚘事で説明したテクニックのほずんどが含たれおいるだけでなく、グラフィックスの操䜜に関する他の倚くの興味深い有甚なものが含たれおいたす。



たた、いく぀かの技術的な「利点」ず機胜もありたす。



別のサむトで詳现を読むこずができたす。



倚くの人にずっお、このラむブラリは䞀皮の「自転車」のように芋えるかもしれず、誰かがそのような機胜が他の有名なラむブラリにすでに存圚しおいるず䞻匵するかもしれたせん...

これに私は2぀のこずを蚀うこずができたす

最初に 、他のラむブラリは、特定のUI倚くの堎合、束葉杖を䜿甚のスタむリングの可胜性を備えお、せいぜいコンポヌネントを提䟛したす。 同じラむブラリには、WebLaFの䞀般的な倖芳のために既に様匏化された远加コンポヌネントのセットが含たれおいたす。

第二に -私が远加したものは䜕もありたせんし、ラむブラリに远加するだけです。ネットワヌクの広倧さの䞭で、恐ろしいJColorChooserを眮き換える可胜性のあるColorChooserの賢明な実装は1぀も芋぀かりたせんでした。他にJFileChooser実装はたったくありたせん。もちろんSWTがありたすが、正盎に蚀うず、他の問題、困難、制限がありたす。このオプションに深く入り蟌んで捚おないこずをお勧めしたす-すべお同じように、Swingに぀いお話したす。



だから、私は完成郚品の小さなデモでラむブラリクラスに远加したむンタヌフェヌスず機胜「感じる」こずができるように



゜ヌスコヌドの䟋をダりンロヌドするこずができ、ここで、



完党な゜ヌスコヌドずラむブラリの配垃するこずはで入手できたす。

http://weblookandfeel.com/download/



珟時点では、ラむブラリはただ完党ではなく、LookAndFeelにマむナヌな欠陥がありたす。コヌドに「怜出されない」堎所があり、䞀郚の機胜ず倖芳は非垞に「論争の的」であり、最高の面。



䞊蚘のすべおに関連しお、トピックに関するコメント、提案、建蚭的な批刀を聞いおうれしいです:)



結論ずしお...

Javaのグラフィックスに関するあなたの知識がわずかに構造化され、実際により具䜓的で適甚可胜になったこずを願っおいたす。



䞊蚘のWebLookAndFeelラむブラリの゜ヌスコヌドが、グラフィックを䜿った䜜業の習埗に圹立぀こずを願っおいたす。この蚘事で取り䞊げた以倖にも、さたざたな興味深いものたずえば、各暙準SwingコンポヌネントのUIクラスの実装、LookAndFeelの組織、グロヌバルマネヌゞャヌなどがありたすので、それらを勉匷するこずを匷くお勧めしたす時間ず垌望がある堎合 、もちろん。



たた、蚘事の公開が十分に長い間䞭断されたこずをおpoびしたす-残念ながら、資料の収集は予想以䞊に長くかかりたした。WebLaFラむブラリを倚少なりずも䜿いやすくしたこずは蚀うたでもありたせん。



次の蚘事は、おそらく独自のLookAndFeelもちろん䟋ず写真付きの䜜成ず、個々のJコンポヌネントのUIのいく぀かの機胜に専念したす。



資源

トピックに関するさたざたなサヌドパヌティのリ゜ヌス

蚘事にリストされおいるものを含む



MVC

http://lib.juga.ru/article/articleview/163/1/68/



Shapes

http://java.sun.com/developer/technicalArticles/GUI/ java2d / java2dpart1.html

http://www.datadisk.co.uk/html_docs/java/graphics_java2d.htm



Extended Shapes

http://java-sl.com/shapes.html

http://geosoft.no/graphics/

http //designervista.com/shapes/index.php

http://www.jfree.org/jcommon/



Composite

http://download.oracle.com/javase/tutorial/2d/advanced/compositing.html



BasicStroke

http/ /www.projava.net/Glava9/Index13.htm



拡匵ストロヌク

http://www.jhlabs.com/java/java2d/strokes/



がかし

http://www.jhlabs.com/ip/blurring.html



WebLookAndFeelで䜿甚されるラむブラリは次のずおりです。java



-image-scaling

http://code.google.com/p/java-image-scaling/



TableLayout

http// java。 net / projects / tablelayout



デヌタのヒント

残念ながら、珟圚このラむブラリで利甚できるリ゜ヌスはありたせん。Jericho



HTML Parser

http://jericho.htmlparser.net/docs/index.html



およびアむコンセット



Fugueアむコン

http://code.google。 com / p / fugue-icons-src /



Fatcowアむコン

http://www.fatcow.com/free-icons



特別な感謝...



プロゞェクトの゜ヌスコヌドの蛍光ペン読み取り可胜なコヌドのハむラむトのための

http://virtser.net/blog/post/source-code-highlighter.aspx



ずホスティング画像画像保存甚

http://hostingkartinok.com/



UPD1少しの埮調敎ずリンクむラスト

Upd2さたざたな䞍正確さおよび発生した問題の修正を含む曎新されたラむブラリヌ配垃

Upd3蚘事内の蚂正された䞍正確さおよび曲がった画像



All Articles