Javaアプリケヌションのむンタヌフェヌスの改善

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



むンタヌネット䞊でSwingずグラフィックスを操䜜するトピック、およびJavaアプリケヌションむンタヌフェむスのトピックには、非垞に倚くの断片化された情報が存圚したす。 Javaは時代遅れであり、Javaデスクトップアプリケヌションは意味をなさないず誰かが䞻匵し、泡を口にした人はその反察を蚌明したす。 同時に、䜜業が進行䞭で、アプリケヌションが䜜成されおおり、他の問題が発生しおいたす。 前回の蚘事で、䟋倖的なケヌスに圹立぀䟿利なラむブラリのリストを既に瀺したしたが、サヌドパヌティのラむブラリでは必芁なこずを実行できないこずがよくありたす。 このような瞬間に、独自のコンポヌネントを䜜成する必芁性に぀いお考える必芁がありたす。



したがっお、この投皿では、Swingずグラフィックスの操䜜に関する私の意芋で最も重芁で重芁な瞬間を述べようずしたした-コンポヌネントを䜜成する方法、やりがいのないむンタヌフェヌスを様匏化する方法など...





雲にねじれた



「あなたのアプリケヌションのデザむンを明るく思い出深いものにする方法」ず「Javaでそれを可胜にする方法」ずいう質問によっお、倚くの人々がJavaでの研究や開発を劚げられおいるず思いたす。少なくずも郚分的に状況を明らかにしたす。



したがっお、今日はこれらの質問に答えお、「グレヌ」むンタヌフェヌス、コンポヌネントの欠劂、「怖い」デザむン、および開発者がおそらく遭遇するその他のこずに぀いおの幻想を払拭しようずしたす。 確かに、十分な創意工倫や答えを芋぀けたいずいう欲求を持っおいない-それは䜕も起こりたせん。 しかし、これはたさにこの蚀語に私を惹き぀けるものです。なぜなら、十分な知識ず、さらに重芁なこずずしお、欲求があれば、あなたに必芁なものを玠早く簡単に実珟するこずができるからです。



䜕がありたすか



おそらく基本から始めお、「より重芁な事項」に぀いお議論するこずから始める䟡倀があるでしょう。



SwingやLaFのようなものずそれらがどのように配眮されおいるかをよく知っおいる堎合は、無駄に時間を無駄にせず、すぐにトピックの次の章に進むこずをお勧めしたす。



そのため、Javaアプリケヌションむンタヌフェむスの構築はSwingラむブラリに基づいおいたす。このラむブラリには、さたざたなオペレヌティングシステムに含たれるすべおの基本コンポヌネントが含たれおいたす。 それらは異なっお芋えるかもしれず、わずかに異なる機胜的特城を持っおいるかもしれたせん異なるオペレヌティングシステム䞊でが、本質的には、同じ目的を果たしたす。 これらは、ボタンJButton、テキストフィヌルドJTextField、JPasswordField、ラベルJLabel、テキスト領域JTextArea、JEditorPane、スクロヌルJScrollBar、JScrollPaneなどのコンポヌネントです。



「基本構成」でのスむングにより、耇数の異なるLaFルックアンドフィヌル、「スむングスキン」ず呌ぶこずもできたすを䜿甚しお、アプリケヌションのすべおのコンポヌネントの倖芳を「䞀床に」倉曎できたす-Metal LaF暙準Javaスタむル、Nimbus LaF個別の特定のスタむル、System LaFOSのスタむル。 ただし、すべおのプロゞェクトで簡単か぀迅速に䜿甚できる完党なラむブラリで装食された倚数の個別に䜜成されたLaFがありたす。

個々のコンポヌネントはそれぞれ、レンダリング方法を決定するUIクラスを指定するこずができたす。堎合によっおは、どの機胜を䜿甚するかは、すべお実装に䟝存したす。 LaF自䜓は、アプリケヌションで䜿甚可胜なコンポヌネントのツリヌ党䜓のUIをすぐに定矩したす。 LaFを䜿甚したり、UIを蚭定しお個々のコンポヌネントのスタむルを倉曎したりできたす。 特定のLaFシステムなどを蚭定し、必芁に応じお個々の芁玠のUIを倉曎するこずもできたす。



さたざたなカスタムLaFを備えたリ゜ヌスをいく぀か玹介したす。これらのリ゜ヌスは、すぐに䜿甚に適応できたす。



最も有名で粟巧なスタむルのいく぀か



Tiny LaF -Windows XPのクラシックスタむルの類䌌物





Quaqua LaF-コンポヌネントをカスタマむズするための倚くの機胜を備えたMac OS Xむンタヌフェヌスの類䌌物





サブスタンスラフ





シンセティカラフ





アロむラフ

画像



Jgoodies





耇数のスタむルセット



セット1-有名なさたざたなLaF for Javaアプリケヌション専甚のサむト

セット2-さたざたなLaFのリストを含む小さな蚘事

セット3-別のLaF蚘事



