最初に書いた時からだいぶ整理したので、全面改訂しました。
URLをURLエンコード/URLデコードするツールのコードです。
import groovy.swing.SwingBuilder
import javax.swing.*
import java.awt.BorderLayout
import java.awt.datatransfer.*
import java.awt.dnd.*
abstract class ConvertDropTarget extends DropTarget {
/** その名の通りドロップされたときに呼ばれるメソッド。 */
public void drop(DropTargetDropEvent event) {
// fravorて言うのはドラッグ&ドロップするデータ形式みたいな物。
// mime-typeとかが有って、たいてい送り側はいくつかの形式をサポートしていて、
// その中から受け手が選びます。今回はプレーンテキストがあればそれ、という感じで。
def flavor = event.currentDataFlavors.find {
it.isMimeTypeEqual("text/plain")
}
// うまく処理できない(今回だと送り側がプレーンテキストを送ってくれない)時は
// event.rejectDrop()してから帰ります。
if (flavor == null) {
event.rejectDrop()
return;
}
// うまく処理できる時はevent.acceptDrop()したあと、
event.acceptDrop(DnDConstants.ACTION_COPY)
// 必要な処理をして、
component.text = convertText(event.transferable.getTransferData(flavor))
// event.dropComplete()してから帰ります。
event.dropComplete(true)
}
/** 実際の変換処理はサブクラスで実装。 */
abstract String convertText(droped);
}
class EncodeDropTarget extends ConvertDropTarget {
String convertText(droped) {
return java.net.URLEncoder.encode(
droped,
"UTF-8")
}
public String toString() {"URLエンコードする"}
}
class DecodeDropTarget extends ConvertDropTarget {
String convertText(droped) {
return java.net.URLDecoder.decode(
droped,
"UTF-8")
}
public String toString() {"URLデコードする"}
}
// builderを使ってframeを構築
def frame = new SwingBuilder().frame(
title: "URLEncoder/Decoder",
size: [320, 240],
defaultCloseOperation: JFrame.DISPOSE_ON_CLOSE) {
// comboBoxから操作するために、ドロップ先エリアの変数を定義
def area
// Encode/Decodeを選択するコンボbox。
def selector = comboBox(constraints: BorderLayout.NORTH,
items: [new DecodeDropTarget(), new EncodeDropTarget()].toArray(),
actionPerformed: {event -> area.dropTarget = event.source.selectedItem})
// ドロップ先を定義。
scrollPane(constraints: BorderLayout.CENTER) {
area = textArea(
text: "ここにドロップ...",
dropTarget: selector.selectedItem)
}
}
// SwingBuilderで作ったJFrameを表示する。
frame.visible = true
最近書いてるgroovyスクリプトの半分はこのひな形に沿ってます。ていうかコピペで大量増殖中...いかんなぁ^^;
好きに解読して使ってください...というのは投げ過ぎなので、ちょっと解説など。
importが必要なパッケージ
普通にSwingアプリケーション用に必要な諸々と、ドラッグ&ドロップ用の諸々をimportします。
まず、Swingアプリケーションをgroovyで書く時は、
の2つはたいてい要ります。
java.awt.BorderLayoutとjavax.swing.*は説明不要かと...
groovy.swing.SwingBuilderはSwingのGUIを記述言語風に書くためのクラスで、groovyにはこういったなんちゃらBuilderが色々あります。
ちなみに、SwingBuilderは最後に使います。
あと、Drag&Dropに必要なのは、
の2つ。
java.awt.datatransfer.*は別アプリケーションとデータをやり取りするためのパッケージ。コピペとかでも使うみたいです。
java.awt.dnd.*はドラッグ&ドロップ用のパッケージ。イベントやらリスナやらのもろもろです。
Javaでドラッグ&ドロップを行うには、
DropTargetをコンポーネントにセットしたり、dragEnabledプロパティをtrueにしたりします。
今回はDropTargetをセットして使用します。
普通はDropTargetListenerを実装し、DropTargetのコンストラクタにComponentと一緒に渡す物なんですが、
SwingBuilderと組み合わせて使う場合、DropTarget自体を拡張した方が楽なのでそっちでやってます。
こんな感じ。ドロップした動作を切り替えるために、抽象クラスでドラッグドロップ回りのややこしいところだけ実装してます。
abstract class ConvertDropTarget extends DropTarget {
/** その名の通りドロップされたときに呼ばれるメソッド。 */
public void drop(DropTargetDropEvent event) {
// fravorて言うのはドラッグ&ドロップするデータ形式みたいな物。
// mime-typeとかが有って、たいてい送り側はいくつかの形式をサポートしていて、
// その中から受け手が選びます。今回はプレーンテキストがあればそれ、という感じで。
def flavor = event.currentDataFlavors.find {
it.isMimeTypeEqual("text/plain")
}
// うまく処理できない(今回だと送り側がプレーンテキストを送ってくれない)時は
// event.rejectDrop()してから帰ります。
if (flavor == null) {
event.rejectDrop()
return;
}
// うまく処理できる時はevent.acceptDrop()したあと、
event.acceptDrop(DnDConstants.ACTION_COPY)
// 必要な処理をして、
component.text = convertText(event.transferable.getTransferData(flavor))
// event.dropComplete()してから帰ります。
event.dropComplete(true)
}
/** 実際の変換処理はサブクラスで実装。 */
abstract String convertText(droped);
}
本当はもうちょっと色々実装して、ドラッグが入って来た時点で受け入れ判定したりしないとユーザビリティ的に大問題ですが、まぁ自分一人のツールなので。
ドロップ受けるためにやる事はだいたいこれでわかったと思ってます。後は似たような事を各メソッドでやればいいはず...
Encode用
toStringはそのままJComboBoxに入れて選択できるようにするためです。
convertTextメソッドの中身はごらんの通り。
class EncodeDropTarget extends ConvertDropTarget {
String convertText(droped) {
return java.net.URLEncoder.encode(
droped,
"UTF-8")
}
public String toString() {"URLエンコードする"}
}
Decode用
Encodeと同様です。以上。
class DecodeDropTarget extends ConvertDropTarget {
String convertText(droped) {
return java.net.URLDecoder.decode(
droped,
"UTF-8")
}
public String toString() {"URLデコードする"}
}
クラスがそろえば、スクリプトでSwingBuilderでGUI構築->表示
これでドロップを受け付けてURLエンコード/デコードする準備はそろいました。
後はスクリプト部分でGUIを組んで行くだけです。
私は、だいたいこんな構成のスクリプトをよく書きます。
最初にいくつかクラスを定義して、その後にそのクラスを使ったスクリプトを書く。
mainメソッドを書いても良いんですけど、せっかくスクリプト言語なので...
ここでSwingBuilderを使います。GUIアプリケーションの場合はスクリプト部分はたいていこんな感じです。
SwingBuilderは、インスタンスを作って
builder.frame(プロパティ:値 ...) { 中に入れるコンポーネント(プロパティ:値 ...) { ...内包させるコンポーネントがあれば同様に } ... }
みたいに書いて行くと、JFrameを作ってくれるクラスです。
GroobyのBuilderはだいたいこんな使い方をします。
// builderを使ってframeを構築
def frame = new SwingBuilder().frame(
title: "URLEncoder/Decoder",
size: [320, 240],
defaultCloseOperation: JFrame.DISPOSE_ON_CLOSE) {
// comboBoxから操作するために、ドロップ先エリアの変数を定義
def area
// Encode/Decodeを選択するコンボbox。
def selector = comboBox(constraints: BorderLayout.NORTH,
items: [new DecodeDropTarget(), new EncodeDropTarget()].toArray(),
actionPerformed: {event -> area.dropTarget = event.source.selectedItem})
// ドロップ先を定義。
scrollPane(constraints: BorderLayout.CENTER) {
area = textArea(
text: "ここにドロップ...",
dropTarget: selector.selectedItem)
}
}
// SwingBuilderで作ったJFrameを表示する。
frame.visible = true
ざっとこんな感じでUI構築 ->表示を行います。
やってる事はコメントに書いてあるのでコメントを読んでください(手抜き)。