Transcript
Page 1: N 半透明ウィンドウのさらなる応用 - oracle.com€¦ · を表します。コンピュータの画像はピ クセルの配列であり、色 の4要素のうち1つ以上

ORACLE.COM/JAVAMAGAZINE /////////////// MAY/JUNE 2012

JAVA TECH

30

COMMUNITY

JAVA IN ACTION

ABOUT US

blog

//java architect /

Java SE 7の優れた新機能の1つに、非矩形ウィンドウおよび半

透明ウィンドウの正式サポートがあります。非矩形ウィンドウは、以前からさまざまなテクニックを使用して実現されてきましたが、近年、各種オペレーティング・システムにおいてネイティブでサポートされ始めました。Java SE 6のアップデートで、非矩形ウィンドウはプライベートAPIとしてネイティブでサポートされましたが、Java SE 7からはJava SEの正式機能となりました。非矩形ウィンドウや半透明ウィン

ドウを使用すると、以前は不可能であった手法でアプリケーションの機能を強化できます。本記事では非矩形ウィンドウおよび半透明ウィンドウの技術について深く掘り下げ、そのテクニックを使用してアプリケーションの機能を強化するための高度な手法を紹介します。本記事に沿って実際にコーディングを行う場合は、プロジェクトのソース・コードをすべてダウンロードしてください。本記事では、非矩形ウィンドウおよ

び半透明ウィンドウの概念とAPIに読者が精通していることを前提とします。これらの概念やAPIになじみがな

い場合は、この話題に関するオラクルのチュートリアルを参照してください。Java SE 7のAPIには、ウィンドウ効果として、非矩形ウィンドウ、半透明ウィンドウ、さらに、アルファ・チャネルを使用したウィンドウの3種類が用意されています。ただし、非矩形ウィンドウと半透明ウィンドウについては、実用性が限られており、かつ一般的な使用方法のほとんどが標準的なチュートリアルですでに解説されているため、本記事では対象としません。第3の 完全なアルファ・チャネルを使用したウィンドウに焦点を置いて説明します。

背景ピクセル単位のアルファ・チャネルを使用したウィンドウは、各ピクセルの透明度を個別に指定できるため、非矩形ウィンドウや半透明ウィンドウよりも強力です。非矩形ウィンドウは、単に矩形でないウィンドウです。可視のピクセルの不透明度はすべて100%ですが、ウィンドウを円形などのさまざまな形状にすることができます。半透明ウィンドウでは、ウィンドウ全体に単一の透明度の値を設定します。ウィンドウ全体を半透明にする

場合は便利ですが、それよりも高度な目的には有効ではありません。ピクセル単位のアルファ・チャネルでは、さまざまな目的を実現します。コンピュータ・グラフィックスでは、

色を赤、緑、青、アルファの4つの要素で定義します。アルファは色の透明度を表します。コンピュータの画像はピクセルの配列であり、色の4要素のうち1つ以上が各ピクセルに対して設定されています。各ピクセルにアルファ要素が設定されている場合は、画像にアルファ・チャネルが存在するということです。最近のデスクトップ・

オペレーティング・システムはすべて、各ウィンドウをオフスクリーン・バッファに描画してから、そのバッファを画面にコピーします。その際、各ピクセルのアルファ要素を使用して、そのピクセルの色と画面上の他のウィンドウの色とをどのように混合するか決定します。アルファ・チャネルを制御することによって、ぼやけた境界、半透明のオーバー

レイ、穴の空いたウィンドウ、外観の良いポップダウン・メニューなど、あらゆる種類の注目すべき効果を作成できます。

バージョン情報画面単純なものから始めます。境界がぼやけたバージョン情報画面です。こ

れは、アプリケーションのシステム・メニューから「バージョン情報」のメニュー項目を選択したときに表示される画面として使用できます。最初に、半透明グラデーションの上にテキストを描画するSwingコンポーネントを作成します。コードは、リスト1に示すように、単純なJava 2Dコードです。矩形をグラデーションで

塗り、その上にテキストを描画しています。グラデーションが4つの色から構成

されており、それぞれの色にアルファ要素(Colorコンストラクタの最後の引数)が指定されている点に注意してください。ただし、リスト1のコードの

Java SE 7: 非矩形ウィンドウと 半透明ウィンドウのさらなる応用注目すべき新しい方法でアプリケーションを強化

JOSH MARINACCI