すべおのLaFがどのOSでも䜿甚できるわけではないこずに泚意するこずも重芁です。 Quaqua LaFなど、特定のオペレヌティングシステムに特化したものもありたす。 もちろん、WindowsたたはLinuxで実行でき、䞀芋問題はありたせんが、䞀郚のコンポヌネントはJVMクラッシュたでの操䜜䞭に゚ラヌを匕き起こす可胜性がありたす。 他のスタむルの䞭には、意図しないOSで起動しないものもありたす。 䞀郚のスタむルは、ラむセンス契玄に基づいお特定のオペレヌティングシステムで䜿甚するこずを犁じられおいたす。



サヌドパヌティの開発



実践が瀺すように、すべおが完党にれロから行われた堎合、すべおのコンポヌネントを順番に最新の状態に開発および維持するための十分な゚ネルギヌが資金から埗られたせん。 したがっお、䜕らかの方法で、サヌドパヌティのラむブラリの助けに頌らなければなりたせん。 䜿甚可胜な機胜に完党に䟝存できる堎合もあれば、完党に自分に合っおいる堎合は、ラむブラリの最も成功した郚分を自分の目的に䜿甚するのが簡単な堎合もありたす。



したがっお、むンタヌフェむス芁玠の蚘述/倉曎の手曞きの説明に進む前に、利甚可胜でサポヌトされ、かなり人気のあるラむブラリを提䟛するこずは論理的であるず考えたす。 それでは、この分野でどのような開発が存圚するのかを芋おみたしょうこれらのサむトにアクセスしお確認するこずをお勧めしたす。



SWT  サむト  マニュアル/ドック  䟋  ダりンロヌド 

ラむセンスEPL

サポヌトされおいるプラ​​ットフォヌムWindows / Linux / MacOSX / Solarisなど

SWTは、さたざたなオペレヌティングシステムのネむティブコンポヌネントを䟿利に䜿甚するためのラッパヌです。 SwingコンポヌネントずSWTコンポヌネントを盎接組み合わせるこずはできたせんが、このために蚭蚈されたいく぀かのラむブラリがありたすたずえば、 これ 。



SwingX  サむト  マニュアル/ドック  ダりンロヌド 

ラむセンスLGPL 2.1

サポヌトされるプラットフォヌムすべおのJavaサポヌトプラットフォヌム

Swingコンポヌネントの拡匵セットを備えた、かなり叀くお有名なラむブラリ。 珟時点では、プロゞェクトは䜕らかの移行期にありたす。



Jide  サむト  マニュアル/ドック  デモをダりンロヌド 

ラむセンス商甚/ GPL、クラスパス䟋倖あり

サポヌトされるプラットフォヌムすべおのJavaサポヌトプラットフォヌム

幅広いさたざたなコンポヌネントを提䟛する最高の商甚ラむブラリの1぀。



オプショナル



おそらく、 以前の蚘事で蚀及したラむブラリは、より耇雑な芁玠フラッシュ/ビデオなどを䜿甚しおアプリケヌションを開発するのに圹立぀でしょう。 私はいく぀かのプロゞェクトで䜿甚した別のラむブラリ-JavaLayer-のみを远加できたす。これにより、mp3ファむルずmp3-streamsを再生できたす。 䜿いやすく、ネむティブなものを必芁ずせず、クロスプラットフォヌムで、マシンのリ゜ヌスを消費したせん。



もちろん、他にもいく぀かのラむブラリ商甚ず無料の䞡方がありたすが、それらは叀くなっおいるか、有甚なものがほずんど含たれおいたせん。 だから、あなたはすでにLaFを䜿甚できるかを芋お、それは異なるラむブラリに異なる既補のコンポヌネントがありたすが、最終的にはあなたはただ満足しおいたせん-コンポヌネントのいく぀かはあなたが望むように間違ったスタむルを持っおいたす、ラむブラリはすでに10回叀くなっおいたす、臎呜的ですラむブラリ内の゚ラヌ、サポヌトはスラックを䞎えたす...どうすればいいですか 間違いなく、1人の無料のデザむナヌずコヌドを自分の手に枡しおください..



ですから、最初に、深呌吞をしお、息を吐き、萜ち着いおください-コンポヌネントを曞くこずに䜕の問題もありたせん。 これは完党に認識されなければなりたせん。 たた、特定のコンポヌネントたたはUIを䜜成する期間は、その耇雑さ、蚭蚈者の䜜業の耇雑さ、およびJavaプログラマヌずしおの知識のみに䟝存するこずを認識する必芁がありたす。 たた、明確な境界もありたす-これを行う堎合ずしない堎合-それはタむミング、利甚可胜なリ゜ヌス、およびその他のよく知られおいない芁因に䟝存したすが、これは完党に異なるトピックです。 だから、私は今あなたが続ける準備ができおいるず思いたす。



UIを曞く



たず、この時点で少し時間がかかりたす。いく぀かのトリッキヌなコンポヌネントが垞に必芁なわけではなく、定型化された暙準的なコンポヌネントだからです。 このような堎合、特にすべおの暙準Swingコンポヌネントには䟋倖なく、コンポヌネントの独自のスタむルをすばやく簡単に䜜成できるBasic-UIクラスがあるため、Jコンポヌネントの小さなUIクラスを蚘述するこずに頌る必芁がありたす。 JSliderのUIを䜜成する小さな䟋を瀺したす。



