【问题标题】:Showing the tooltip of the parent component on JTextPane在 JTextPane 上显示父组件的工具提示
【发布时间】:2014-01-15 19:47:43
【问题描述】:

我有一个应用程序,它基本上使用 JTextPane 作为多行标签,可以将文本居中并自动换行(居中是我不使用较轻组件的原因,但 JTextArea 会有同样的问题) .它用作较大实体的一部分,该实体应使用一个工具提示。但是,为包含组件设置工具提示不适用于JTextPane。其他组件按预期显示工具提示。

SSCCE:

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;

public class ToolTipTest {
    ToolTipTest() {
        JFrame frame = new JFrame("Tool tip test");
        frame.setLocationByPlatform(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel bg = new JPanel(new BorderLayout());
        frame.add(bg);
        bg.add(new JLabel("Tooltip shows here"), BorderLayout.NORTH);
        JTextPane text = new JTextPane();
        try {
            text.getStyledDocument().insertString(0, "Lorem ipsum dolor sit"
                    + " amet, consectetur adipiscielit, sed eiusmod tempor"
                    + " incidunt ut labore et dolore magna aliqua.", null);
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
        text.setEditable(false);
        text.setFocusable(false);
        bg.add(text);
        bg.setToolTipText("A tooltip, that should show on both the label and the text");
        // Works, but is ugly and results in visible change in tooltip when
        // moving cursor between components
        // text.setToolTipText("A tooltip, that should show on both the label and the text");
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ToolTipTest();
            }
        });
    }
}

在上面的示例中,工具提示显示在JLabel 上,但不在JTextPane 上。我目前正在为文本窗格设置相同的工具提示文本作为解决方法,但是当用户将鼠标光标移动到组件顶部时,这会导致工具提示之间的可见切换。

有没有办法在JTextPane上显示父组件的工具提示?

编辑: 按照 cmets 中的建议,我尝试覆盖 getToolTipText() 方法并使用工具提示管理器注册组件。这有效,因为文本窗格然后从父级获取工具提示文本。但是,视觉效果与我的解决方法完全相同。

【问题讨论】:

  • 我想知道这是否需要继承,如果覆盖 getToolTipText()getToolTipText(MouseEvent event) 并返回父级的工作。我没有测试过这个。
  • @HovercraftFullOfEels 不工作,很遗憾。
  • 您可能需要向工具提示管理器注册组件才能触发 getToolTipText 方法
  • @MadProgrammer 这确实有所作为,谢谢。不幸的是,它对我想要解决的问题没有帮助。也就是说,它再次导致两个不同的工具提示。
  • 问题是,ToolTipManager 在每个组件上注册了一个MouseListener,所以它跟踪mouseEntermouseExit 以及mouseMove 事件。不确定您是否可以防止这种情况发生

标签: java swing tooltip jtextpane


【解决方案1】:

本质上,您需要代理工具提示功能,以便在请求时将值从父级传回。

你还需要手动注册组件到ToolTipManager,否则不会被提示工具提示...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.BadLocationException;

public class ParentToolTip {

    public static void main(String[] args) {
        new ParentToolTip();
    }

    public ParentToolTip() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JTextPane text = new JTextPane() {

                    @Override
                    public String getToolTipText() {
                        return ((JComponent) getParent()).getToolTipText();
                    }

                    @Override
                    public String getToolTipText(MouseEvent event) {
                        return ((JComponent) getParent()).getToolTipText(event);
                    }

                };
                try {
                    text.getStyledDocument().insertString(0, "Lorem ipsum dolor sit"
                            + " amet, consectetur adipiscielit, sed eiusmod tempor"
                            + " incidunt ut labore et dolore magna aliqua.", null);
                } catch (BadLocationException e) {
                    e.printStackTrace();
                }

                ToolTipManager.sharedInstance().registerComponent(text);

                JFrame frame = new JFrame("Testing");
                JPanel panel = new JPanel(new BorderLayout());
                panel.setToolTipText("This is not the tooltip your are looking for");
                frame.setContentPane(panel);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(text);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}

【讨论】:

  • 我最终还是这样做了,但是正确地记录这一点(而不是将其留给 cmets 解决问题)方法值得一票。我的条件有点特殊,这可能更适合其他人。
【解决方案2】:

在某种程度上基于 mKorbel 的想法,我在组件组顶部制作了一个玻璃窗格样式的叠加层。在我的例子中,所有组件都只提供信息,不需要用户交互,所以玻璃窗格不会打扰向它们分派事件。

我使用了OverlayLayout,因为它对我的目的来说最简单且足够了。应用于问题中的代码,ToolTipTest 构造函数将更改为:

ToolTipTest() {
    JFrame frame = new JFrame("Tool tip test");
    frame.setLocationByPlatform(true);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // Holds the component group and the glass pane
    JComponent content = new JPanel();
    content.setLayout(new OverlayLayout(content));
    frame.add(content);
    JComponent glassPane = new JComponent(){};
    content.add(glassPane);
    final JPanel bg = new JPanel(new BorderLayout());
    content.add(bg);
    bg.add(new JLabel("Tooltip shows here"), BorderLayout.NORTH);
    JTextPane text = new JTextPane();
    try {
        text.getStyledDocument().insertString(0, "The same tooltip also shows here", null);
    } catch (BadLocationException e) {
        e.printStackTrace();
    }
    text.setEditable(false);
    text.setFocusable(false);
    bg.add(text);
    glassPane.setToolTipText("A tooltip, that shows on both the label and the text");
    JLabel other = new JLabel("This component has another tooltip");
    other.setToolTipText("Another tooltip");
    frame.add(other, BorderLayout.SOUTH);

    frame.pack();
    frame.setVisible(true);
}

编辑:在组件组之外包含一个带有共享工具提示的标签,以区别于更典型的玻璃窗格使用。

【讨论】:

  • @mKorbel 这是正常的方式,并且适用于示例:-) 在我的真实代码中,组件组不会覆盖整个窗口,所以我不能使用根窗格(没有手动处理坐标的额外技巧)。我在JLayeredPaneOverlayLayout 之间进行了思考,后者对于我的特定用例来说更简单,所以我接受了它。对于玻璃板的典型用途,getRootPane().setGlassPane() 绝对是最佳选择。我可能应该对示例进行足够的修改以包含一个不应共享工具提示的组件。
  • 您可以使用 JLayer(jdk7 或 jdk6 中的 JXLayer)及其 glassPane 作为工具提示 - 在您的上下文中,未来只是简单的(需求正在改变,不是吗:- ) 你甚至可以实现一个自定义的 LayoutUI 来在需要时处理 mouseEvent 传播。
  • @kleopatra 我也考虑过 JLayer,但我们仍然支持 java 6,当普通标准库完成这项工作时,我不想引入外部依赖项。当然,一旦最终要求第 7 版(并且需要更多功能:-D),这是一个有吸引力的选择
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-10
  • 2019-07-01
相关资源
最近更新 更多