BIO

写真: CHRIS PIETSCH / GETTY IMAGES

形状のサポート 非矩形ウィンドウはこれまでもさまざまなテクニックを利用して実現してきましたが、Java SE 7より正式な機能となりました。

Josh Marinacciは、ワイヤレス、Web、デスクトップの各プラットフォームにおけるJavaテクノロジー・ベースのユーザー・インタフェースに関する経験豊富なライターです。Xerox Parc、Sun Microsystemsでのキャリアを経て、現在はNokiaの研究者として職務を遂行しています。著作には、『Swing Hacks』(O’Reilly、2005年、Chris Adamsonとの共著)、『Building Mobile Applications with Java Using the Google Web Toolkit and PhoneGap』(O’Reilly、2012年)があります。

Page 2: N 半透明ウィンドウのさらなる応用 - oracle.com€¦ · を表します。コンピュータの画像はピ クセルの配列であり、色 の4要素のうち1つ以上

ORACLE.COM/JAVAMAGAZINE /////////////// MAY/JUNE 2012

JAVA TECH

31

COMMUNITY

JAVA IN ACTION

ABOUT US

blog

//java architect /

みでは、このコンポーネントは画面上に半透明で表示されません。部分的には半透明になりますが、その結果表示されるのはウィンドウの背景です。Swingでは、すべてのウィンドウに標準の背景色(通常はグレー)が設定されており、その上にすべてのコンポーネントが描画されます。したがって、ウィンドウを本当に半透明にするためには、コードを追加する必要があります(リスト2参照)。リスト2のコードでは、コンポーネントを

配置するためのウィンドウを作成しています。ウィンドウの装飾を無効にし、背景色を0,0,0,0に設定することで完全に透明にします。その結果、ウィンドウの背景が見えなくなり、デスクトップの背景や他のアプリケーションが透けて見えるようになります。このウィンドウを上記のカスタム・コンポーネントと組み合わせることで、アプリケーションは図1のように表示されます。図1の半透明ウィンドウは、

外観は優れている一方で、いくつかの問題があります。第1に、ウィンドウの装飾を無効にしたため、ユーザーがウィンドウを移動できません。ドラッグするタイトル・バーがないためです。第2に、ウィンドウがタスクバーにも表示されますが、これは好ましくありません。ウィンドウの外観を良くするだけでは不十分であり、ユーザーがウィンドウを使用

する方法を考慮する必要があります。次の例では、上記の問題を解決します。

キーストロークのオーバーレイ表示筆者は画面上でプログラムをデモンストレーションすることがあります。聴衆はマウス・カーソルの動きを確認することは可能ですが、特に筆者がメニューのショートカットを使用した場合などに、押されたキーを把握できていないことが多くあります。キーを押しても、画面には何も表示されないためです。そのような場合、押したキーを大きな見やすいフォントで表示するウィンドウが、画面下部に、アプリケーションの上にかぶせるようにして表示されていたら便利です。これは、半透明ウィンドウを利用すれば、簡単に実現します。まず、キーストロークを取り込む必要があ

ります。アプリケーション内のすべてのテキスト・コンポーネントにキーボード・リスナーを配置することも可能ですが、より簡単な方法があります。Swingでは、イベント・キューに直接リスナーを追加できるため、すべてのキーストローク・イベントを1か所で参照できます。リスト3に、AWTEventListenerを

追加するコードを示します。リスト3のコードでは、リス

ナーをメインのイベント・キューに追加しています。また、マスクを使用して、キーストローク以外のイベントを除外しています。キーストローク・イベントが、(keyReleasedイベントでもkeyTypedイベントでもなく)keyPressedイベントの場合、このコードによりイベントがオーバーレイ・ウィンドウを通過します。次に、オーバーレイ・ウィンドウに移ります。このオーバーレイは、半透明

のグレーの角丸矩形とし、中央

に大きな白のテキストを表示するようにします。そのために、Java 2Dコードを使用して各要素を描画するオーバーレイ・コンポーネントを作成します。キーストローク・イベント・リスナーによって、setText()メソッドを使用してテキストが設定されます。これにより再描画が開始され、押したキーを示すテキストが画面に描画されます(リスト4参照)。次に、オーバーレイをウィンドウ内に配置

します。前述の例と同様に、ウィンドウを作成し、装飾を無効にし、背景色を透明に設定して、コンポーネントを追加します(リスト5参照)。ただし、わずかな差異が1点あります。