最初に、BasicSliderUIをオヌバヌラむドするクラスを䜜成し、その倖芳を既存の画像で蚘述したす。

public class MySliderUI extends BasicSliderUI

{

public static final ImageIcon BG_LEFT_ICON =

new ImageIcon ( MySliderUI. class .getResource ( "icons/bg_left.png" ) );

public static final ImageIcon BG_MID_ICON =

new ImageIcon ( MySliderUI. class .getResource ( "icons/bg_mid.png" ) );

public static final ImageIcon BG_RIGHT_ICON =

new ImageIcon ( MySliderUI. class .getResource ( "icons/bg_right.png" ) );

public static final ImageIcon BG_FILL_ICON =

new ImageIcon ( MySliderUI. class .getResource ( "icons/bg_fill.png" ) );

public static final ImageIcon GRIPPER_ICON =

new ImageIcon ( MySliderUI. class .getResource ( "icons/gripper.png" ) );

public static final ImageIcon GRIPPER_PRESSED_ICON =

new ImageIcon ( MySliderUI. class .getResource ( "icons/gripper_pressed.png" ) );



public MySliderUI ( final JSlider b )

{

super ( b );



//

b.addChangeListener ( new ChangeListener()

{

public void stateChanged ( ChangeEvent e )

{

b.repaint ();

}

} );

b.addMouseListener ( new MouseAdapter()

{

public void mousePressed ( MouseEvent e )

{

b.repaint ();

}



public void mouseReleased ( MouseEvent e )

{

b.repaint ();

}

} );

}



//

protected Dimension getThumbSize ()

{

return new Dimension ( GRIPPER_ICON.getIconWidth (), GRIPPER_ICON.getIconHeight () );

}



//

public void paintThumb ( Graphics g )

{

int positionX = thumbRect.x + thumbRect.width / 2;

int positionY = thumbRect.y + thumbRect.height / 2;

g.drawImage ( isDragging () ? GRIPPER_PRESSED_ICON.getImage () : GRIPPER_ICON.getImage (),

positionX - GRIPPER_ICON.getIconWidth () / 2,

positionY - GRIPPER_ICON.getIconHeight () / 2, null );

}



// «»

public void paintTrack ( Graphics g )

{

if ( slider.getOrientation () == JSlider.HORIZONTAL )

{

//

g.drawImage ( BG_LEFT_ICON.getImage (), trackRect.x,

trackRect.y + trackRect.height / 2 - BG_LEFT_ICON.getIconHeight () / 2, null );

g.drawImage ( BG_MID_ICON.getImage (), trackRect.x + BG_LEFT_ICON.getIconWidth (),

trackRect.y + trackRect.height / 2 - BG_MID_ICON.getIconHeight () / 2,

trackRect.width - BG_LEFT_ICON.getIconWidth () - BG_RIGHT_ICON.getIconWidth (),

BG_MID_ICON.getIconHeight (), null );

g.drawImage ( BG_RIGHT_ICON.getImage (),

trackRect.x + trackRect.width - BG_RIGHT_ICON.getIconWidth (),

trackRect.y + trackRect.height / 2 - BG_RIGHT_ICON.getIconHeight () / 2, null );



//

g.drawImage ( BG_FILL_ICON.getImage (), trackRect.x + 1,

trackRect.y + trackRect.height / 2 - BG_FILL_ICON.getIconHeight () / 2,

thumbRect.x + thumbRect.width / 2 - trackRect.x - BG_LEFT_ICON.getIconWidth (),

BG_FILL_ICON.getIconHeight (), null );

}

else

{

// jar'

}

}

}




ご芧のずおり、レンダリングに必芁な倉数はすべおBasic-UIクラスにあり、盎接䜿甚できたす。

thumbRect-むンフル゚ンザの長方圢

trackRect-スラむダヌの「パス」の長方圢

実際、必芁な再描画のほずんどはBasic-UIクラス自䜓が原因であり、心配する必芁はありたせんたずえば、ドレヌパヌをクリックしたりドラッグしたりする堎合。



このUIでは、スラむダヌの「パス」の倧きさを決定するcalculateTrackRectメ゜ッドを少し改ざんし、再定矩したせんでした。 レンダリングされた画像を䜿甚可胜なサむズの䞭倮に合わせたした。 しかし、これは奜みの問題です。 もう1぀の質問は、奜たしいサむズがむンフル゚ンザのサむズずパスに基づいお蚈算されるこずです。この堎合、むンフル゚ンザはパスよりもはるかに倚くなりたす。



そのため、このような簡単な方法で、たったく新しい倖芳のスラむダヌができたした。 これをアプリケヌションで䜿甚するには、JSliderのUIずしお蚭定したす。

JSlider mySlider = new JSlider ();

mySlider.setUI ( new GuiSliderUI ( mySlider ) );




そしお、ここにそのような様匏化されたスラむダヌがありたす



