IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  Java technology  >

実用的な Groovy: SwingBuilder と Twitter API、第 1 回

Swing ベースの GUI を驚くほど容易に作成

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません

ダウンロード

原文はこちら

原文はこちら


レベル: 中級

Scott Davis, Founder, ThirstyHead.com

2009年 9月 29日

実用的な Groovy」シリーズの今回の記事で Scott Davis が取り上げる話題は、サーバー・サイド Java™ の開発者の大部分が心から恐れる Swing です。この記事を読むとわかるように、Groovy の SwingBuilder を利用することで、強力ながら複雑な GUI フレームワークである Swing の難しさをいくらか軽減することができます。

私は最近、IBM developerWorks の連載記事「多忙な Java 開発者のための Scala ガイド」の著者である Ted Neward と対談しました (「参考文献」を参照)。私達はその対談の中で、彼がその連載の中で作成中の Scitter (Scala + Twitter) という興味深い Twitter ライブラリーについて議論しました。Scitter は Scala の Web サービス機能と XML の構文解析機能を利用していますが、この API のフロントエンドを作成することまではしないかもしれない、と彼は話していました。当然のことですが、私はそれを聞き、Twitter GUI を Groovy で作成したらどうなるだろうと考えたのです。Gwitter (Groovy + Twitter) なら、この GUI にふさわしいように思いませんか?

この記事では Scala + Groovy という統合の話題は取り上げませんが、この 2 つの言語を組み合わせて使うことで大きな相乗効果がもたらされる可能性があります。この記事では Scala + Groovy の代わりに、Java エコシステムの片隅にある、Java 開発者が見過ごしがちな Swing に注目します。しかしその前に、Groovy の XmlSlurper によって Twitter の Atom フィードを簡単に扱えることを説明します。

Twitter Search API

Twitter Search API のオンライン・ドキュメント (「参考文献」を参照) を見ると、Twitter に対する検索は単純な HTTP GET リクエストで行えるようです。クエリーはクエリー・ストリングの q パラメーターによって渡され、その結果は Atom (XML による配信フォーマット) または JSON (JavaScript Object Notation) のいずれかのフォーマットで返されます。つまり thirstyhead に関するすべてのつぶやきを集めた Atom の結果セットを得るためには、HTTP GET リクエストを http://search.twitter.com/search.atom?q=thirstyhead のように実行します。

リスト 1 を見るとわかるように、この結果は <feed> 要素の中に一連の <entry> 要素がネストされた形で返されます。


リスト 1. Twitter を検索して Atom で返された結果

<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <entry>
    <title>thirstyhead: New series from Andrew Glover: Java Development 2.0 
           http://bit.ly/bJX5i</title>
    <content type="html">thirstyhead: New series from Andrew Glover: Java 
                         Development 2.0 http://bit.ly/bJX5i</content>
    <id>tag:twitter.com,2007:
        http://twitter.com/thirstyhead/statuses/3419507135</id>
    <published>2009-08-20T02:54:54+00:00</published>
    <updated>2009-08-20T02:54:54+00:00</updated>
    <link type="text/html" rel="alternate" 
          href="http://twitter.com/thirstyhead/statuses/3419507135"/>
    <link type="image/jpeg" rel="image" 
          href="http://s3.amazonaws.com/twitter_production/profile_images/
          73550313/flame_normal.jpg"/>
    <author>
      <name>ThirstyHead.com</name>
      <uri>http://www.thirstyhead.com</uri>
    </author>
  </entry>

  <entry>...</entry>
  <entry>...</entry>  
  <!-- snip -->
</feed>

実用的な Groovy: XML を作成し、構文解析し、容易に扱う」では、Groovy の XmlSlurper を使うと XML による結果を容易に処理できることを学びました。その記事で、XmlSlurper を使った結果がどのようなものになるかは紹介されているので、今度は searchCli.groovy という名前のファイルを作成します (リスト 2)。


