2011-05-10 140 views
18

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

我需要什么样的行为应该像一个提示,换句话说,只有鼠标一直徘徊在字一两秒钟后显示弹出式文本,它会自动消失一旦鼠标移开。当然,这里棘手的部分是,我希望在文本中的字符/字级别,而不是在组件级别......任何建议?

+1

@trashgod和@ camickr说了这一切:-)唯一轻微的讨厌是Swing本身:实现依赖位置的工具提示需要子类化。这是一个小的代价,相比于滚动你自己的WhateverHoverManager – kleopatra 2011-05-11 08:23:59

回答

21

您可以根据需要重写getToolTipText(Mouse Event event)

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

+0

为简单起见。 – MByD 2011-05-10 23:01:56

+0

@ trashgod +1,但我知道someComponet.dispatchEvent(SwingUtilities.convertMouseEvent(..)从Renderer,但如何处理TextArea + Caret – mKorbel 2011-05-10 23:31:49

+0

@mKorbel:好问题。我_think_位置信息在['JTextComponent']( http://download.oracle.com/javase/6/docs/api/javax/swing/text/JTextComponent.html)就足够了。作为参考,我已经更新了指向'JTextComponent#getToolTipText()'的链接,在'JComponent'中覆盖。 – trashgod 2011-05-11 00:00:06

0

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

假设有某种HoverListener或者你可以实现的东西,否则你将不得不实现一个鼠标监听器并在你自己的等待计时器中构建。但是,一旦你到达这里,你知道你想要弹出一个工具提示,你只是不知道他们正在写什么字母/单词。我非常确定,可以在屏幕上获得光标位置。然后使用这个位置,你可能能够计算出光标在TextArea内的位置,然后你可以抓住该字符。一旦你拥有了角色/位置,你也可以在不需要做太多工作的情况下抓住整个单词。 (注意,如果文本区域具有滚动条,则计算光标盘旋时文本区域的“视口”将视为仅显示屏幕上可见区域)

对不起非常罗嗦的答案,但这是我会尝试的一般逻辑,如果我有这个功能,我知道Swing不提供它。希望这是一个体面的起点。

+1

你必须添加一个MouseMotionListener到JTextArea。但getToolTipText要简单得多。 – MeBigFatGuy 2011-05-10 22:54:10

+0

覆盖工具TipText更简单,但使用MouseMotionListener我认为可能会在其事件参数中传递光标的位置,但toolTipText也可能如此。它只是一个看到什么和我猜测什么可用的问题。就像我说的,我对任何投票都不抱希望,但我至少想提供一些东西来刺激其他人的创意。 – gnomed 2011-05-11 00:00:51

+2

也许它会被投票,向下...创造力是好的,但浪费在重新发明轮子上。只有当你在一天结束时出现一个令人难以置信的增强型车轮时,你才会得到赞扬。成功的先决条件是对已有的简单车轮及其局限性(如果有的话)的深入了解......纯粹的假设无法帮助。布道结束:-) – kleopatra 2011-05-11 08:17:48

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

+1对于_tour de force_! – trashgod 2011-05-10 22:57:03

+0

你喜欢随机代码片段:-) – kleopatra 2011-05-11 07:34:37

10

当然,这里的棘手的部分是,我想它在文本

你用鼠标点中的字符/单词的水平,以确定您是在文本区:

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

既然你有一个偏移量,你可以得到该位置的字符或单词。 Utilities类具有诸如getWordStart()和getWordEnd()之类的方法。

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

+0

+1谢谢您验证此内容。我不确定何时对@mKorbel发表评论,并且当我更新[我的]时,我无意中忽略了你的答案(http://stackoverflow.com/questions/5957241/text-mouseover-popups-over-a-swing-jtextarea/5957412 #5957412)。 – trashgod 2011-05-11 04:31:29

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