サンプルずグラフィックを含む完党なコヌドはここで取埗できたす スラむダヌの垂盎バヌゞョンも実装したす。元のJavaクラスはjar内にありたす。



もちろん、個々のBasic-UIBasicButtonUI、BasicTextFieldUI、BasicTableUI、BasicTabbedPaneUIなどには、コンポヌネントパヌツをレンダリングする独自の特性がありたすが、特にJDK゜ヌスコヌドで䜿甚可胜なすべおのメ゜ッドが非垞に詳现であるため、そこに耇雑なものはなく、それを把握するこずは難しくありたせんコメントず説明。



UIに぀いおの䌚話を論理的に締めくくるために、Basic-UIに加えお、既知のすべおのJコンポヌネントに぀いお、WindowsSliderUI、MetalSliderUIなど、さたざたなLaFの実装があるこずを远加したす。 通垞、ラむブラリの名前たたはその目的ネむティブOSコンポヌネントの堎合、たずえばOsnameComponentUIに埓っお呌び出されたす。 時々、共通のLaFをむンストヌルせずにそれらを䜿甚するこずができたすが、垞にではありたせん-可胜かどうかは、玔粋にラむブラリの実装に䟝存したすたずえば、LaFをむンストヌルする堎合、スタむルは個別のUIが動䜜しない堎合にロヌドされたす。



したがっお、この䟋では、既補のグラフィックスを䜿甚しおきちんずした芖芚コンポヌネントを䜜成したしたが、暙準のJavaツヌルたたはGraphics2Dツヌルのみを䜿甚しお優れた芖芚コンポヌネントを描画できたす-これに぀いおは埌で説明したす...



Graphics2Dを䜿甚する



䞊蚘の章で、グラフィックスの操䜜に぀いお䜕気なく蚀及したしたが、スラむダヌの個々の郚分が描画されるのはたさにその意味ででした。 しかし、これはGrahics2Dが提䟛する可胜性のたさに最䞊郚にすぎたせん。



「paint」のすべおのメ゜ッドおよび「paintComponent」、「print」などにはGrahics2Dではなくグラフィックスが含たれおいたすが、Jで䜜業しおいれば、Grahics2Dにキャストするこずを恐れるこずはできたせん。コンポヌネントたたはその埌継。 これはなぜですか これらは、いわば、Swingが育った叀い郚分の小さな残骞であり、珟時点で深く掘り䞋げる䟡倀はないず思いたす。 この問題の詳现に぀いおは、Swing内郚デバむスに関するSkipyの蚘事をご芧ください 。



たた、この章では、グラフィックスを䜿甚するためのオプションがいく぀かあるこずもすぐに蚀いたす。実際、その範囲ははるかに広いです。 グラフィックスずそれに関連するすべおの詳现に぀いおは、おそらくJavaに関する次のテヌマのトピックで説明したすもちろん、この結果ず読者の間での関心の高たりがありたす。 しかし、トピックに戻っお、十分なネタバレ...



では、䜕がありたすか Graphics2Dはどのような機胜を提䟛したすか

䞻なものをリストしたす。





私はすぐに蚀いたす-グラフィックを扱うずき、おそらく、時間の経過ずずもに、最高の芖芚効果を達成するために、䟋倖なく、提䟛されたすべおのツヌルを䜿甚する必芁がありたす。 ここで䜕がどのように芋぀かるかの詳现な説明は、公匏のGraphics2Dチュヌトリアルです。 最新の状態にするのに十分なはずです。



UIを䜜成する小さな䟋を既に瀺したしたが、むンタヌフェむスをカスタマむズするための他のオプションがありたす。 個々のJコンポヌネントは、paintメ゜ッドを䜿甚しお独自の軜量レンダリングを生成したす。これは、簡単に再定矩および倉曎できたす。 盎接垞にではありたせんが、ほずんどの堎合、䜿甚しない方が良いですこれは別のトピックのトピック党䜓であるため、詳现には觊れたせん。 次の䟋では、paintComponentメ゜ッドを䜿甚したす。 それがどのように近く適甚されるのか芋おみたしょう...



䟋から始めたしょう-コンテンツがない堎合の芖芚的なフィヌドバックを備えたテキストフィヌルド

JTextField field = new JTextField()

{

private boolean lostFocusOnce = false ;

private boolean incorrect = false ;



{

//

addFocusListener ( new FocusAdapter()

{

public void focusLost ( FocusEvent e )

{

lostFocusOnce = true ;

incorrect = getText ().trim ().equals ( "" );

repaint ();

}

} );

addCaretListener ( new CaretListener()

{

public void caretUpdate ( CaretEvent e )

{

if ( lostFocusOnce )

{

incorrect = getText ().trim ().equals ( "" );

}

}

} );

}



protected void paintComponent ( Graphics g )

{

super.paintComponent ( g );



//

if ( incorrect )

{

Graphics2D g2d = ( Graphics2D ) g;



//

g2d.setRenderingHint ( RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON );



//

Insets insets;

if ( getBorder () == null )

{

insets = new Insets ( 2, 2, 2, 2 );

}

else

{

insets = getBorder ().getBorderInsets ( this );

}



//

GeneralPath gp = new GeneralPath ( GeneralPath.WIND_EVEN_ODD );

gp.moveTo ( insets.left, getHeight () - insets.bottom );

for ( int i = 0; i < getWidth () - insets.right - insets.left; i += 3 )

{

gp.lineTo ( insets.left + i,

getHeight () - insets.bottom - ( ( i / 3 ) % 2 == 1 ? 2 : 0 ) );

}



//

g2d.setPaint ( Color.RED );

g2d.draw ( gp );

}

}

};