リスト5では、J F r a m eではなくJWindowを使用しています。JWindowはJFrameの基底クラスであり、動作は非常によく似ていますが、重大な違いが1点あります。JFrameは装飾を含む完全なトップ・レベル・ウィンドウであり、オペレーティング・システムのネイティブのタスク・マネージャに表示されます。したがって、Microsoft Windowsであれば、タスクバーに表示されます。これに対して、JWindowは単なるウィンドウです。アプリケーションの重要な部分を表すものではないため、タスクバーには表示されず、装飾もありません。Mac OS X

図1

全てのリストのテキストをダウンロード

private static class AboutComponent extends JComponent { public void paintComponent(Graphics graphics) { Graphics2D g = (Graphics2D) graphics;

//create a translucent gradient Color[] colors = new Color[]{ new Color(0,0,0,0) ,new Color(0.3f,0.3f,0.3f,1f) ,new Color(0.3f,0.3f,0.3f,1f) ,new Color(0,0,0,0)}; float[] stops = new float[]{0,0.2f,0.8f,1f}; LinearGradientPaint paint = new LinearGradientPaint( new Point(0,0), new Point(500,0), stops,colors); //fill a rect then paint with text g.setPaint(paint); g.fillRect(0, 0, 500, 200); g.setPaint(Color.WHITE); g.drawString(“My Killer App”, 200, 100); } }

リスト1 リスト2 リスト3 リスト4 リスト5

さまざまな選択肢従来、使用できるUIコントロールは少なく、ボタン、スライダ、チェック・ボックス、スクロールバー、メニューと非常に限定されていました。現在では、非常に多くのカスタム・コントロールが存在します。

Page 3: N 半透明ウィンドウのさらなる応用 - oracle.com€¦ · を表します。コンピュータの画像はピ クセルの配列であり、色 の4要素のうち1つ以上

ORACLE.COM/JAVAMAGAZINE /////////////// MAY/JUNE 2012

JAVA TECH

32

COMMUNITY

JAVA IN ACTION

ABOUT US

blog

//java architect /

であれば、Exposeビューにも表示されません。JWindowは、ドロップダウン・メニューやコンボ・ボックスなどの一時的な要素に使用します。キーボードのオーバーレイ表示はアプリケーションの重要な機能ではないため、JWindowの使用が最適です。図2に、最終的なアプリケーションの外観

を示します。テキスト・フィールドに入力するかメニューのショートカット・キーを押すと、キーを押すたびにそのキーを示すテキストがオーバーレイ・ウィンドウに表示されます。

外観の良いポップダウン・メニュー従来のウィンドウ・インタフェースでは、使用できるU Iコントロールは少なく、 ボタン、スライダ、チェック・ボックス、スクロール・バー、メニューと非常に限定されていました。選択肢はほとんどなかったので

す。現在では、多様な振舞いをする非常に多くのカスタム・コントロールが存在します。Chromeなどのデスクトップ・アプリケー

ションで人気のある新しいコントロールに、ポップダウン・メニューがあります(このコントロールの呼称はプラットフォームによって異なります)。ポップダウン・メニューは、複数のアクションを含む小さなウィンドウです。メイン・インタフェースのボタンから「パッと下りてくる(pop down)」メニューであり、メイン・ウィンドウを表示したままユーザーに対して追加の機能を示すために使用します。ポップダウン・メニューは一時的なウィンドウです。ユーザーがボタンをクリックすると表示され、ユーザーがアクションを選択するか別のウィンドウに切り替えると閉じます。また、当然ながら外観の良さも求められます。したがって、半透明のJWindowに適しています。図3は、これから作成するポップダウン・メ

ニューの完成形です。四隅の丸いウィンドウの中に、複数のアクションが含まれます。ウィンドウの上部には、ポップダウン・メニューの発生元を指し示すとがった部分があります。この部分があることで、ユーザーはポップダウン・メニューが何に対するものなのかを見失わずに済みます。このポップダウン・メニューの描画自体は

非常に簡単です。ボタンは通常のJButtonオブジェクトであり、PopupTabPanelというカスタム・コンテナでラップされたJPanel内に配置されています。このカスタム・パネルのサイズは子コンポーネントに合わせて自動的に調整されますが、丸い四隅ととがった部分を持つ境界を描画するためには余分な領域が必要です。そのために、SwingのBorderFactoryを使用して透明な境界線(EmptyBorder)を追加し、paintComponentをオーバーライドしてグラデーション効果を描画します。リスト6にコードを示します。

図2

図3

private static class PopupTabComponent extends JComponent { public PopupTabComponent(JComponent component) { this.setLayout(new BorderLayout()); this.add(component, BorderLayout.CENTER); component.setBackground(new Color(0,0,0,0)); this.setBorder(BorderFactory.createEmptyBorder(35, 10, 10, 10)); } @Override protected void paintComponent(Graphics gfx) { Graphics2D g = (Graphics2D) gfx; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Color[] colors = new Color[]{ new Color(0.6f,.6f,.6f,0.9f) ,new Color(0.9f,0.9f,0.9f,1f) ,new Color(0.9f,0.9f,0.9f,1f) ,new Color(0.6f,0.6f,0.6f,0.9f)}; float[] stops = new float[]{0.2f,0.4f,0.9f,1f}; LinearGradientPaint paint = new LinearGradientPaint( new Point(0,0), new Point(0,getHeight()), stops,colors); //g.setPaint(new Color(255,255,255,120)); g.setPaint(paint); Path2D.Double path = new Path2D.Double(); path.moveTo(getWidth()/2, 0); path.lineTo(getWidth()/2+20, 30); path.lineTo(getWidth()/2-20, 30); path.closePath(); Area area = new Area(path); RoundRectangle2D.Double rect = new RoundRectangle2D.Double(0,30,getWidth()-1,getHeight()-30-1,30,30); area.add(new Area(rect)); g.fill(area); g.setPaint(new Color(50,50,50,120)); g.draw(area); }

リスト6

全てのリストのテキストをダウンロード

Page 4: N 半透明ウィンドウのさらなる応用 - oracle.com€¦ · を表します。コンピュータの画像はピ クセルの配列であり、色 の4要素のうち1つ以上

ORACLE.COM/JAVAMAGAZINE /////////////// MAY/JUNE 2012

JAVA TECH

33

COMMUNITY

JAVA IN ACTION

ABOUT US

blog

//java architect /

Java 2DのAreaクラスを使用していることに注意してください。Areaクラスにより、複数の形状を結合できます。ここでは、とがった部分のある形状を作成するため、三角形を角丸矩形と結合しています。形状をベジエ曲線コードで直接記述するよりも、はるかに簡単です。さらに、この形状を半透明グラデーションで塗り、目立たせるために細い境界線を追加しています。このポップダウン・メニューの外観は優れ

ており、JWindowを使用したためタスクバーに表示されることもありません。ただし、まだ問題が1点残っています。ユーザーがアクションを選択した場合、ポップダウン・メニューは閉じます。では、ユーザーが別のアプリケーションに切り替えた場合やメイン・ウィンドウの最小化を実行した場合と、ウィンドウを移動した場合について検討してみると、このポップダウン・メニューは表示されたまま、いわば切り離された状態で空中にぶら下がることになります。この問題を修正するために、ウィンドウ・イ

ベントに対するリスナーを追加する必要があります。ウィンドウが移動した場合には、ポップダウン・メニューも移動するようにします。

また、ウィンドウが非表示になるか、アクティブ・ウィンドウでなくなった場合は、ポップダウン・メニューを閉じるようにします。リスト7のコードで、メイン・フレームにリスナーを追加し、必要に応じてポップダウン・メニューの移動または非表示を処理します。前にも述べたように、このようなカスタ

ム・ウィンドウを作成する際には、ユーザーがウィンドウを使用する方法を常に考慮する必要があります。

拡大鏡最後の例として、以前は不可能であった、優れたウィンドウを作成します。画面上で動作する拡大鏡です。このウィンドウには、穴が空いています。穴の内側にあるものは拡大されます。外観を良くするため、ウィンドウ装飾の全くないカスタム・ウィンドウを使用します。そのため、ユーザーがウィンドウ装飾を使用しなくてもウィンドウを移動できる手段が必要です。最初に、外観の良いウィンドウを作成しま

す。Adobe Photoshopを使用してウィンドウを作成し、透過PNGファイルとして保存したものを図4に示します。この例でも、アルファ・チャネルを使用した

ウィンドウの内部にカスタム・コンポーネントを作成します。また、別のウィンドウの操作中にも拡大鏡を使用できるように、拡大鏡のウィンドウを常に最前面に表示するように設定します。リスト8にコードを示します。次に、拡大鏡が実際に動作するようにしま

す。小さい円の内部のイメージを取り込むため、java.awt.Robot APIを使用します。java.awt.Robot APIは、おもにテストと自動化の目的で作成されたものですが、便利な画面取り込みメソッドがあるため、画面の小さな領域を取り込むよう指定できます。画面の小さな領域を取り込んだ後、そのイメージを8倍に拡大して、もう1つの円の内

部に描画します。リスト9にコードの抜粋を示します。すべてのコードはarchitect.trans-windows-project.zipに含まれています。以上で拡大鏡はできましたが、ウィンドウ

装飾がないため、ユーザーがウィンドウを移動できません。もっとも自然な方法として、

ユーザーがウィンドウ上の任意の位置をクリックしてドラッグし、拡大鏡を移動できるようにします。そのために、マウス・リスナーをメイン・コンポーネントに追加します。ユーザーがドラッグするたびに、ウィンドウの位置を更新し、さらに画面の取り込みを更新しま

図4

全てのリストのテキストをダウンロード

frame.addComponentListener(new ComponentAdapter() { @Override public void componentMoved(ComponentEvent e) { tab.hideTab(); } }); frame.addWindowListener(new WindowAdapter() {

@Override public void windowClosed(WindowEvent e) { tab.hideTab(); }

@Override public void windowIconified(WindowEvent e) { tab.hideTab(); }

@Override public void windowDeactivated(WindowEvent e) { tab.hideTab(); } }); frame.add(button); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); frame.setSize(300, 100); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

リスト7 リスト8 リスト9 リスト10

Page 5: N 半透明ウィンドウのさらなる応用 - oracle.com€¦ · を表します。コンピュータの画像はピ クセルの配列であり、色 の4要素のうち1つ以上

ORACLE.COM/JAVAMAGAZINE /////////////// MAY/JUNE 2012

JAVA TECH

34

COMMUNITY

JAVA IN ACTION

ABOUT US

blog

//java architect /

す。以上で、拡大鏡は完成です。リスト10のコードでは、最初に座標を画

面座標に変換し、次にマウス・ドラッグのオフセットを加算している点に注意してください。コンポーネントの座標移動によってイベントは再計算されますが、これにより発生する可能性のある任意のエラーを未然に防ぐため、

必ず画面座標に変換して処理を行わなければなりません。この拡大鏡アプリ

ケーションを実行し、小さな円の内部をクリックすると、マウス・イベントがその円を通り抜け、下のウィンドウに到達することを確認できます。このウィンドウには、本当に穴が空いています(図5参照)。ここで、オペレー

ティング・システムは、ウィンドウの実際の境界をどのような方法で認識しているのかという疑問が生じます。この例では、特別なAPIも設定しておらず、マウス・イベントを下のウィンドウへ転送してもいません。実は、オペレーティング・システムはアルファ・チャネルを使用します。ユーザーがウィンドウ内のピクセルをクリックした場合、そのピクセルが完全に透明であれば、イベントは通り抜けます。一方、そのピクセルが完全に不透明または半透明である場合は、イベントがアプリケーションに渡されます。ここで、また1つの疑問が生じます。0で

はない小さなアルファ値を使用して、透明度99%のウィンドウを作成できるかどうかです。作成できる場合、クリックは取り込まれるのか、それとも通り抜けるのかを検討する必要があります。Java SE 7 API仕様では正確な動作が定義されていませんが、テストの結果、オペレーティング・システムでは閾値を使用していることがわかりました。アルファ値が0でなくとも、閾値を下回る場合、オペレーティング・システムはアルファ値を0として扱い、マウス・クリックを通過させます。これにより、悪意のあるプログラムがほぼ透明のウィンドウで画面全体を覆い、マウス・クリックを不正に取り込むなどしてユーザーを欺くことを防止しています。筆者のテストでは、アルファ値が10、または2.5%の場合はクリックが取り込まれました。</article>

図5

LEARN MORE• Java SE 7 API仕様

注目のコントロール機能ポップダウン・メニューは、デスクトップ・アプリケーションで注目されている新しいコントロール機能です。小さなウィンドウに追加の機能が表示されます。

YOUR LOCAL JAVA USER GROUP NEEDS YOU

Find your JUG here


Recommended