2015-08-25 27 views
1

是否有人知道如何從JLabel開始的文本部分獲取到鼠標指針?例如,假設我們有一個文本爲'C:\ aaa \ bbb \ ccc'的JLabel。用戶將鼠標指針指向字符'bbb',所以我想獲得文本'C:\ aaa \ bbb'。現在,當我有這部分文字時,我可以改變它的顏色。我認爲將使用HTML。如何根據鼠標指針從JLabel中獲取文本的部分

+0

簡短的回答是,沒有很多(我的意思是很多)努力工作,也許一些黑客。您可以根據標籤,FontMetrics(和支持文本API)和鼠標位置的設置「猜測」。您可以從[使用文本API](https://docs.oracle.com/javase/tutorial/2d/text/index.html)開始,但問題是要知道標籤呈現文本的位置。 .. – MadProgrammer

+1

我可能更容易將一個文本組件打扮成標籤(不可編輯,無邊框,無背景)並使用它代替 – MadProgrammer

+0

謝謝@MadProgrammer,我沒有想到這一點。早上喝咖啡時想一想,這是一個好的開始。 – polis

回答

0

的Java Accessibility API方便地包括在該位置一個getIndexAtPoint方法作爲AccessibleText接口,一個位置轉換(諸如鼠標指針的)的一部分的字符的索引:

給定一個指向本地座標,返回該點下的字符的從零開始的索引。如果該點無效,則此方法返回-1。

下面是用這種方法來獲得你要的字符串的一部分的測試程序:

import java.awt.BorderLayout; 
import java.awt.Point; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionAdapter; 

import javax.accessibility.AccessibleText; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 

public class JLabelMouseDemo { 
    private static String labelText = "<html>C:\\aaa\\bbb\\ccc</html>"; 
    private static JLabel label; 
    private static JLabel substringDisplayLabel; 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     label = new JLabel(labelText); 
     label.addMouseMotionListener(new MouseMotionAdapter() { 
      public void mouseMoved(MouseEvent e) { 
       AccessibleText accessibleText = 
         label.getAccessibleContext().getAccessibleText(); 
       Point p = e.getPoint(); 
       int index = accessibleText.getIndexAtPoint(p); 
       if (index >= 0) { 
        // The index is with respect to the actually displayed 
        // characters rather than the entire HTML string, so we 
        // must add six to skip over "<html>", which is part of 
        // the labelText String but not actually displayed on 
        // the screen. Otherwise, the substrings could end up 
        // something like "tml>C:\aaa" 
        index += 6; 

        // Strangely, in my testing, index was a one-based index 
        // (for example, mousing over the 'C' resulted in an 
        // index of 1), but this makes getting the part of the 
        // string up to that character easier. 
        String partOfText = labelText.substring(0, index); 

        // Display for demonstration purposes; you could also 
        // figure out how to highlight it or use the string or 
        // just the index in some other way to suit your needs. 
        // For example, you might want to round the index to 
        // certain values so you will line up with groups of 
        // characters, only ever having things like 
        // "C:\aaa\bbb", and never "C:\aaa\b" 
        substringDisplayLabel.setText(partOfText); 
       } 
      } 
     }); 
     frame.add(label); 
     substringDisplayLabel = new JLabel(); 
     frame.add(substringDisplayLabel, BorderLayout.SOUTH); 
     frame.setSize(200, 200); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 

實際上獲得式AccessibleText的對象,對應於特定的JLabel可能並不總是工作:據我所知,只有當JLabel顯示HTML文本時纔可能。這也似乎是由JLabel source支持:

public AccessibleText getAccessibleText() { 
      View view = (View)JLabel.this.getClientProperty("html"); 
      if (view != null) { 
       return this; 
      } else { 
       return null; 
      } 
     } 

我並不完全瞭解發生了什麼事在該代碼或者爲什麼可訪問性並不適用於非HTML文本,但我的測試程序不工作當JLabel包含普通文本而不是HTML文本時:label.getAccessibleContext().getAccessibleText()將返回null,並且使用強制轉換(AccessibleText) label.getAccessibleContext()將產生僅從getIndexAtPoint返回-1的對象。


編輯:這是可能得到的文本部分,而不必擔心調整基於沒有被顯示爲可見文本的HTML標籤的位置索引。您只需在標籤上維護兩個字符串副本:其中一個僅包含要根據索引切片的字符(以下示例中爲rawText),另一個包含將實際使用的格式化HTML版本作爲標籤的文字(下面的formatLabelText的結果)。由於getIndexAtPoint僅返回與顯示的字符相關的索引,因此在第二個示例中獲取所需的子字符串比我的原始子字符串更容易。對index進行的唯一調整是四捨五入,以便突出顯示的文本與反斜線分隔的組排成一行。

import java.awt.Point; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionAdapter; 

import javax.accessibility.AccessibleText; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 

public class JLabelMouseHighlightDemo { 
    private static String rawText = "C:\\aaa\\bbb\\ccc"; 
    private static JLabel label; 

    private static String formatLabelText(int index) { 
     if (index < 0) { 
      index = 0; 
     } 
     if (index > rawText.length()) { 
      index = rawText.length(); 
     } 
     StringBuilder sb = new StringBuilder(); 
     sb.append("<html>"); 
     sb.append("<font color='red'>"); 
     sb.append(rawText.substring(0, index)); 
     sb.append("</font>"); 
     sb.append(rawText.substring(index)); 
     sb.append("</html>"); 
     return sb.toString(); 
    } 

    private static int roundIndex(int index) { 
     // This method rounds up index to always align with a group of 
     // characters delimited by a backslash, so the red text will be 
     // "C:\aaa\bbb" instead of just "C:\aaa\b". 
     while (index < rawText.length() && rawText.charAt(index) != '\\') { 
      index++; 
     } 
     return index; 
    } 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     label = new JLabel(formatLabelText(0)); 
     label.addMouseMotionListener(new MouseMotionAdapter() { 
      public void mouseMoved(MouseEvent e) { 
       AccessibleText accessibleText = 
         label.getAccessibleContext().getAccessibleText(); 
       Point p = e.getPoint(); 
       int index = accessibleText.getIndexAtPoint(p); 
       index = roundIndex(index); 
       label.setText(formatLabelText(index)); 
      } 
     }); 
     frame.add(label); 
     frame.setSize(200, 200); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 
+0

它看起來適合我的需求非常好。謝謝你,@Alden – polis

+1

我接受了這個答案,因爲我從中學到了一些新東西。我真的無法弄清楚如何從JLabel中獲取文本的一部分,但是,我想爲該部分文本更改顏色。在JLabel的情況下,我必須插入HTML代碼才能更改文本的顏色,例如:' C:\ aaa \ bbb',但從那時開始跟蹤鼠標位置由於在文本中間增加了不可顯示的html標籤,文本變成了一場噩夢。我想我會遵循@ MadProgrammer的建議並使用文本組件。 – polis

+0

@polis如果您保留僅包含屏幕上顯示字符的標籤文本的副本,則確定子字符串不必是如此的噩夢。看到我上面的編輯。 – Alden

0

這是一種使@Alden的代碼無需在任何地方存儲原始文本就能工作的方法。事實證明,從JLabel中獲取視圖可以讓您訪問文本的一個版本,並剝離掉所有的html。

import java.awt.BorderLayout; 
import java.awt.Point; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionAdapter; 

import javax.accessibility.AccessibleText; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.text.BadLocationException; 
import javax.swing.text.View; 

public class JLabelMouseDemo { 
    private static String labelText = "<html>C:\\aaa\\bbb\\ccc</html>"; 
    private static JLabel label; 
    private static JLabel substringDisplayLabel; 

    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     label = new JLabel(labelText); 
     label.addMouseMotionListener(new MouseMotionAdapter() { 
      public void mouseMoved(MouseEvent e) { 
       AccessibleText accessibleText = 
         label.getAccessibleContext().getAccessibleText(); 
       Point p = e.getPoint(); 
       int index = accessibleText.getIndexAtPoint(p); 
       if (index >= 0) { 
        View view = (View) label.getClientProperty("html"); 
        String strippedText = null; 
        try { 
         strippedText = view.getDocument().getText(0, accessibleText.getCharCount()); 
        } catch (BadLocationException e1) { 
         e1.printStackTrace(); 
         return; 
        } 
        // getIndexAtPoint seems to work from the end of a 
        // character, not the start, so you may want to add 
        // one to get the correct character 
        index++; 
        if (index > strippedText.length()) index = strippedText.length(); 
        String partOfText = strippedText.substring(0, index); 

        // Display for demonstration purposes; you could also 
        // figure out how to highlight it or use the string or 
        // just the index in some other way to suit your needs. 
        substringDisplayLabel.setText(partOfText); 
       } 
      } 
     }); 
     frame.add(label); 
     substringDisplayLabel = new JLabel(); 
     frame.add(substringDisplayLabel, BorderLayout.SOUTH); 
     frame.setSize(200, 200); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 
相關問題