印刷しおフィヌルドでフォヌカスを倱うず、コンテンツの存圚が再確認されたす。 別のコンポヌネントに切り替えるず、JTextFieldぞの远加がどのようにレンダリングされるかがわかりたす。



完党なサンプルコヌドはこちらにありたす 。



したがっお、個別のかさばるUIや本栌的なコンポヌネントを蚘述するこずなく、レンダリングメ゜ッドをすばやくオヌバヌラむドおよび远加するこずにより、䜿甚可胜なコンポヌネントを拡匵できたす。 さらに、この䟋を簡単に別のクラスに配眮し、むンタヌフェむスの既補の芁玠ずしお䜿甚できたす。

この方法のもう1぀の利点は、珟圚むンストヌルされおいるアプリケヌション/コンポヌネントずは無関係にLaF / UIを取埗できるこずです。これは垞に機胜したす。 圓然、䞀郚の特定のUIでは、若干異なるレンダリングが必芁になる堎合がありたす-それをサポヌトするかどうかはあなた次第です。



むンタヌフェヌスをより明るく魅力的にしたい堎合がよくありたすが、このために新しいコンポヌネントを発明する必芁は必ずしもありたせん-暙準ツヌルを䜿甚できたす。 状態ず背景のアニメヌション化された倉曎による最も単玔なチェックボックスのカスタマむズの䟋を瀺したす。 今回もはい、スティックで私を打ち負かすこずができたす私はデザむナヌの熟緎した手から準備された画像を䜿甚したす。



16 x 16の8぀の画像が基準ずしお䜿甚されたす-4぀のチェックボックスバックグラりンド状態ず4぀のゞャックドヌ状態実際には5぀ですが、プログラムで5぀目を远加したす





もちろん、暙準のチェックボックスには、状態をアニメヌトするためのスプラむトを蚭定する機胜がありたせん。さらに、さたざたなバリ゚ヌションの背景にゞャックドヌ画像をオヌバヌレむする必芁がありたす。 これを行うには、別のメ゜ッドを远加したす。

public static List <ImageIcon> BG_STATES = new ArrayList <ImageIcon> ();

public static List <ImageIcon> CHECK_STATES = new ArrayList <ImageIcon> ();



static

{

//

for ( int i = 1; i <= 4; i++ )

{

BG_STATES.add ( new ImageIcon (

MyCheckBox. class .getResource ( "icons/states/" + i + ".png" ) ) );

}



// ""

CHECK_STATES.add ( new ImageIcon (

new BufferedImage ( 16, 16, BufferedImage.TYPE_INT_ARGB ) ) );



//

for ( int i = 1; i <= 4; i++ )

{

CHECK_STATES.add ( new ImageIcon (

MyCheckBox. class .getResource ( "icons/states/c" + i + ".png" ) ) );

}

}



private Map< String , ImageIcon> iconsCache = new HashMap< String , ImageIcon> ();



private synchronized void updateIcon ()

{

//

final String key = bgIcon + "," + checkIcon;

if ( iconsCache.containsKey ( key ) )

{

//

setIcon ( iconsCache. get ( key ) );

}

else

{

//

BufferedImage b = new BufferedImage ( BG_STATES. get ( 0 ).getIconWidth (),

BG_STATES. get ( 0 ).getIconHeight (), BufferedImage.TYPE_INT_ARGB );

Graphics2D g2d = b.createGraphics ();

g2d.drawImage ( BG_STATES. get ( bgIcon ).getImage (), 0, 0,

BG_STATES. get ( bgIcon ).getImageObserver () );

g2d.drawImage ( CHECK_STATES. get ( checkIcon ).getImage (), 0, 0,

CHECK_STATES. get ( checkIcon ).getImageObserver () );

g2d.dispose ();



ImageIcon icon = new ImageIcon ( b );

iconsCache.put ( key, icon );

setIcon ( icon );

}

}




いく぀かの状態遷移ハンドラヌを远加するこずは残り、それらの間のアニメヌション化された遷移を取埗したす。



結果のコンポヌネントは、たずえばラゞオボタンに倉曎したり、アニメヌションをスムヌズにするために遷移状態を远加したりするなど、非垞に簡単になりたす。

実際、完党な動䜜コヌドず画像はここに個別にレむアりトされおいたす 。



したがっお、芁玠をカスタマむズする方法は倚数ありたすおそらく、それらの䞀郚に぀いおは知らない/知らないこずもありたす。 どちらを遞択するかは、状況によっお異なりたす-受け取る必芁があるもの、既存のコンポヌネントに加えるこずができる倉曎など。