リスト 2. Atom の結果を構文解析する Groovy スクリプト

if(args){
 def username = args[0]
 def addr = "http://search.twitter.com/search.atom?q=${username}"
 def feed = new XmlSlurper().parse(addr)
 feed.entry.each{
   println it.author.name
   println it.published
   println it.title
   println "-"*20
 }  
}else{
 println "USAGE: groovy searchCli <query>"
}

コマンドラインで groovy searchCli thirstyhead と入力すると、13 行から成る Atom の結果が得られます (リスト 3)


リスト 3. searchCli.groovy スクリプトを実行する

$ groovy searchCli thirstyhead

thirstyhead (ThirstyHead.com)
2009-08-20T02:54:54Z
New series from Andrew Glover: 
Java Development 2.0 http://bit.ly/bJX5i
--------------------
kung_foo (kung_foo)
2009-08-18T12:33:32Z
ThirstyHead interviews Venkat Subramaniam: 
http://blip.tv/file/2484840 "Groovy and Scala are good friends..." 
(via @mittie). very good.

//snip




上に戻る


最初の Gwitter クラスを作成する

Groovy スクリプトは正式ではないユーティリティーや概念検証用の実験などには便利ですが、Groovy スクリプトを作成することに比べて Groovy クラスの作成が非常に難しいということはありません。しかもその成果として、Groovy クラスをコンパイルすることができ、そのコンパイルしたものを Java コードから呼び出すことができるのです。

例えば Tweet.groovy を作成してみます (リスト 4)。


リスト 4. Tweet.groovy

class Tweet{
  String content
  String published
  String author
  
  String toString(){
    return "${author}: ${content}"
  }
}

ご存知のように、この POGO (Plain Old Groovy Object) によって、これよりもはるかに冗長な POJO (Plain Old Java Object) を簡単に置き換えることができます。

今度はリスト 2 の検索スクリプトを Search.groovy に変換します (リスト 5)。


リスト 5. Search.groovy

class Search{
  static final String addr = "http://search.twitter.com/search.atom?q="
  
  static Object[] byKeyword(String query){
    def results = []
    def feed = new XmlSlurper().parse(addr + query)
    feed.entry.each{entry->
      def tweet = new Tweet()
      tweet.author = entry.author.name
      tweet.published = entry.published
      tweet.content = entry.title
      results << tweet
    }
    return results as Object[]    
  }
}

通常であれば、私は結果を java.util.ArrayList にしておきますが、この記事の後の方で使用する javax.swing.JList では Object[] が必要になるので、そのときのために、ここでは結果を Object[] にしています。

Search.groovy には main() メソッドがないことに注目してください。この状態で、この Search クラスをどう扱えばよいのでしょう。もちろん、ユニット・テストを使うのです。そこで、SearchTest.groovy を作成します (リスト 6)。


リスト 6. SearchTest.groovy

class SearchTest extends GroovyTestCase{
  void testSearchByKeyword(){
    def results = Search.byKeyword("thirstyhead")
    results.each{
      assertTrue it.content.toLowerCase().contains("thirstyhead") ||
                 it.author.toLowerCase().contains("thirstyhead")
    }    
  }
}

コマンド・プロンプトで groovy SearchTest と入力して OK (1 test) が表示されると (リスト 7)、単純な検索スクリプトを、再利用可能な一連のクラスに変換できたことになります。


リスト 7. テストを実行して成功した結果

$ groovy SearchTest
.
Time: 4.64

OK (1 test)


これでベースとなる土台ができたので、次のステップでは外観を整えます。




上に戻る


SwingBuilder の導入

Swing は信じられないほど強力な GUI ツールキットです。残念なことに、その強力さが複雑さの影に隠れてしまう場合があります。Swing が初めての人にとって、その使い方を学ぶことは、本当は小型単発機のセスナかハング・グライダーの操縦方法を学びたいのに、ボーイング 747 の操縦方法を学んでいるかのように思えるかもしれません。

