Originariamente inviato da jurij7
Qualcuno sa dirmi come si fa a sottolinerare il testo presente in un jtextpanel quando il mouse ci passa sopra ?
Sì, si può fare ma è una cosa non proprio banale perché bisogna tenere in considerazione svariate cose.
Innanzitutto per ricevere notifica dei movimenti sul text pane si deve usare un MouseMotionListener. La notifica tramite invocazione di mouseMoved() indica quindi che il mouse si è mosso sul componente.
Per sapere quale è la parola si può fare in un modo simile a quanto avevo spiegato qui: si usa viewToModel() per ottenere l'offset nel document dal Point e poi si usano i metodi getWordStart() e getWordEnd() di javax.swing.text.Utilities per ottenere l'inizio/fine della parola.
Una volta ottenuti questi dati si può aggiungere un certo insieme di attributi (AttributeSet) usando setCharacterAttributes di StyledDocument.
Ma non è così banale. Se mi sto muovendo restando sempre sulla stessa parola, non dovrei fare nulla ma se mi muovo su un'altra parola oppure esco fuori dal componente, dovrei togliere l'effetto di "hover" dalla parola su cui ero prima.
Questo comporta un po' di controlli. Per getWordStart()/getWordEnd() una "parola" può essere anche uno o più spazi, quindi se passo sopra a degli spazi, non dovrei attivare l'hover. Inoltre se mi muovo sempre nel componente ma nello spazio vuoto sotto le parole (se ce n'è), come offset mi trovo al fondo, quindi è come se fossi uscito dal componente.
In pratica si deve determinare la logica per capire quando si "entra" e quando si "esce" da una parola. Se si entra in una parola e c'era già un hover, va chiaramente tolto. Poi a questo punto si imposta l'effetto di hover sulla nuova parola aggiungendo gli attributi voluti. Ma non basta. Quando l'effetto di hover va tolto, non sarebbe corretto togliere semplicemente gli attributi di hover. Se l'effetto di hover consiste nella sottolineatura e la parola ha già di per sé delle lettere sottolineate??? Togliendo l'hover non riporterei la parola nello stato originale. Quindi vanno salvati gli attributi di ogni carattere.
Ecco un mio esempio:
codice:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class TestFrame extends JFrame
{
public TestFrame ()
{
super ("Test Frame");
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setSize (300, 300);
StyledDocument document = new DefaultStyledDocument ();
SimpleAttributeSet attributes;
try
{
attributes = new SimpleAttributeSet ();
StyleConstants.setForeground (attributes, Color.RED);
document.insertString (document.getLength (), "rosso ", attributes);
attributes = new SimpleAttributeSet ();
StyleConstants.setUnderline (attributes, true);
document.insertString (document.getLength (), "sotto", attributes);
document.insertString (document.getLength (), "lineato ", null);
attributes = new SimpleAttributeSet ();
StyleConstants.setBold (attributes, true);
document.insertString (document.getLength (), "grassetto", attributes);
}
catch (BadLocationException e) { }
JTextPane textPane = new JTextPane (document);
JScrollPane scrollPane = new JScrollPane (textPane);
getContentPane ().add (scrollPane);
//---- Creo l'attributo di sottolineatura per l'hover ----
SimpleAttributeSet hoverAttrSet = new SimpleAttributeSet ();
StyleConstants.setUnderline (hoverAttrSet, true);
//---- Creo il gestore dell'hover ----
HoverHandler hoverHandler = new HoverHandler (textPane, document, hoverAttrSet);
//---- Applico i listener al text pane ----
textPane.addMouseListener (hoverHandler);
textPane.addMouseMotionListener (hoverHandler);
}
public static void main (String[] args)
{
SwingUtilities.invokeLater (new Runnable ()
{
public void run ()
{
TestFrame f = new TestFrame ();
f.setVisible (true);
}
});
}
}
class HoverHandler implements MouseMotionListener, MouseListener
{
private JTextPane textPane;
private StyledDocument styledDoc;
private AttributeSet hoverAttrSet;
private boolean hover;
private int oldStart;
private int oldEnd;
private AttributeSet[] oldAttributes;
public HoverHandler (JTextPane textPane, StyledDocument styledDoc, AttributeSet hoverAttrSet)
{
this.textPane = textPane;
this.styledDoc = styledDoc;
this.hoverAttrSet = hoverAttrSet;
}
public void mouseDragged (MouseEvent e) { }
public void mouseMoved (MouseEvent e)
{
try
{
int pos = textPane.viewToModel (e.getPoint ());
int start = Utilities.getWordStart (textPane, pos);
int end = Utilities.getWordEnd (textPane, pos);
if (isExited (pos, start, end))
exit ();
if (isEntered (pos, start, end))
enter (start, end);
}
catch (Exception ex) { }
}
public void mouseClicked (MouseEvent e) { }
public void mouseEntered (MouseEvent e) { }
public void mousePressed (MouseEvent e) { }
public void mouseReleased (MouseEvent e) { }
public void mouseExited (MouseEvent e)
{
if (hover)
exit ();
}
private boolean isExited (int pos, int start, int end)
{
return hover && (pos == styledDoc.getLength () || start != oldStart);
}
private boolean isEntered (int pos, int start, int end)
throws BadLocationException
{
String str = styledDoc.getText (start, end-start);
if (str.trim ().equals (""))
return false;
if (hover)
return start != oldStart;
else
return pos != styledDoc.getLength ();
}
private void enter (int start, int end)
{
oldAttributes = new AttributeSet[end-start];
for (int pos = start; pos < end; pos++)
oldAttributes[pos-start] = styledDoc.getCharacterElement (pos).getAttributes ().copyAttributes ();
styledDoc.setCharacterAttributes (start, end-start, hoverAttrSet, false);
hover = true;
oldStart = start;
oldEnd = end;
}
private void exit ()
{
for (int pos = oldStart; pos < oldEnd; pos++)
styledDoc.setCharacterAttributes (pos, 1, oldAttributes[pos-oldStart], true);
hover = false;
oldAttributes = null;
}
}