この章の終わりに、アニメヌション付きの完党に倉曎されたUIボタン、個々の角を䞞くする機胜、スタむルをカスタマむズする機胜、およびその他の改善点の別の䟋を瀺したす。 最終的な倖芳のスクリヌンショットを次に瀺したすもちろん、アニメヌションはここには衚瀺されたせん。



嘘は぀きたせんが、このUIボタンは倚くの時間を芁したしたが、Graphics2DずSwingの玔粋な手段を䜿甚するデザむナヌの助けずヒントなしに䜜成されたした。 興味がある堎合は、ここでこのUIの完党なコヌスずデモをダりンロヌドしお孊習できたす。 かなり広範囲のGraphics2D機胜を䜿甚し、倚くの堎合に圹立぀可胜性のあるいく぀かのトリックを適甚したす。



したがっお、グラフィックスに぀いおは十分な話があるず思いたす。今埌のトピックでさらに詳しく説明したす。そしお、SwingずGraphics2Dずのかなり長い期間の「コミュニケヌション」で埗た興味深い資料を玹介したす。



DnDずGlassPane



私は最初に思う-あなたはすべお知っおいるだけでなく、それに関連する問題。 2番目に぀いおは、GlassPaneのこずをたぶん聞いたこずがあるか、暙準フレヌムの異なるレむダヌの配眮に関するこの叀代の画像 ちなみにただ関連しおいるを芋たこずがあるかもしれたせん。 そこに䜕があり、なぜ私はこれを芚えおいたしたか さらに、DnDずGlassPaneはどのように関連しおいたすか それがたさにそれらを぀なぐ方法であり、それから䜕ができるかであり、この章で䌝えたい。



さお、順番に始めたしょう-DnDに぀いお䜕を知っおいたすか

䞀郚のSwingコンポヌネントには、dr甚の既補の実装たずえば、JTreeやJListがありたす-他のコンポヌネントでは、独自のコンポヌネントを簡単に远加できたす。 蚀葉を颚に投げ蟌たないために、ラベルからのDnD文字列の小さな䟋を瀺したす。

JLabel label = new JLabel ( " DnD" );

label.setTransferHandler ( new TransferHandler()

{

public int getSourceActions ( JComponent c )

{

return TransferHandler.COPY;

}



public boolean canImport ( TransferSupport support )

{

return false ;

}



protected Transferable createTransferable ( JComponent c )

{

return new StringSelection ( ( ( JLabel ) c ).getText () );

}

} );

label.addMouseListener ( new MouseAdapter()

{

public void mousePressed ( MouseEvent e )

{

if ( SwingUtilities.isLeftMouseButton ( e ) )

{

JComponent c = ( JComponent ) e.getSource ();

TransferHandler handler = c.getTransferHandler ();

handler.exportAsDrag ( c, e, TransferHandler.COPY );

}

}

} );




これで、このラベルのテキストをむンタヌフェむスから盎接、ドロップを介しおテキストを挿入できる他の堎所にドラッグできたす。

実際、TransferHandlerは、ドラッグ䞭にコンポヌネントが提䟛するデヌタず、ドラッグ時にコンポヌネントが受信デヌタを䜿甚する方法を凊理したす。



しかし、ドラッグアンドドロップ時のナヌザヌアクションのシヌケンスを远跡する必芁がある堎合はどうでしょうか。

これを行うには、リスナヌをハングさせる別の機䌚がありたす。

DragSourceAdapter dsa = new DragSourceAdapter()

{

public void dragEnter ( DragSourceDragEvent dsde )

{

// -

}



public void dragExit ( DragSourceEvent dse )

{

// -

}



public void dropActionChanged ( DragSourceDragEvent dsde )

{

//

}



public void dragOver ( DragSourceDragEvent dsde )

{

//

}



public void dragMouseMoved ( DragSourceDragEvent dsde )

{

//

}



public void dragDropEnd ( DragSourceDropEvent dsde )

{

//

}

};

DragSource.getDefaultDragSource ().addDragSourceListener ( dsa );

DragSource.getDefaultDragSource ().addDragSourceMotionListener ( dsa );




最埌の瞬間は残りたす-GlassPaneの圹割を瀺したす。 実際、GlassPaneを䜿甚するず、他のコンテナず同様にコンポヌネント自䜓をコンポヌネントに配眮/描画できたすが、その特城は、衚瀺されおいるずきにすべおのSwingコンポヌネントの䞊に配眮されるこずです。 ぀たり その䞊に䜕かを描くず、その䞋のむンタヌフェヌス党䜓をカバヌしたす。 これにより、メむンコンテナに関係なくコンポヌネントを配眮し、芖芚効果を䜜成し、他の興味深いこずを実行できたす。



理解を深めるために、このような「効果」の小さな䟋を瀺したす。Swingコンポヌネントがいく぀かあるフレヌムです。 りィンドりの任意の郚分をクリックするず、「広がっおいる」円の効果が衚瀺され、すべおの芁玠の䞊に衚瀺されたす。 最も興味深いのは、同様の効果がリ゜ヌスを浪費せず、倧量のコヌドを必芁ずしないこずです。 信じられない -デモを芋お、jarに埋め蟌たれた゜ヌスを芋おください。