Groovy の SwingBuilder を使っても、適切な LayoutManager を選択するとか、スレッドの問題を適切に処理するといった、タスクの持つ本質的な複雑さを軽減することはできません。しかし SwingBuilder を使うことで、構文の複雑さが軽減されるのです。このすぐ後に説明するように、名前付き引数または可変長引数を使った Groovy のコンストラクターは、さまざまな JComponent にとって最適です。JComponent はインスタンス化する必要があり、インスタンス化したら即座に一連のセッターを使って構成する必要があるからです。(SwingBuilder の詳細については「参考文献」を参照してください。)

しかし構文が簡単になることと同じくらい貴重なことは、Groovy でクロージャーが使えることです。私には長年 Swing に関して抱えている問題があります。それは、実装の詳細を作成しているうちに、本来の階層構造がわからなくなってしまうことです。Java コードでは、コンポーネント同士の関連が失われ、どこに何が属するのか、まったくわからなくなります。JFrameJPanelJLabel を任意の順序で宣言できてしまうため、コード上ではすべてが同じレベルのように見えますが、実際には JFrameJPanel を含み、JPanelJLabel を含んでいます。リスト 8 はその一例です。


リスト 8. HelloJavaSwing.java

import javax.swing.*;

public class HelloJavaSwing {
  public static void main(String[] args) {
    JPanel panel = new JPanel();
    JLabel label = new JLabel("Hello Java Swing");

    JFrame frame = new JFrame("Hello Java Swing");
    panel.add(label);
    frame.add(panel);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(200,300);
    frame.setVisible(true);
  }
}

このコードをコンパイルして (javac HelloJavaSwing.java)、実行すると (java HelloJava)、図 1 のようなアプリケーションが出来上がるはずです。


図 1. HelloJavaSwing

リスト9 は上と同じアプリケーションを Groovy で作成したものです。これを見るとわかるように、SwingBuilder がクロージャーを適切に使用しているおかげで、所有関係がコードの中に明確に宣言されています。


リスト 9. HelloGroovySwing.groovy

import groovy.swing.SwingBuilder
import javax.swing.*

def swingBuilder = new SwingBuilder()
swingBuilder.frame(title:"Hello Groovy Swing", 
                   defaultCloseOperation:JFrame.EXIT_ON_CLOSE, 
                   size:[200,300],
                   show:true) {
  panel(){
    label("Hello Groovy Swing")    
  }
}

groovy HelloGroovySwing と入力すると、このアプリケーションが図 2 のように表示されます。


図 2. HelloGroovySwing

リスト 9 で、すべてのコンポーネント名から先頭の J がなくなっていることに注目してください。同様に、メソッド名から余分な getset がなくなっています。次に、名前付き引数を使った frame コンストラクターに注目してください。Groovy は背後で、引数を持たないデフォルトのコンストラクターを呼び出し、その後でセッター・メソッドを呼び出しています。これは上に示した Java の例と何も変わりません。しかし、これらがすべてコンストラクターの中にまとまっていることで、すべてが簡潔に整理され、またメソッドの前に付いていた set と後ろに付いていた括弧をなくしたことで、見た目が非常にすっきりしています。

Swing を知らない人から見ると、これでも複雑に見えるかもしれません。しかし、少しでも Swing を経験した人であれば、おそらくこれは Swing の持つ、簡潔で明確、そして効率的という本質が凝縮されているように見えるはずです。

この前のセクションの場合と同じように、このスクリプトから学んだことをクラスに変換してみましょう。Gwitter.groovy という名前のファイルを作成します (リスト 10)。これは Groovy + Twitter によるクライアント UI を作成するための控え目な出発点です。


リスト 10. Gwitter UI のスケルトン

import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.*

class Gwitter{   
  static void main(String[] args){
    def gwitter = new Gwitter()
    gwitter.show()
  }
    
