Samples > テキストウィジェットにハイパーリンクを作る

 

テキストウィジェットにハイパーリンクを作る

StyledTextにハイパーリンクを生成するサンプルです。URL文字列に対して文字の装飾とカーソルの形状を変えます。またリンクをクリックするとIEが立ち上がる仕組みになっています。スクリーンショットはこのようになります。

まず文字の装飾についてです。これは、StyleText基礎編のところで説明しましたが、StyleRangeを使います。このサンプルでは、URLの文字列情報を持たせるために、HyperLinkRangeクラスを新たに作りました。

class HyperLinkRange extends StyleRange {
       String keyword;
}

文字装飾を行う際に、URLのパターンにマッチしたキーワードをHyperLinkRangeに保持し、Vectorに格納していきます。格納したリストは、マウスの形状変化やクリック時の処理に使います。

private void createHyperLink(StyledText text) {
       String content = text.getText();
       Pattern pattern = Pattern.compile("http://[a-zA-Z\\./0-9%]*");
       Matcher matcher = pattern.matcher(content);

       while (matcher.find()) {
           String line = matcher.group();
           int index = content.indexOf(line);
           HyperLinkRange range = new HyperLinkRange();
           range.start = index;
           range.length = line.length();
           range.fontStyle = SWT.BOLD;
           range.foreground = display.getSystemColor(SWT.COLOR_BLUE);
           range.keyword = line;
           ranges.add(range);
                        
           text.setStyleRange(range);
        }
}

次にリンク上のカーソルの形状やクリック時の動作について説明します。StyledTextには、ハイパーリンク機能はありませんので、MouseListenerやMouseMoveListenerなどを駆使して自分で実装する必要があります。やり方は比較的単純です。カーソルのx, y座標からハイパーリンクか否かを判断し、カーソルの形状を変えています。現在の位置がリンクか否かを判断するには、getHyperLinkRangeという独自メソッドを使っていますが、これはあとで説明します。

public void mouseMove(MouseEvent event) {
     int x = event.x;
     int y = event.y;
     HyperLinkRange range = getHyperLinkRange(x, y);
     if (range != null) {
        text.setCursor(handCursor);
     } else {
        text.setCursor(arrowCursor);
     }               
}

またクリック時の動作は、形状判断のときと同様に、マウスが押下されたときの座標を調べ、リンク上であればIEを起動する処理を行っています。

public void mouseDown(MouseEvent event) {
     int x = event.x;
     int y = event.y;
     HyperLinkRange range = getHyperLinkRange(x, y);
     if (range != null) {
          Runtime runtime = Runtime.getRuntime();
          String path = "\"C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE\"";
          String [] cmds = {path, range.keyword};
          try{
               runtime.exec(cmds);
          }catch(IOException ex){
               ex.printStackTrace();
          }           
    }
    return;
}

そして最後に、ポインタの位置座標からリンクか否かを判断するgetHyperLinkRangeメソッドの説明です。StyledTextウィジェットには、マウスポインタのx, y座標からオフセットを計算するメソッドがあります。オフセットとは、文頭から数えたカーソルの位置のことです。前もっと用意しておいたHyperLinkRangeのリストを調べて、該当するリンクがあればそれを返します。なければnullを返しています。

private HyperLinkRange getHyperLinkRange(int x, int y) {
    Point p = new Point(x, y);
    try {
        int offset = text.getOffsetAtLocation(p);
        for (int i = 0; i < ranges.size(); i++) {
            HyperLinkRange r = (HyperLinkRange) ranges.get(i);
            int offset1 = r.start;
            int offset2 = offset1 + r.length;
            if (offset >= offset1 && offset <= offset2) {
                 return r;
            }
        }
    } catch (IllegalArgumentException ex) {
        //カーソルの位置によっては、Offsetが計算できず、
        //Exceptionが発生する。したがってここでは何もしない。
    }
    return null;
}

ちなみにハイパーリンクの機能を内部に持たせたテキストクラスを新たに設計したかったのですが、ドキュメントによるとStyledTextを継承することは推奨されていないとのことです。したがって、StyledTextクラスの外部にハイパーリンクの機能を持たせることになりました。