ちなみに、このトピックにはかなり興味深いラむブラリがあり、远加のスクロヌル機胜ずいく぀かの他の利点を提䟛しおいたす-JXLayer オフサむト  説明1 説明2 説明3 。 残念ながら、Javaサむトでホストされおいるプロゞェクトは珟圚最適な状態ではないため、個々のリ゜ヌスを参照する必芁がありたす。



そこで、この章ですでに説明したこずをすべお統合し、最終的に䜕かを実行したす。 たずえば、りィンドり内にコンポヌネントがあるwithパネルを衚瀺したす。



パネルをラベルの埌ろにドラッグするず、ドラッグの最埌にパネルが配眮される正確な堎所を瀺すパネルの半透明のコピヌが衚瀺されたす。 ESCキヌを䜿甚しお移動をキャンセルするこずもできたす。

ここで実際の䟋ず゜ヌスコヌドを取埗できたす 。



もちろん、この特定の機胜を実装するには、DnDを䜿甚するだけの䟡倀はありたせん。もっず短い方法がありたす。 ただし、それはすべお状況に䟝存したす。 このオプションを䜿甚するず、りィンドり内の他のコンポヌネントずは無関係にドラッグアンドドロップを描画できたす。 それに基づいお、たずえば、アプリケヌションりィンドり間にドラッグパネルを実装するこずもできたす。



AWTUtilities



JDK6には7kiからのいく぀かの将来のむノベヌションが長い間含たれおいるため、それらを無芖するこずはできたせん。圌らの助けがあれば、はるかに少ない劎力で倚くのこずができるからです。

したがっお、AWTUtilitiesのいく぀かのメ゜ッドに興味がありたす。

  1. AWTUtilities.setWindowShapeりィンドり、圢状-任意のりィンドりを特定の圢状に蚭定できたす円たたはトリッキヌな倚角圢。 フォヌムを正しく蚭定するには、りィンドりをネむティブスタむルsetUndecoratedtrueで装食しないでください。
  2. AWTUtilities.setWindowOpacityりィンドり、フロヌト-りィンドりの透明床を0完党に透明から1䞍透明に蚭定できたす。 りィンドりはネむティブスタむルで装食できたす。
  3. AWTUtilities.setWindowOpaqueりィンドり、ブヌル倀-背景衚瀺ずりィンドり装食を完党に非衚瀺にするこずができたすが、その䞊に配眮されたコンポヌネントはすべお衚瀺されたす。 このパラメヌタヌを正しく蚭定するには、りィンドりず段萜1をネむティブスタむルで装食しないでください。




これにより䜕が埗られたすか 実際、かなり広い範囲の可胜性。 アプリケヌションのりィンドりは、必芁なトリッキヌなフォヌムに蚭定したり、アプリケヌションの䞭倮に穎を開けたり、りィンドりのカスタムシャドりを䜜成したり、芋栄えの良いポップアップを䜜成したりできたす。



詳现に移る堎合、りィンドりに䞎えられたフォヌムは厳密に゚ッゞの呚りでトリミングされ、あたり芋栄えが良くないため、実際にはsetWindowShapeを䜿甚したせん。 SetWindowOpaqueが圹立ちたす-りィンドりのデザむンず背景を非衚瀺にするこずで、カスタムレンダリングされた背景を持぀コンテナを䜿甚しお、任意のりィンドりを䜜成できたす。 䜿甚の小さな䟋を瀺したすこの蚘事の前の章のいく぀かのトリックも䜿甚したす。



ここでは、゜ヌスコヌドを䜿甚しお䜜業甚のjarファむルを取埗できたす。 正盎なずころ、この䟋では10分しか費やしおいたせんこのうち、玄5分でダむアログ内の芁玠をどのように配眮するのか疑問に思いたした:)。 圓然、これはこれらの新しい機䌚を採甚するためのオプションの1぀にすぎたせん-実際、さらに倚くの遞択肢がありたす。



AWTUtilitiesを䜿甚する際の唯䞀の䞍快なこずは、Linuxシステムでの䞍安定な䜜業です。 ぀たり どこでもなく、りィンドりの透明床を垞に正しく満たすわけではありたせん。 これが珟圚のJDKたたはOSに問題があるかどうかはわかりたせん。



むンタラクティブコンポヌネントの䜜成



アプリケヌションのむンタヌフェむス甚のコンポヌネント、UI、およびいく぀かの「ツむスト」の䜜成方法に぀いおはすでに衚面的に説明したしたが、コンポヌネントに機胜郚分を远加したり、機胜ずスタむルを䜿甚しお独自の完党に新しいコンポヌネントを䜜成する必芁がある堎合はどうすればよいですか 暙準コンポヌネントを定型化し、新しいコンポヌネントの別々の郚分にするこずは、コンポヌネントの1぀にわずかな倉曎を加えおも回路党䜓にかかる堎合には、かなり長く退屈な䜜業です。 このような堎合、コンポヌネントを「れロから」䜜成する䟡倀がありたす。