  void show(){
    def swingBuilder = new SwingBuilder()  
    swingBuilder.frame(title:"Gwitter", 
                       defaultCloseOperation:JFrame.EXIT_ON_CLOSE, 
                       size:[400,500],
                       show:true) {
    }    
  }  
} 

groovy Gwitter と入力し、空のフレームが表示されることを確認します。すべてが想定どおりに動作したら、次のステップとして、このアプリケーションに簡単なメニューを追加します。




上に戻る


メニューバーを追加する

Swing でメニューを作成すると、本来の階層構造を持つコンポーネントの別の例を見ることができます。ここで JMenuBar を作成します。JMenuBarJMenu を 1 つ以上含み、JMenu は 1 つ以上の JMenuItem を含みます。

Exit というメニュー項目を持つ File メニューを作成するために、リスト 11 のコードを Gwitter.groovy に追加します。


リスト 11. Gwitter に File メニューを追加する

import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.*

class Gwitter{   
  static void main(String[] args){
    def gwitter = new Gwitter()
    gwitter.show()
  }
    
  void show(){
    def swingBuilder = new SwingBuilder()  
    
    def customMenuBar = {
      swingBuilder.menuBar{
        menu(text: "File", mnemonic: 'F') {
          menuItem(text: "Exit", mnemonic: 'X', actionPerformed: { dispose() })
        }
      }  
    }    
    
    swingBuilder.frame(title:"Gwitter", 
                       defaultCloseOperation:JFrame.EXIT_ON_CLOSE, 
                       size:[400,500],
                       show:true) {
      customMenuBar()                         
    }    
  }  
}

customMenuBar クロージャーがネストされた階層構造を持つことに注目してください。ここでは読みやすくするために customMenuBar を別に取り出していますが、これをフレームの中で、インラインで定義することも容易にできます。このクロージャーを定義できたら、そのクロージャーを frame クロージャーの中で呼び出します。再度 groovy Gwitter と入力し、File メニューが表示されることを確認します (図 4)。File > Exit の順に選択してアプリケーションを終了します。


図 4. Gwitter の File メニュー

リスト 11 を再度見てください。actionPerformed ハンドラーが、匿名クラスではなくクロージャーとして定義されていることに注目してください。こうすることで、Java の場合よりもコードがすっきりと読みやすくなったと思いませんか。

今度は、いくつかのフォーム要素を追加し、検索を実行できるようにしましょう。




上に戻る


検索パネルを追加する

経験豊富な Swing 開発者は、個々の JPanel から最終的なアプリケーションを簡単に作り上げます。JPanel というコンテナー・コンポーネントを使うと、関連する類似のコンポーネント同士を容易に一緒にまとめられるのです。

例えば Gwitter には、ユーザーが検索条件を入力するための JTextField と、リクエストを送信するための JButton が必要です。この 2 つのオブジェクトは searchPanel クロージャーの中に一緒にまとめた方が適切です (リスト 12)。


リスト 12. 検索パネルを追加する

import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.*

class Gwitter{   
  def searchField
  
  static void main(String[] args){
    def gwitter = new Gwitter()
    gwitter.show()
  }
    
  void show(){
    def swingBuilder = new SwingBuilder()  
    
    def customMenuBar = {
      swingBuilder.menuBar{
        menu(text: "File", mnemonic: 'F') {
          menuItem(text: "Exit", mnemonic: 'X', actionPerformed: {dispose() })
        }
      }  
    }    

    def searchPanel = {
      swingBuilder.panel(constraints: BorderLayout.NORTH){
        searchField = textField(columns:15)
        button(text:"Search", actionPerformed:{ /* TODO */ } )
      }
    }
    
    swingBuilder.frame(title:"Gwitter", 
                       defaultCloseOperation:JFrame.EXIT_ON_CLOSE, 
                       size:[400,500],
                       show:true) {
      customMenuBar()                         
      searchPanel()
    }    
  }  
}