ソースコード (HyperLinkTest.java)

説明したすべてのソースコードを以下に示します。

import java.io.IOException;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.swt.widgets.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.*;

public class HyperLinkTest implements MouseListener, MouseMoveListener{

        private Display display;
        private Shell shell;
        private Vector ranges = new Vector();
        private StyledText text;
        private Cursor handCursor;
        private Cursor arrowCursor;
        
        public static void main(String[] args) {
                new HyperLinkTest();
        }
        public HyperLinkTest() {
                display = new Display();
                shell = new Shell(display);
                shell.setText("HyperLinkTest");
                shell.setLayout(new FillLayout());

                text = new StyledText(shell, SWT.MULTI | SWT.BORDER);
                text.setText("これはハイパーリンクのテストです。\n");
                text.append("URL1: http://www.yahoo.co.jp\n");
                text.append("URL2: http://cjasmin.fc2web.com");
                
                //init cursor
                handCursor = new Cursor(display, SWT.CURSOR_HAND);
                arrowCursor =
                        new Cursor(display, SWT.CURSOR_ARROW);
                
                createHyperLink(text);
                text.addMouseListener(this);
                text.addMouseMoveListener(this);
                 
                shell.setSize(300,200);
                shell.open();
                while (!shell.isDisposed()) {
                        if (!display.readAndDispatch()) {
                                display.sleep();
                        }
                }
                handCursor.dispose();
                arrowCursor.dispose();
                display.dispose();
        }

        private void createHyperLink(StyledText text) {
                String content = text.getText();
                Pattern pattern = Pattern.compile("http://[a-zA-Z\\./0-9%]*");
                Matcher matcher = pattern.matcher(content);

                while (matcher.find()) {
                        String line = matcher.group();
                        int index = content.indexOf(line);
                        HyperLinkRange range = new HyperLinkRange();
                        range.start = index;
                        range.length = line.length();
                        range.fontStyle = SWT.BOLD;
                        range.foreground = display.getSystemColor(SWT.COLOR_BLUE);
                        range.keyword = line;
                        ranges.add(range);
                        
                        text.setStyleRange(range);
                }
                
        }
        
        //カーソル上にハイパーリンクがあればHyperLinkRangeを返し、
        //それ以外はnullを返す。
        private HyperLinkRange getHyperLinkRange(int x, int y) {
                Point p = new Point(x, y);
                try {
                        int offset = text.getOffsetAtLocation(p);
                        for (int i = 0; i < ranges.size(); i++) {
                                HyperLinkRange r = (HyperLinkRange) ranges.get(i);
                                int offset1 = r.start;
                                int offset2 = offset1 + r.length;
                                if (offset >= offset1 && offset <= offset2) {
                                        return r;
                                }
                        }
                } catch (IllegalArgumentException ex) {
                        //カーソルの位置によっては、Offsetが計算できず、
                        //Exceptionが発生する。したがってここでは何もしない。
                }
                return null;
        }
        public void mouseDoubleClick(MouseEvent e) {
        }

        public void mouseDown(MouseEvent event) {
                int x = event.x;
                int y = event.y;
                HyperLinkRange range = getHyperLinkRange(x, y);
                if (range != null) {
                   Runtime runtime = Runtime.getRuntime();
                   String path = "\"C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE\"";
                   String [] cmds = {path, range.keyword};
                   try{
                        runtime.exec(cmds);
                   }catch(IOException ex){
                        ex.printStackTrace();
                   }
                        
                }
                return;
        }

        public void mouseUp(MouseEvent e) {
        }

        public void mouseMove(MouseEvent event) {
                int x = event.x;
                int y = event.y;
                HyperLinkRange range = getHyperLinkRange(x, y);
                if (range != null) {
                        text.setCursor(handCursor);
                } else {
                        text.setCursor(arrowCursor);
                }               
        }
        
        class HyperLinkRange extends StyleRange {
                String keyword;
        }
}
 

Copyright(C) 2003,2004 Jasmin Project. All Right Reserved.
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送