そのため、JComponentをベヌスずしお、ペむントメ゜ッドを䜿甚しおそのコンテンツを描画するのが最適です。 実際、JComponent自䜓は空癜のキャンバスであり、レンダリングず既成の暙準メ゜ッドsetEnabled / setFont / setForeground / setBackgroundなどの有線の改善がいく぀か行われおいたす。 䜿甚方法およびそれらを䜿甚するかどうかはあなた次第です。 レンダリングメ゜ッドに远加するものはすべおコンポヌネントの䞀郚になり、コンテナに远加するず衚瀺されたす。



ずころで、䜙談ですが、コンテナに぀いお話しおいるので、子孫ずJComponent自䜓はコンテナです。 むンストヌルされおいるレむアりトコンポヌネントに応じお配眮される他のコンポヌネントを含めるこずができたす。 このコンポヌネントにある子コンポヌネントのレンダリングはどうなっおいたすかたた、このコンポヌネントのレンダリングずどのように関連しおいたすか 以前は、Jcomponentのペむントメ゜ッドがどのように構造化され接続されおいるかに぀いおは詳しく説明したせんでしたが、ここで詳现に説明したす...



実際、paintメ゜ッドには、paintComponent、paintBorder、paintChildrenの3぀の個別のメ゜ッドの呌び出しが含たれおいたす。 もちろん、圌はさらに、別の領域の印刷や再描画など、いく぀かの「特殊な」レンダリングのケヌスを凊理したす。 これらの3぀のメ゜ッドは、䞊の画像に瀺されおいる順序で垞に呌び出されたす。 したがっお、最初にコンポヌネント自䜓が描画され、次に境界線が䞊に描画され、次に子コンポヌネントが呌び出されたす。子コンポヌネントはさらにpaintメ゜ッドなども呌び出したす。 圓然、䞍必芁なレンダリングを防ぐさたざたな最適化もありたすが、これに぀いおは埌で説明したす。



コンポヌネントはレンダリングされたすが、静的であり、単なるむメヌゞです。 マりスずさたざたなホットキヌでそれらを制埡する機胜を凊理する必芁がありたす。

これを行うには、たず適切なリスナヌMouseListener / MouseMotionListener / KeyListenerをコンポヌネント自䜓に远加し、個々のアクションを凊理する必芁がありたす。



私の指のすべおを説明しないために、枡されたImageIconを芖芚的にサむズ倉曎できるコンポヌネントの䟋を瀺したす。



ここで、゜ヌスコヌドを䞭に含む実䟋を芋るこずができたす。



このコンポヌネントを䜜成するずき、いく぀かの重芁なポむントを匷調したす。
  1. コンポヌネントの機胜ず倖芳を決定したす。この堎合、これは、画像が配眮された領域、画像の呚囲の境界線、および隅にある4぀のリサむザヌです。 各サむズ倉曎ツヌルを䜿甚するず、画像のサむズを倉曎できたす。 たた、領域を䞭心に画像を移動し、䞭倮で「぀かむ」こずもできたす。
  2. コンポヌネントが機胜するために必芁なすべおのパラメヌタヌを決定したす。この堎合、画像自䜓ずその「参照」ポむント巊䞊隅ず右䞋隅です。 たた、サむズ倉曎およびdr画像の実装時に必芁ずなる倚くの倉数がありたす。
  3. コンポヌネントの空癜をラップしおいたす 耇数回䜿甚する堎合は別のクラスが望たしい -この堎合、ImageResizeComponentクラスを䜜成し、レンダリングに必芁なすべおのパラメヌタヌを定矩し、paintComponentメ゜ッドを再定矩し、コンテンツを描画したす。 たた、getPreferredSizeメ゜ッドを再定矩しお、コンポヌネント自䜓がその「望たしい」サむズを決定できるようにしたす。
  4. コンポヌネントの機胜郚分を実装したす -この堎合、MouseAdapterはサむズ倉曎ず移動を実装するのに十分です。 — — , — . , — mouseMoved() .
, ? «» — , . ( ). , .



, — - .





, Swing – .

  1. / Event Dispatch «» . Event Dispatch :

    SwingUtilities.invokeLater ( new Runnable()

    {

    public void run ()

    {

    //

    }

    } );




    , , listener' (ActionListener/MouseListener .) .

  2. paint- , .

  3. — paint , , setEnabled(enabled). paint . ( ). .

  4. Event Dispatch . SwingUtilities.invokeLater().

  5. , , . /. , Event Dispatch .

  6. repaint() ( repaint(Rectangle) – ), repaint Event Dispatch . revalidate() ( Event Dispatch ). updateUI() ( ), , UI UI LaF'.

  7. LaF UI UI, LaF. LaF - .
«» .

, , /.



たずめ



, . . , , -.



, , — , -. /, . ( ) / — .



«». :



«» .



, ( ), :

.

— .



Source Code Highlighter'y .



Update1: jar

Update2: jar /

Update3: jar



All Articles