パネルを扱い始めると、適切な LayoutManger をどう選択するかという問題が起きてきます。デフォルトで、JPanelFlowLayout を使います。これはつまり、textFieldbutton が横方向に隣り合って配置されるということです。

JFramecontentPane はそれとは少し異なり、デフォルトで BorderLayout を使います。これは、フレームに searchPanel を追加する際には、searchPanelNORTHSOUTHEASTWESTCENTER の領域のどこに表示するかを指定する必要があるということです。(方角がよくわからなくなってしまう人の場合には、PAGE_STARTPAGE_ENDLINE_STARTLINE_ENDCENTER を使うこともできます。) Swing で利用できる各種の LayoutManager については、「参考文献」を参照してください。

searchField 変数がクラス・レベルで宣言されていることに注意してください。これは、この変数に対してボタンなどの他のコンポーネントがアクセスできるようにするためです。それ以外のコンポーネントは匿名です。一連のクラスの内容を少し見ると、一部のコンポーネントが他のコンポーネントよりも重要であることがわかります。

おそらく読者の皆さんは、このボタンの actionPerformed リスナーが (まだ) 何もしていないことに、既にお気付きではないでしょうか。この時点では、このリスナーがする仕事は実際に何もありません。このリスナーを実装する前に、検索結果を保持する別のパネルをアプリケーションに追加する必要があります。




上に戻る


結果パネルを追加する

リスト 13 に示すように、searchPanel の場合と同じく、ネストされたクロージャーの中で resultsPanel を定義します。ただしこの場合には、パネルの中に JScrollPane という別のコンテナーをネストさせる必要があります。このコンポーネントによって、必要に応じて横スクロールバーと縦スクロールバーを表示したり非表示にしたりすることができます。Search.byKeyword() メソッドを呼び出した結果は、resultsList という名前の JList に表示されます。(JList.setListData() メソッドは Object[] を引数に取ります。まさにこの Object[] を返すように Search.byKeyword() メソッドを設定する、ということを忘れないでください。)
リスト 13. resultsPanel を追加する

import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.*

class Gwitter{   
  def searchField
  def resultsList
  
  static void main(String[] args){
    def gwitter = new Gwitter()
    gwitter.show()
  }
    
  void show(){
    def swingBuilder = new SwingBuilder()  
    
    def customMenuBar = {
      swingBuilder.menuBar{
        menu(text: "File", mnemonic: 'F') {
          menuItem(text: "Exit", mnemonic: 'X', actionPerformed: {dispose() })
        }
      }  
    }    

    def searchPanel = {
      swingBuilder.panel(constraints: BorderLayout.NORTH){
        searchField = textField(columns:15)
        button(text:"Search", actionPerformed:{ 
          resultsList.listData = Search.byKeyword(searchField.text) } )
      }
    }
    
    def resultsPanel = {
      swingBuilder.scrollPane(constraints: BorderLayout.CENTER){
        resultsList = list()
      }
    }    
    
    swingBuilder.frame(title:"Gwitter", 
                       defaultCloseOperation:JFrame.EXIT_ON_CLOSE, 
                       size:[400,500],
                       show:true) {
      customMenuBar()                         
      searchPanel()
      resultsPanel()
    }    
  }  
}

resultsList 変数が、searchField と同じように、クラス・レベルで定義されていることに注意してください。どちらの変数も、searchPanel の中にあるボタンの actionPerformed ハンドラーの中で使われます。

resultsPanel が追加されると、Gwitter が動作するようになります。コマンド・プロンプトで groovy Gwitter と入力し、想定どおりに動作することを確認します。thirstyhead を検索すると、図 5 のような結果が表示されるはずです。


図 5. 検索結果、その 1

ここで終了して成功を宣言することもできますが、勝利を宣言する前に、さらに 2 つの問題に対処したいと思います。第 1 に、検索ボタンの actionPerformed ハンドラーによって、知らないうちにスレッド化に関する悪夢が発生する可能性があります。第 2 に、このアプリケーションは実行結果が見づらくなっています。この 2 つの問題を次の 2 つのセクションで解決します。




