如何获取 JTextArea 中的单词(或选择)在屏幕上的位置的点值?

How to get a point value for where a word (or selection) in a JTextArea is on the screen?

我的目标是在 JTextArea "actionable" 中创建 anyGivenWord。例如,当您将鼠标悬停在任何 GivenWord 上时,会出现一个工具提示,但当您将鼠标悬停在 JTextArea 中的任何其他单词上时则不会。据我所知,由于您不能直接执行此操作,我正在考虑在 JTextArea 中每个 anyGivenWord 出现的位置放置一个组件,并在 JTextArea 的大小发生变化时让它重新定位,以便单击看起来是 anyGivenWord 的内容实际上是在单击组件(导致触发某些侦听器)。为此,我需要知道该词出现在什么点 (x,y),以便我可以将组件放置在该点。

我想我可以搜索 JTextArea 和 select anyGivenWord 的实例,然后是 getSelectionStart() 和 getSelectionEnd(),但我认为这些方法 return 的索引是first/last 字母 selected,例如,它在由 getText() 编辑的字符串 return 中的位置。我需要的是 x/y 坐标。这可能吗?

如果没有...有什么建议可以更优雅地完成我想做的事情吗?

您可以将 JEditorPane 与 HTML 一起使用,并向任何给定的单词添加超链接。阅读 Swing 教程中关于 How to Use Editor Panes 的部分,了解入门的基础知识。

然后您可以添加一个 HyperlinkListener 来响应单击单词时的事件。阅读 JEditorPane API 以获取使用 HyperlinkListener.

的示例

For example, when you hover the mouse over anyGivenWord, a tooltip appears,

如果您不想使用超链接,则可以通过覆盖 getToolTipText(...) 方法来控制工具提示文本。此方法接收 MouseEvent,因此您可以获得鼠标位置。然后,您可以使用 JTextArea 的 viewToModel(...) 方法来获取鼠标在 Document 中的偏移量。然后查看Utilities。 class 这将帮助您获得单词的 start/end 偏移量,以便您可以使用 getText(...) 方法在当前鼠标位置提取单词。

您可以使用任何 JTextComponent 并通过一些方法(在下面提供)可以从您的文本中收集几个不同的项目,例如:

  • 当前鼠标指针位置下的角色;
  • 当前鼠标指针位置下的Word;
  • 位于当前鼠标指针位置下的选定文本 (如果选择);
  • 位于当前鼠标指针位置下的高亮文本 (如果您也喜欢在文本中突出显示);
  • 鼠标指针下的文字是否被选中?;
  • 鼠标指针下的文字是否突出显示?

正如@camickr 已经如此慷慨地指出的那样,这里的关键是使用 JTextComponent.viewToModel() 方法(我相信所有 Swing Text 组件都包含这个方法)以获得与当前鼠标指针在组件内的位置相关的文本索引位置。

这里有一些可以玩的方法:

/**
     * This method will return either boolean true or false if the text contained 
     * under the current mouse pointer location within a JTextComponent is Selected 
     * or not. If the text under the mouse is found to be Selected then boolean
     * true is returned. If the text under the mouse pointer is NOT found to be 
     * Selected then boolean false is returned.<br><br>
     * 
     * This method is not to be confused with the getHighlightedUnderMouse() method. 
     * Highlighted text and Selected text are two completely different things. 
     * Highlighted Text can be text which is Highlighted (generally with a specific 
     * color) and can be in many different locations throughout the entire document 
     * whereas Selected Text is generally done by dragging the mouse over a document 
     * location while holding the left mouse button making the text SELECTED.<br><br>
     * 
     * This method is generally run within a JTextComponent MouseMove Event but can be 
     * run from any JTextComponent Mouse event which will provide the current mouse 
     * coordinates within the supplied JTextComponent Object.
     * 
     * @param textComp (JTextComponent) The JTextComponent object to work on. This 
     * can be the component variable name for either a JTextField, JTextArea, 
     * JFormattedField, JPasswordField, JTextPane, and JEditorPane.<br>
     * 
     * @param textAreaMouseXLocation (Integer) The current X Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int x = evt.getX();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @param textAreaMouseYLocation (Integer) The current Y Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int y = evt.getY();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @return (Boolean) True if the text under the current mouse pointer location 
     * within the supplied JTextComponent is Selected and false if it is not.
     */
    public static boolean isSelectededUnderMouse(JTextComponent textComp, int textAreaMouseXLocation,
                                           int textAreaMouseYLocation) {
        boolean isSelected = false;
        if (textComp.getText().isEmpty()) { return false; }

        Point pt = new Point(textAreaMouseXLocation, textAreaMouseYLocation);
        int pos = textComp.viewToModel(pt);

        int start = textComp.getSelectionStart();
        int end = textComp.getSelectionEnd();
        if (pos >= start && pos <= end) {
            isSelected = true;
        }
        return isSelected;
    }

    /**
     * This method will return either boolean true or false if the text contained 
     * under the current mouse pointer location within a JTextComponent is Highlighted 
     * or not. If the text under the mouse is found to be Highlighted then boolean
     * true is returned. If the text under the mouse pointer is not found to be 
     * highlighted then boolean false is returned.<br><br>
     * 
     * This method is not to be confused with the getSelectedUnderMouse() method. 
     * Highlighted text and Selected text are two completely different things. 
     * Highlighted Text can be text which is Highlighted (generally with a specific 
     * color) and can be in many different locations throughout the entire document 
     * whereas Selected Text is generally done by dragging the mouse over a document 
     * location while holding the left mouse button making the text SELECTED.<br><br>
     * 
     * This method is generally run within a JTextComponent's MouseMove Event but can be 
     * run from any JTextComponent's Mouse event which will provide the current mouse 
     * coordinates within the supplied JTextArea Object.
     * 
     * @param textComp (JTextComponent) The JTextComponent object to work on. This 
     * can be the component variable name for either a JTextField, JTextArea, 
     * JFormattedField, JPasswordField, JTextPane, and JEditorPane.<br>
     * 
     * @param textAreaMouseXLocation (Integer) The current X Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int x = evt.getX();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @param textAreaMouseYLocation (Integer) The current Y Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int y = evt.getY();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @return (Boolean) True if the text under the current mouse pointer location 
     * within the supplied JTextComponent is Highlighted and false if it is not.
     */
    public static boolean isHighlightededUnderMouse(JTextComponent textComp, int textAreaMouseXLocation,
                                           int textAreaMouseYLocation) {
        boolean isHighlighted = false;
        if (textComp.getText().isEmpty()) { return false; }

        Point pt = new Point(textAreaMouseXLocation, textAreaMouseYLocation);
        int pos = textComp.viewToModel(pt);

        Highlighter.Highlight[] allHighlights = textComp.getHighlighter().getHighlights();
        String strg = "";
        for (int i = 0; i < allHighlights.length; i++) {
            int start =  (int)allHighlights[i].getStartOffset();
            int end =  (int)allHighlights[i].getEndOffset();
            if (pos >= start && pos <= end) {
                isHighlighted = true;
                break;
            }
        }        
        return isHighlighted;
    }

    /**
     * This method will return the "Selected" text contained under the mouse pointer
     * location within a JTextComonent.<br><br>
     * 
     * This method is not to be confused with the getHighlightedUnderMouse() method. 
     * Highlighted text and Selected text are two completely different things. 
     * Highlighted Text can be text which is Highlighted (generally with a specific 
     * color) and can be in many different locations throughout the entire document 
     * whereas Selected Text is generally done by dragging the mouse over a document 
     * location while holding the left mouse button making the text SELECTED.<br><br>
     * 
     * This method is generally run within a Text Component's MouseMove Event but can be 
     * run from any Text Component's Mouse event which will provide the current mouse 
     * coordinates within the supplied Text Component Object.
     * 
     * @param textComp (JTextComponent) The JTextComponent object to work on. This 
     * can be the component variable name for either a JTextField, JTextArea, 
     * JFormattedField, JPasswordField, JTextPane, and JEditorPane.<br>
     * 
     * @param textAreaMouseXLocation (Integer) The current X Location of the mouse 
     * pointer. This value can be acquired from the Text Component's MouseMove event like 
     * this <code>int x = evt.getX();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @param textAreaMouseYLocation (Integer) The current Y Location of the mouse 
     * pointer. This value can be acquired from the Text Component's MouseMove event like 
     * this <code>int y = evt.getY();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @return (String) The current selected string located under the current mouse 
     * location.
     */
    public static String getSelectededUnderMouse(JTextComponent textComp, int textAreaMouseXLocation,
                                           int textAreaMouseYLocation) {
        String selectedText = "";
        if (textComp.getText().isEmpty()) { return selectedText; }

        Point pt = new Point(textAreaMouseXLocation, textAreaMouseYLocation);
        int pos = textComp.viewToModel(pt);

        int start = textComp.getSelectionStart();
        int end = textComp.getSelectionEnd();
        int selectedLength = (end - start);
        if (pos >= start && pos <= end) {
            try {
                selectedText = textComp.getText(start, selectedLength);
            } 
            catch (BadLocationException ex) {
                // Ignore!!!
            }
        }
        return selectedText;
    }

    /**
     * This method will return the "Highlighted" text contained under the mouse pointer
     * location within a JTextComponent.<br><br>
     * 
     * This method is not to be confused with the getSelectedUnderMouse() method. 
     * Highlighted text and Selected text are two completely different things. 
     * Highlighted Text can be text which is Highlighted (generally with a specific 
     * color) and can be in many different locations throughout the entire document 
     * whereas Selected Text is generally done by dragging the mouse over a document 
     * location while holding the left mouse button making the text SELECTED.<br><br>
     * 
     * This method is generally run within a JTextComponent MouseMove Event but can be 
     * run from any JTextComponent Mouse event which will provide the current mouse 
     * coordinates within the supplied JTextComponent Object.
     * 
     * @param textComp (JTextComponent) The JTextComponent object to work on. This 
     * can be the component variable name for either a JTextField, JTextArea, 
     * JFormattedField, JPasswordField, JTextPane, and JEditorPane.<br>
     * 
     * @param textAreaMouseXLocation (Integer) The current X Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int x = evt.getX();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @param textAreaMouseYLocation (Integer) The current Y Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int y = evt.getY();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @return (String) The current highlighted string located under the current mouse 
     * location.
     */
    public static String getHighlightededUnderMouse(JTextComponent textComp, int textAreaMouseXLocation,
                                           int textAreaMouseYLocation) {
        if (textComp.getText().isEmpty()) { return ""; }

        Point pnt = new Point(textAreaMouseXLocation, textAreaMouseYLocation);
        int pos = textComp.viewToModel(pnt);

        String highlightedText = "";
        Highlighter.Highlight[] allHighlights = textComp.getHighlighter().getHighlights();
        if (allHighlights.length > 0) { 
            for (int i = 0; i < allHighlights.length; i++) {
                int start =  (int)allHighlights[i].getStartOffset();
                int end =  (int)allHighlights[i].getEndOffset();
                int hlStringLength = (end-start);
                if (pos >= start && pos <= end) {
                    try {
                        highlightedText = textComp.getText(start, hlStringLength);
                        break;
                    } 
                    catch (BadLocationException ex) { 
                        // Ignore!!!
                    }
                }

            }
        }
        return highlightedText;
    }

    /**
     * This method would normally be called within a JTextComponent's MouseMove Event.
     * 
     * @param textComp (JTextComponent) The JTextComponent object to work on. This 
     * can be the component variable name for either a JTextField, JTextArea, 
     * JFormattedField, JPasswordField, JTextPane, and JEditorPane.<br>
     * 
     * @param textAreaMouseXLocation (Integer) The current X Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int x = evt.getX();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @param textAreaMouseYLocation (Integer) The current Y Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int y = evt.getY();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @return (String) The current character located under the current mouse 
     * location.
     */
    public static String getCharUnderMouse(JTextComponent textComp, int textAreaMouseXLocation,
                                           int textAreaMouseYLocation) {
        String character = "";
        Point pt = new Point(textAreaMouseXLocation, textAreaMouseYLocation);
        int pos = textComp.viewToModel(pt);
        try {
            character = textComp.getDocument().getText(pos, 1);
        } 
        catch (BadLocationException ex) { 
            // Ignore!! 
        }
        return character;
    }

    /**
     * This method would normally be called within a JTextComponent's MouseMove Event.
     * 
     * @param textComp (JTextArea) The JTextComponent object to work on. This 
     * can be the component variable name for either a JTextField, JTextArea, 
     * JFormattedField, JPasswordField, JTextPane, and JEditorPane.<br>
     * 
     * @param textAreaMouseXLocation (Integer) The current X Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int x = evt.getX();</code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @param textAreaMouseYLocation (Integer) The current Y Location of the mouse 
     * pointer. This value can be acquired from the JTextComponent's MouseMove event like 
     * this <code>int y = evt.getY();<code> where evt is the <b>java.awt.event.MouseEvent</b> 
     * parameter variable.<br>
     * 
     * @return (String) The current Word located under the current mouse location.
     */
    public static String getWordUnderMouse(JTextComponent textComp, int textAreaMouseXLocation,
                                           int textAreaMouseYLocation) {
        Point pt = new Point(textAreaMouseXLocation, textAreaMouseYLocation);
        int pos = textComp.viewToModel(pt);
        String word = "";
        try {
            Document doc = textComp.getDocument();
            if( pos > 0 && (pos >= doc.getLength() || Character.isWhitespace( doc.getText( pos, 1 ).charAt( 0 ) )) ) {
                // if the next character is a white space then use 
                // the word on the left side..
                pos--;
            }
            // get the word from current position
            final int begOffs = Utilities.getWordStart(textComp, pos);
            final int endOffs = Utilities.getWordEnd(textComp, pos);
            word = textComp.getText( begOffs, endOffs - begOffs );
        } 
        catch( BadLocationException ex ) {
            // Ignore this exception!!!
        }
        return word;
    }