在Swing JTextArea上弹出文本鼠标悬停?

时间:2011-05-10 22:27:42

标签: java swing jtextarea

是否有任何内容允许您在单个单词或Swing JTextArea中的字母上显示一个小文本弹出窗口(如工具提示)? (或具有类似功能的JTextArea替代方案。)

我需要的东西应该像工具提示一样,换句话说,只有在鼠标悬停在单词上一两秒后才会显示弹出文本,一旦鼠标离开,它就会自动消失。当然,这里棘手的部分是我希望它在文本中的字符/单词级别,而不是在组件级别...任何建议?

5 个答案:

答案 0 :(得分:21)

您可以根据需要覆盖getToolTipText(Mouse Event event)

附录:JTextComponentJTextArea的父级通过两种方法提供位置信息:modelToView()viewToModel()latter应该允许您将鼠标位置转换为文档偏移量。

答案 1 :(得分:10)

也许

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);
    }
}

答案 2 :(得分:10)

  

当然,这里棘手的部分是我希望它在文本中的字符/单词级别

使用鼠标点确定文本区域的位置:

int offset = textArea.viewToModel(...);

现在你有一个偏移量,你可以获得该位置的字符或单词。 Utilities类有getWordStart()和getWordEnd()等方法。

然后使用getText(...)方法获取单词或字符。

答案 3 :(得分:0)

听起来很棘手。这只是我的头脑,可能不会被投票。但你可能会这样做。

假设有某种HoverListener或者你可以实现的东西,否则你将不得不实现一个鼠标监听器并在你自己的等待计时器中构建。但是一旦你到达这里,你知道你想要弹出工具提示,你就不知道他们在哪个字母/单词上。我很确定可以在屏幕上获得光标位置。然后使用此位置,您可以计算光标在TextArea中的位置,然后您可以获取该角色。一旦你拥有角色/位置,你也可以抓住整个单词,而无需更多的工作。 (注意,在计算光标悬停的位置时,您希望获取文本区域的“视口”,如果文本区域有滚动条,则视口将仅代表屏幕上可见的区域)

对于非常罗嗦的回答感到抱歉,但如果我有这个功能,那就是我会尝试的一般逻辑,我知道Swing不提供它。希望它是一个不错的起点。

答案 4 :(得分:0)

这是一个基于@trashgods和@camickr回答的实际实现:

addToolTip(line,toolTip) 

您可以为特定行添加工具提示,当您将鼠标悬停在该行上时,该工具提示将会显示。您可能需要设置debug = true以获取每个位置的工具提示显示。

如果您想为没有特定行的行显示常规工具提示,可能需要添加

addToolTip(-1,"general tool tip").

源代码:

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;
  }
}