java Swing JTextArea 上的文本鼠标悬停弹出窗口?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5957241/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 13:39:40  来源:igfitidea点击:

Text-mouseover popups over a Swing JTextArea?

javaswingjtextarea

提问by Manius

Is there anything out there that allows you to show a small text popup window (like a tooltip) over individual wordsor letters in a Swing JTextArea? (Or a JTextArea alternative with similar functionality.)

有没有什么东西可以让您在 Swing JTextArea 中的单个单词或字母上显示一个小的文本弹出窗口(如工具提示)?(或具有类似功能的 JTextArea 替代品。)

What I need should behave like a tooltip, in other words only display the popup text after the mouse has hovered over the word for a second or two, and it would vanish automatically once the mouse moves away. Of course the tricky part here is that I want it at the character/word level within the text, not at the component level... any suggestions?

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

回答by trashgod

You can override getToolTipText(Mouse Event event)as needed.

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

Addendum: JTextComponent, the parent of JTextAreaprovides location information via two methods: modelToView()and viewToModel(). The lattershould let you translate the mouse location into a document offset.

附录:JTextComponent,的父级JTextArea通过两种方法提供位置信息:modelToView()viewToModel()。在后者应该让你翻译的鼠标位置插入到文档中的偏移。

回答by camickr

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().

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

Then you use the getText(...) method to get the word or the character.

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

回答by mKorbel

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

回答by Wolfgang Fahl

Here is an actual implementation built on @trashgods and @camickr answer:

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

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.

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

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.

这个解决方案不是 100% 所要求的,但非常接近。通过一些调整,它应该得到最初想要的结果。

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

回答by gnomed

That sounds tricky. This is just off the top of my head and probably wont get voted. But you might be able to do this.

这听起来很棘手。这只是我的头顶,可能不会被投票。但你或许能够做到这一点。

Assuming there is some sort of HoverListener or something that you can implement, or else you will have to implement a mouse listener and build in your own wait timer. But once you get here, to a point where you know you want to popup a tooltip, you just dont know what letter/word they are on. I am pretty sure though that it is possible to get the cursor position on the screen. Then using this position you might be able to calculate where the cursor was inside the TextArea and then you can grab the character. Once you have the character/location you can also grab the whole word too without much more work. (NOTE that you want to get the "viewport" of the text area when calculating what the cursor was hovering over, if your text area has scroll bars the viewport will represent only the area visible on the screen)

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

Sorry for the very wordy answer, but that is the general logic I would try if I HAD to have this functionality and I know Swing does not offer it. Hopefully it makes a decent starting point.

抱歉我的回答非常冗长,但如果我必须拥有此功能并且我知道 Swing 不提供它,那么这是我会尝试的一般逻辑。希望它是一个不错的起点。