上に戻る


EDT (イベント・ディスパッチ・スレッド)

Swing には、残酷で皮肉な側面があります。それは、ソフトウェア設計者のほうが適切に扱えるはずのマルチスレッド化に関する問題を、グラフィック・デザイナーが苦もなく扱うことができると想定している点、あるいはソフトウェア設計者がグラフィック・デザインの微妙なニュアンスやユーザビリティーの一般的な問題を理解できると想定している点です。

Swing アプリケーションでのスレッド化に関する問題のように複雑な問題は、いくつかの短い段落で説明しようとしても、とても説明しきれるものではありません。ここでは、Swing アプリケーションは基本的に、そのままの状態ではシングル・スレッドである、とだけ言っておきます。すべては EDT (イベント・ディスパッチ・スレッド) 上で行われます。ユーザーが Swing アプリケーションの動作の遅さや応答の悪さについて不満を言う場合、それは通常、経験の浅い開発者が、計算負荷が高く長々としたデータベース・クエリーや Web サービスの呼び出しを EDT 上で実行したためです。しかし EDT は画面の更新やメニューのクリックなどを処理するスレッドと同じスレッドなのです。ここではうかつにも、まさにこうした処理を検索ボタンの actionPerformed ハンドラーの中で実行してしまいました。(これを見ても、このよくありがちな誤りをいかに起こしやすいかがわかります。)

幸いなことに、javax.swing.SwingUtilities クラスには、適切な名前の付いた 2 つのコンビニエンス・メソッド (invokeAndWait()invokeLater()) が用意されており、この 2 つのメソッドによってスレッド化の問題をいくらか軽減することができます、この 2 つのメソッドを使うと、EDT 上で同期または非同期にアクションを実行することができます。(SwingUtilities クラスについての詳細は「参考文献」を参照)。SwingBuilder を使うと、この 2 つのメソッドのいずれかを簡単に呼び出すことができます。しかも、このいずれかのメソッドを呼び出す方法に続く第 3 の方法として、SwingBuilder を使うことで、負荷の重そうなアクションを実行する新しいスレッドを苦労せずに作成することができます。

EDT 上で同期呼び出し (SwingUtilities.invokeAndWait()) を実行するためには、その呼び出しを edt{} クロージャーの中にラップします。EDT 上で非同期呼び出し (SwingUtilities.invokeLater()) を実行するためには、その呼び出しを doLater{} クロージャーの中にラップします。しかしここでは第 3 の方法を実行します。つまり、新しいスレッドを作成して Search.byKeyword() メソッドの呼び出しを処理します。そのためには、doOutside{} の中にコードをラップします(リスト 14)。


リスト 14. doOutside クロージャーを使う

def searchPanel = {
  swingBuilder.panel(constraints: BorderLayout.NORTH){
    searchField = textField(columns:15)
    button(text:"Search", actionPerformed:{ 
      doOutside{ 
        resultsList.listData = Search.byKeyword(searchField.text)
      }
    } )
  }
}

Gwitter のように単純なアプリケーションの場合には、EDT 上で Web サービスの呼び出しを行うようにしたとしても、まったく苦労することはないでしょう。しかし、そのコードを Swing のエキスパートに見せた瞬間、彼らは、追い越し車線をゆっくりと走るドライバーや店の身障者用駐車スペースに不法駐車するドライバーに向けるような軽蔑の目で皆さんを見るでしょう。SwingBuilder を使えばスレッド化に関する適切な処理を容易に行えるため、SwingBuilder を使わない理由はありません。

これでスレッド化に関する問題を解決できたので、残る作業は、このアプリケーションの実行結果を見やすくすることです。




上に戻る


リストを縞模様にする

