Index > マウスカーソル位置の単語を自動選択してハイライトするJEditorPane その2(改良版)(swing)
Tue, February 5, 2008

マウスカーソル位置の単語を自動選択してハイライトするJEditorPane その2(改良版)(swing)

前回の改良版。

前回は、ハイライトの描画をGlassPaneを使って行っていたが、 それを直接 JEditorPane に描画する方法に改良。

この方法では、 GlassPaneのことを気にしなくていい(GlassPaneはJFrameかJAppletにしかない) のが利点です。

GlassPaneは何か別の目的...たとえば、DragAndDropの描画に使っている場合 など、自由にコントロールできないときがあります。
そんな場合でも、JEditorPane 内でハイライト描画も完結して記述していれば、 問題ありません。

コード

TestFrame.java

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class TestFrame extends JFrame{

    private static final String SAMPLE_HTML=("<html><h1>Hello world!</h1><p>There was a farmer had a dog and BINGO was his name, oh.</p>");

    //private MyGlassPane glassPane;
    private DraggableBrowser editorPane;

//  private ChunkManager chunkManager;



    public TestFrame() {
        super();

        //chunkManager=new ChunkManager();


        editorPane=new DraggableBrowser();


        // layout
        doMyLayout();

        // init
        editorPane.setText(SAMPLE_HTML);
    }

    private void doMyLayout(){

        JPanel panel=new JPanel(new BorderLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
        panel.add(new JLabel("Test"),BorderLayout.NORTH);
        panel.add(editorPane,BorderLayout.CENTER);

        Container pane=getContentPane();
        pane.add(panel,BorderLayout.CENTER);

    }


    public static void main(String[] args) {

        TestFrame frame = new TestFrame();

        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

        frame.setSize(320, 360);
        frame.setVisible(true);
    }
}

Chunk.java

class Chunk {
    public int start;
    public int end;
    public String word;
    public Chunk(String word,int start,int end){
        this.word=word;
        this.start=start;
        this.end=end;
    }
    public boolean contains(int pos){
        if(start<=pos && pos<end){
            return true;
        }
        return false;
    }
}

ChunkManager.java

import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Locale;


class ChunkManager{

    private ArrayList chunkList=new ArrayList();
    //private ArrayList<Chunk> chunkList=new ArrayList<Chunk>();

    public void setText(String text){

        chunkList.clear();

        //BreakIterator
        BreakIterator boundary = BreakIterator.getWordInstance(Locale.ENGLISH);
        boundary.setText(text);
        int start = boundary.first();
        for (int end = boundary.next(); end != BreakIterator.DONE;start = end, end = boundary.next()) {
            String word = text.substring(start, end);
            chunkList.add( new Chunk(word,start,end) );
        }
    }
    public Chunk getChunk(int offset){
        Chunk myChunk=null;
        for(int i=0; i<chunkList.size(); i++){
            Chunk c=(Chunk)chunkList.get(i);
            if(c.contains(offset)){
                myChunk=c;
                break;
            }
        }
        return myChunk;

        /*
        for(Chunk c : chunkList){
            if(c.contains(offset)){
                myChunk=c;
            }
        }
        return myChunk;
        */
    }

}

DraggableBrowser.java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.JApplet;
import javax.swing.JEditorPane;
import javax.swing.text.Document;

//import mikan.dnd.GhostGlassPane;

public class DraggableBrowser extends JEditorPane{

    private ChunkManager chunkManager;

    public DraggableBrowser(){
        super();

        setEditable(false);
        setContentType("text/html");

        chunkManager=new ChunkManager();


        addMouseMotionListener(new MouseMotionAdapter(){
            //@Override
            public void mouseMoved(MouseEvent e) {

                Point pt=e.getPoint();
                int offset=viewToModel(pt);

                /*
                int endOffset=getDocument().getEndPosition().getOffset();
                if(offset<endOffset-1){
                    offset=offset+1;
                }
                */


                Chunk myChunk=chunkManager.getChunk(offset);
                if(myChunk!=null){

                    Rectangle rect1=null;
                    Rectangle rect2=null;

                    try{
                        rect1=modelToView(myChunk.start);
                        rect2=modelToView(myChunk.end);
                    }
                    catch(Exception ex){
                        hideGlassPane();
                        return ;
                    }

                    int w=rect2.x-rect1.x;
                    int h=rect1.height;

                    if(w>0 && h>0){
                        Point loc=new Point(rect1.x,rect1.y);
                        setSelectedWordRectangle(new Rectangle(loc.x,loc.y,w,h));

                        DraggableBrowser.this.repaint();
                    }
                    else{
                        hideGlassPane();
                        return ;
                    }
                }
                else{
                    hideGlassPane();
                    return ;
                }
            }
        });

    }
    private Rectangle selectedWordRect;
    private void setSelectedWordRectangle(Rectangle rect){
        this.selectedWordRect=rect;
    }
    private Rectangle getSelectedWordRectangle(){
        return selectedWordRect;
    }

    private void hideGlassPane(){
        selectedWordRect=null;
        repaint();
        /*
        Component c=applet.getGlassPane();
        if(c!=null)
            c.setVisible(false);
            */
    }
    //@Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Rectangle rect=getSelectedWordRectangle();
        if(rect==null){
            return ;
        }

        Graphics2D g2=(Graphics2D)g;
        Color keepC=g2.getColor();
        {
            g2.setColor(Color.RED);
            g2.draw(rect);
        }
        g2.setColor(keepC);
    }

    //@Override
    public void setText(String t) {
        super.setText(t);

        try{
            Document doc=getDocument();
            int len=doc.getLength();
            String text=doc.getText(0, len);

            chunkManager.setText(text);
        }
        catch(Exception ex){
            System.out.println(ex);
        }
    }

}

※ドラッグ機能を追加するつもりで書いていたので、このようなクラス名になっていますが、 実際にはドラッグ可能ではありません。 単にマウスオーバーしている単語がハイライト(囲みを描画)するだけです。

 Twitter
follow me on Twitter
 Categories