Text-mouseover popups over a Swing JTextArea?
You can override getToolTipText(Mouse Event event)
as needed.
Addendum: JTextComponent
, the parent of JTextArea
provides location information via two methods: modelToView()
and viewToModel()
. The latter should let you translate the mouse location into a document offset.
Of course the tricky part here is that I want it at the character/word level within the text
You use the mouse point to determine where you are in the text area:
int offset = textArea.viewToModel(...);
Now that you have an offset you can get the character or word at that location. The Utilities class has methods like getWordStart() and getWordEnd().
Then you use the getText(...) method to get the word or the character.
maybe
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.*;
import javax.swing.event.*;
public class SimplePaintSurface implements Runnable, ActionListener {
private static final int WIDTH = 1250;
private static final int HEIGHT = 800;
private Random random = new Random();
private JFrame frame = new JFrame("SimplePaintSurface");
private JPanel tableaux;
@Override
public void run() {
tableaux = new JPanel(null);
for (int i = 1500; --i >= 0;) {
addRandom();
}
frame.add(tableaux, BorderLayout.CENTER);
JButton add = new JButton("Add");
add.addActionListener(this);
frame.add(add, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(WIDTH, HEIGHT);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
tableaux.requestFocusInWindow();
}
@Override
public void actionPerformed(final ActionEvent e) {
addRandom();
tableaux.repaint();
}
void addRandom() {
Letter letter = new Letter(Character.toString((char) ('a' + random.nextInt(26))));
letter.setBounds(random.nextInt(WIDTH), random.nextInt(HEIGHT), 16, 16);
tableaux.add(letter);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new SimplePaintSurface());
}
}
class Letter extends JLabel {
private Font font1;
private Font font2;
private final FontRenderContext fontRenderContext1;
private final FontRenderContext fontRenderContext2;
public Letter(final String letter) {
super(letter);
setFocusable(true);
setBackground(Color.RED);
font1 = getFont();
font2 = font1.deriveFont(48f);
fontRenderContext1 = getFontMetrics(font1).getFontRenderContext();
fontRenderContext2 = getFontMetrics(font2).getFontRenderContext();
MouseInputAdapter mouseHandler = new MouseInputAdapter() {
@Override
public void mouseEntered(final MouseEvent e) {
Letter.this.setOpaque(true);
setFont(font2);
Rectangle bounds = getBounds();
Rectangle2D stringBounds = font2.getStringBounds(getText(), fontRenderContext2);
bounds.width = (int) stringBounds.getWidth();
bounds.height = (int) stringBounds.getHeight();
setBounds(bounds);
}
@Override
public void mouseExited(final MouseEvent e) {
Letter.this.setOpaque(false);
setFont(font1);
Rectangle bounds = getBounds();
Rectangle2D stringBounds = font1.getStringBounds(getText(), fontRenderContext1);
bounds.width = (int) stringBounds.getWidth();
bounds.height = (int) stringBounds.getHeight();
setBounds(bounds);
}
};
addMouseListener(mouseHandler);
}
}
Here is an actual implementation built on @trashgods and @camickr answer:
with
addToolTip(line,toolTip)
you can add a tooltip for a specific line which will be displayed when you hover over the line. You might want to set debug=true to get a tooltip display for every location.
if you want to show a general tool tip for lines that do not have specific one you might want to add it with
addToolTip(-1,"general tool tip").
This solution is not 100% what was asked for but pretty close. With a few tweaks it should get the originally wanted result.
Source Code:
package com.bitplan.swingutil;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JTextArea;
import javax.swing.text.BadLocationException;
/**
* Answer for
* http://stackoverflow.com/questions/5957241/text-mouseover-popups-over-a-swing-jtextarea/35250911#35250911
*
* see http://stackoverflow.com/a/35250911/1497139
* a JTextArea that shows the current Position of the mouse as a tooltip
* @author wf
*
*/
public class JToolTipEventTextArea extends JTextArea {
// make sure Eclipse doesn't show a warning
private static final long serialVersionUID = 1L;
// switch to display debugging tooltip
boolean debug=false;
/**
* the map of tool tips per line
*/
public Map<Integer,String> lineToolTips=new HashMap<Integer,String>();
/**
* create me with the given rows and columns
* @param rows
* @param cols
*/
public JToolTipEventTextArea(int rows, int cols) {
super(rows,cols);
// initialize the tool tip event handling
this.setToolTipText("");
}
/**
* add a tool tip for the given line
* @param line - the line number
* @param tooltip -
*/
public void addToolTip(int line,String tooltip) {
lineToolTips.put(line,tooltip);
}
/**
* get the ToolTipText for the given mouse event
* @param event - the mouse event to handle
*/
public String getToolTipText(MouseEvent event) {
// convert the mouse position to a model position
int viewToModel =viewToModel(event.getPoint());
// use -1 if we do not find a line number later
int lineNo=-1;
// debug information
String line=" line ?";
// did we get a valid view to model position?
if(viewToModel != -1){
try {
// convert the modelPosition to a line number
lineNo = this.getLineOfOffset(viewToModel)+1;
// set the debug info
line=" line "+lineNo;
} catch (BadLocationException ble) {
// in case the line number is invalid ignore this
// in debug mode show the issue
line=ble.getMessage();
}
}
// try to lookup the tool tip - will be null if the line number is invalid
// if you want to show a general tool tip for invalid lines you might want to
// add it with addToolTip(-1,"general tool tip")
String toolTip=this.lineToolTips.get(lineNo);
// if in debug mode show some info
if (debug) {
// different display whether we found a tooltip or not
if (toolTip==null) {
toolTip="no tooltip for line "+lineNo;
} else {
toolTip="tooltip: "+toolTip+" for line "+lineNo;
}
// generally we add the position info for debugging
toolTip+=String.format(" at %3d / %3d ",event.getX(),event.getY());
}
// now return the tool tip as wanted
return toolTip;
}
}