現在の状態では Gwitter の実行結果が非常に見にくいことを認めざるを得ません。ここでは簡単なことを 2 つ行い、少しばかりHTML を使うことで見やすくします。幸いなことに、JLabel は基本的な HTML を描画することができます。Tweet.groovy の toString() メソッドを調整します (リスト 15)。JListtoString() メソッドを呼び出して結果を表示します。


リスト 15. toString() メソッドの中で HTML を返す

class Tweet{
  String content
  String published
  String author
  
  String toString(){
    //return "${author}: ${content}"

    return """<html>
         <body>
           <p><b><i>${author}:</i></b></p>
           <p>${content}</p>
         </body>
       </html>"""
  }
}

次の細工は、もう少し巧妙です。GUI で一般的に使われる手法として、長いリストやテーブルを縞模様にする方法があります。偶数行と奇数行に異なる色を使うことで、リストが見やすくなります。私は検索エンジンで JList stripes を検索し、最初に見つかった助言に従うことにしました。その助言を書いた人は、カスタムの DefaultListCellRenderer を作成するように推奨しています。私はその助言を読みながら厳粛にうなずき、恥知らずにも、そのサンプル・コードをそのままコピーしました (完全な記事は「参考文献」を参照)。

Groovy の構文は Java の構文のスーパーセットであるため、その Java コードをそのまま Groovy ファイルにコピー・アンド・ペーストすることができました。もし私が Java コードと Groovy コードの両方をコンパイルする完全なビルド・システムを持っていたとしたら、その Java コードをそのまま Java ファイルのままに保持することができたはずです。しかしここではそのファイルに .groovy 拡張子を付けることで、コンパイルせずにすべての Gwitter コードを実行することができます。この場合も、Java 言語と Groovy とをシームレスに統合できることを利用しています。どのような Java ソリューションであれ、そのソリューションを何も変更せずに Groovy アプリケーションで使用することができるのです。

StripeRenderer.groovy という名前のファイルを作成し、リスト 16 のコードを追加します。


リスト 16. 縞模様の CellRenderer を作成する

import java.awt.*;
import javax.swing.*;

class StripeRenderer extends DefaultListCellRenderer {
    public Component getListCellRendererComponent(JList list, Object value,
            int index, boolean isSelected, boolean cellHasFocus) {
        JLabel label = (JLabel) super.getListCellRendererComponent(list, value,
                index, isSelected, cellHasFocus);
       
        if(index%2 == 0) {
            label.setBackground(new Color(230,230,255));
        }
        
        label.setVerticalAlignment(SwingConstants.TOP);
        return label;
    }
}

StripeRenderer クラスが用意できたら、最後に必要なことは、このクラスを JList で利用することです。resultsPanel をリスト 17 のように調整します。


リスト 17. カスタムの CellRendererJList に追加する

def resultsPanel = {
  swingBuilder.scrollPane(constraints: BorderLayout.CENTER){
    //resultsList = list()
    resultsList = 
       list(fixedCellWidth: 380, fixedCellHeight: 75, cellRenderer:new StripeRenderer())
  }
}

最後にもう 1 度、コマンド・プロンプトから groovy Gwitter と入力します。そして thirstyhead を検索すると、図 6 のような結果が得られるはずです。


図 6. 縞模様付きで表示された結果

もっと長い時間をかけて Gwitter の見栄えを良くすることもできたのですが、約 50 行の Swing コード (もちろんサポート・クラスは別です) で実現できたことを見ると、きっと皆さんは驚くはずです。




上に戻る


まとめ

この記事で学んだように、Groovy によって Swing の本質的な複雑さを軽減することはできませんが、構文の複雑さを大幅に軽減することができます。そのおかげで、より重要な他の事項に専念できるようになります。

