10

テキストエディターウィンドウの特定の要件を実装するために2日以上試みています...残念ながら、これまでのところ成功していません:(

目標は、他のテキスト エディターが行うように、現在の行を強調表示するテキスト エディター ウィンドウを取得することです。現在の行とは、現在カーソル/キャレットが配置されている行を意味します。

すでに2つの異なるアプローチを見つけましたが、残念ながらそれらを採用できないため、期待どおりに機能します。

最初のアプローチは、DefaultHighlighter( http://snippets.dzone.com/posts/show/6688 ) を上書きすることです。2 番目のアプローチでは、HighlighterPainter代わりに上書きされます ( http://www.jroller.com/santhosh/date/20050622 )。

現在、プロジェクトで最初のアプローチを採用しようとしていますが、前述のように、期待どおりに機能していません。

この投稿の最後に、問題を示す小さなサンプル アプリケーションを投稿します。

  • プログラムを起動すると、キャレットが最初の行の先頭に配置されます。ただし、行は強調表示されません。
  • 今、私はいくつかの文字を入力します。これらの文字は強調表示されますが、完全な行ではなく、それらの文字のみが強調表示されます
  • Enter キーを押して次の行に移動します。最初の行が強調表示されなくなりました。これは正しいことです。2 行目も強調表示されていません。これは正しくありません。繰り返しますが、いくつかの文字を入力すると、それらは強調表示されますが、完全な行ではありません。
  • カーソルキーまたはマウスのクリックによってキャレットを最初の行に戻すと、既存の文字だけでなく、最初の行全体が強調表示されます。これは、私が最初から望んでいる動作です。

ここで私が間違っていることを誰かが教えてくれることを願っています...または、その問題をまったく解決できない理由を説明してください。線の強調表示を実現するための代替ソリューションも高く評価されています!

事前にどうもありがとう 乾杯 Preachie

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;

import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;

public class HighlightProblem extends JFrame {
    private static final long serialVersionUID = 1L;
    private final JTextPane textPane;
    private final Highlighter.HighlightPainter cyanPainter;

    public HighlightProblem() {
        cyanPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.CYAN);

        textPane = new JTextPane();
        textPane.setPreferredSize(new Dimension(500, 300));
        textPane.setHighlighter(new LineHighlighter());
        textPane.addCaretListener(new CaretListener() {
            @Override
            public void caretUpdate(CaretEvent e) {
                setHighlight(e);
            }
        });
        getContentPane().add(textPane);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        new HighlightProblem();
    }

    public void setHighlight(CaretEvent e) {
        textPane.getHighlighter().removeAllHighlights();
        int currentLine = getLineFromOffset(textPane, e.getDot());
        int startPos = getLineStartOffsetForLine(textPane, currentLine);
        int endOffset = getLineEndOffsetForLine(textPane, currentLine);

        try {
            textPane.getHighlighter().addHighlight(startPos, endOffset, cyanPainter);           
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        textPane.repaint();
    }

    public int getLineFromOffset(JTextComponent component, int offset) {
        return component.getDocument().getDefaultRootElement().getElementIndex(offset);
    }

    public int getLineStartOffsetForLine(JTextComponent component, int line) {
        return component.getDocument().getDefaultRootElement().getElement(line).getStartOffset();
    }

    public int getLineEndOffsetForLine(JTextComponent component, int line) {
        return component.getDocument().getDefaultRootElement().getElement(line).getEndOffset();
    }

    public class LineHighlighter extends DefaultHighlighter {
        private JTextComponent component;

        @Override
        public final void install(final JTextComponent c) {
            super.install(c);
            this.component = c;
        }

        @Override
        public final void deinstall(final JTextComponent c) {
            super.deinstall(c);
            this.component = null;
        }

        @Override
        public final void paint(final Graphics g) {
            final Highlighter.Highlight[] highlights = getHighlights();
            final int len = highlights.length;
            for (int i = 0; i < len; i++) {
                Highlighter.Highlight info = highlights[i];
                if (info.getClass().getName().indexOf("LayeredHighlightInfo") > -1) {
                    // Avoid allocing unless we need it.
                    final Rectangle a = this.component.getBounds();
                    final Insets insets = this.component.getInsets();
                    a.x = insets.left;
                    a.y = insets.top;
                    // a.width -= insets.left + insets.right + 100;
                    a.height -= insets.top + insets.bottom;
                    final Highlighter.HighlightPainter p = info.getPainter();
                    p.paint(g, info.getStartOffset(), info.getEndOffset(), a, this.component);
                }
            }
        }

        @Override
        public void removeAllHighlights() {
            textPane.repaint(0, 0, textPane.getWidth(), textPane.getHeight());
            super.removeAllHighlights();
        }
    }
}
4

3 に答える 3

4

http://tips4java.wordpress.com/2008/10/29/line-painter/

これがあなたが探しているものだと思います。私はそのLinePainterクラスを取得し、コンストラクターをmainメソッドにコピーし、蛍光ペンの部分を取り出してnew LinePainter(textPane); 、チャームのような作品を追加しました

于 2011-03-23T13:53:39.913 に答える
2

以下は、現在の行からテキストを抽出するコードです。同じロジックを使用して、必要なインデックスを取得し、テキストを強調表示できます

    private String getCurrentEditLine() {
        int readBackChars = 100;
        int caretPosition = scriptEditor.getCaretPosition();

        if (caretPosition == 0) {
            return null;
        }

        StyledDocument doc = scriptEditor.getStyledDocument();

        int offset = caretPosition <= readBackChars ? 0 : caretPosition
                - readBackChars;

        String text = null;
        try {
            text = doc.getText(offset, caretPosition);
        } catch (BadLocationException e) {
        }

        if (text != null) {
            int idx = text.lastIndexOf("\n");
            if(idx != -1) {
                return text.substring(idx);
            }else {
                return text;
            }
        }

        return null;
    }
于 2012-03-15T03:10:17.553 に答える
1

蛍光ペンを使用してこれを達成するのは難しいかもしれないと思います-私はそれが彼らが設計されたものではないと思います。カスタムペイントコードでそれを行う必要があるかもしれません:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;

import javax.swing.JFrame;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;

public class HighlightLineTest {
    private static class HighlightLineTextPane extends JTextPane {
        public HighlightLineTextPane() {
            // Has to be marked as transparent so the background is not replaced by 
            // super.paintComponent(g);
            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            g.setColor(getBackground());
            g.fillRect(0, 0, getWidth(), getHeight());
            try {
                Rectangle rect = modelToView(getCaretPosition());
                if (rect != null) {
                    g.setColor(Color.CYAN);
                    g.fillRect(0, rect.y, getWidth(), rect.height);
                }
            } catch (BadLocationException e) {
            }
            super.paintComponent(g);
        }

        @Override
        public void repaint(long tm, int x, int y, int width, int height) {
            // This forces repaints to repaint the entire TextPane.
            super.repaint(tm, 0, 0, getWidth(), getHeight());
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("Highlight test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new HighlightLineTextPane());
        frame.setBounds(100, 100, 300, 400);
        frame.setVisible(true);
    }
}
于 2011-03-23T13:54:59.403 に答える