もし、この記事を読んで Groovy と Swing に対する興味が湧いたようであれば、ぜひ Griffon プロジェクトを調べてみてください (「参考文献」を参照)。このプロジェクトは Grails プロジェクトの構成に関するすべての scaffold と規約を提供していますが、SwingBuilder と Groovy の上に構築されており、Spring MVC や Hibernate の上に構築されているわけではありません。このプロジェクトはまだ初期の段階にありますが (この記事の執筆時点で最新リリースは 0.2 です)、十分に堅牢であり、JavaOne 2009 では Scriptg Bowl for Groovy 賞を獲得しました。そして、このプロジェクトに同梱されているサンプル・プロジェクトの 1 つが Greet であり、この Greet は Groovy で実装された完全な Twitter クライアントです。

次回は、Gwitter に明らかに欠けている機能である、新しいつぶやきを投稿する機能を追加します。その中で、基本的な HTTP 認証の処理方法、HTTP POST の実行方法、そして XmlSlurper に似ている ConfigSlurper の利用方法を学びます。では次回まで、皆さんが Groovy の実用的な使い方をたくさん見つけられることを祈っています。





上に戻る


ダウンロード

内容ファイル名サイズダウンロード形式
Source code for article examplesj-groovy09299.zip24KBHTTP
ダウンロード形式について


参考文献

学ぶために
  • Groovy プロジェクトの Web サイトで Groovy について学んでください。

  • Interview with Ted Neward」では、Scott Davis が Scitter ライブラリーやその他の話題について、シリーズ記事、「多忙な Java 開発者のための Scala ガイド」の著者と議論しています。

  • Twitter Search API を調べ、アプリケーションで Twitter を検索するために必要な構文を見つけてください。

  • SwingBuilder について学んでください。

  • A Visual Guide to Layout Managers を読み、Swing のレイアウト・マネージャーについて学んでください。

  • Threads and Swing」(Hans Muller と Kathy Walrath の共著、java.sun.com、2000年9月) を読み、スレッドや Swing コンポーネント、SwingUtilities クラスについて学んでください。

  • Gwitter で実装した、縞模様で表示するソリューションを提供してくれたのは「Java Web Start Persistence and JList Striping」(Joshua Marinacci 著、java.sun.com、2006年11月) です。

  • Griffon のサイトを訪れ、Groovy でデスクトップ・アプリケーションを作成するための、Grails 風のアプリケーション・フレームワークについて学んでください。

  • AboutGroovy.com には Groovy に関する最新のニュースと記事へのリンクがあります。

  • Scott Davis による最新の書籍、『Groovy Recipes』(Pragmatic Programmers、2008年刊) を読み、Groovy と Grails について学んでください。

  • Scott Davis による関連のシリーズ「Grails をマスターする」では、Web 開発のための Groovy ベースの Grails プラットフォームに焦点を当てています。

  • Technology bookstore には、この記事や他の技術的な話題に関する本が豊富に取り揃えられています。

  • developerWorks の Java technology ゾーンには Java プログラミングのあらゆる側面を網羅した記事が豊富に用意されています。


製品や技術を入手するために
  • Groovy の最新の ZIP ファイルまたは tarball をダウンロードしてください。


議論するために


著者について

Scott Davis

Scott Davis は国際的に知られた著者、講演者、そしてソフトウェア開発者で、Groovy と Grails の教育を目的とした会社、ThirstyHead.com の創設者でもあります。彼の著書には、『Groovy Recipes: Greasing the Wheels of Java』、『GIS for Web Developers: Adding Where to Your Application』、『The Google Maps API』、『JBoss At Work』などがあります。現在、IBM developerWorks の「Grails をマスターする」と「実用的な Groovy」の 2 本の連載を執筆中です。




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



 


 


不充分・不完全である大変素晴らしい
 


この記事を共有する

del.icio.us del.icio.us newsing newsing FC2ブックマーク FC2ブックマーク
Choix! Choix! ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
MM/memo MM/memo CZブックマーク CZブックマーク livedoorクリップ livedoorクリップ
はてなブックマーク はてなブックマーク Buzzurl(バザール) Buzzurl(バザール)




上に戻る


    日本IBMについて プライバシー お問い合わせ