繁体   English   中英

JTable 单元格中的 JPanel 中的 JLabels 不显示工具提示

[英]Tooltips don't display for JLabels in a JPanel in a JTable cell

下面显示了JTable单元格,每个单元格都包含一个面板,该面板又包含两个标签。 我已经在 JLabel 上设置了工具JLabel ,但它们没有出现。 (感谢@MadProgrammer 提供的原始精简代码以显示JTable并说明 setToolTipLocation setToolTipLocation() 。)

我为一个 label 覆盖getToolTipText() ,并为另一个调用 setToolTipText setToolTipText() 如果我在前一个中设置断点,它会被调用,但不会出现工具提示。 所以我尝试覆盖setToolTipLocation() ,尽管我不确定它的合适值是什么; 我不确定它会使用什么坐标系,认为 10,10 会将它留在大多数事物的范围内。

这里没有显示,我还尝试在getTableCellRendererComponent()调用之外创建标签,并在getTableCellRendererComponent() () 中设置它们的尺寸、背景 colors 和工具提示。 那也行不通。

我还需要做什么才能看到这些工具提示?

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.MouseEvent;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.border.Border;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
    
    public class Test
    {
      Border labelBorder = BorderFactory.createLineBorder(Color.black);
    
      public static void main(String[] args)
      {
        new Test();
      }
    
      public Test()
      {
        EventQueue.invokeLater
        (new Runnable()
          {
            @Override
            public void run()
            {
              JFrame frame = new JFrame("Testing");
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              frame.add(new TestPane());
              frame.pack();
              frame.setLocationRelativeTo(null);
              frame.setVisible(true);
            }
          }
        );
      }
    
      public class TestPane extends JPanel
      {
        public TestPane()
        {
          setLayout(new BorderLayout());
          int rows = 4;
          int cols = 3;
          DefaultTableModel model = new DefaultTableModel(0, cols);
          for (int row = 0; row < rows; row++)
          {
            Object[] data = new Object[cols];
            for (int col = 0; col < cols; col++)
            {
              data[col] = row + "x" + col;
            }
            model.addRow(data);
          }
    
          JTable table = new JTable(model);
//          table.setToolTipText("table text");     // this works, but would block tooltips from UI children
          table.setDefaultRenderer(Object.class, new TestCellRenderer());
    
          add(new JScrollPane(table));
        }
    
        public class TestCellRenderer extends DefaultTableCellRenderer
        {
          @Override
          public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
              int row, int column)
          {
            // create two labels, put them side-by-side in a panel, and return
            // the panel as the component being rendered.
            JLabel label1 = new JLabel("a Banana @" + value.toString())
            {
              @Override
              public String getToolTipText() 
              { 
                return "AA"; 
              }
              @Override public Point getToolTipLocation(MouseEvent mouseEvent) { return new Point(10,10); }
            };
            label1.setBorder(labelBorder);
            label1.setToolTipText("AA");            // this tooltip text does not show up.
    
            JLabel label2 = new JLabel("b Banana @" + value.toString());
            label2.setBorder(labelBorder);
            label2.setToolTipText("BB");            // this tooltip text does not show up.
            
            JPanel panel = new JPanel();
            BoxLayout layout = new BoxLayout(panel, BoxLayout.X_AXIS);
            panel.setLayout(layout);
//            panel.setToolTipText("panel text");   //this works, but would block tooltips on the JLabels
            panel.add(label1);
            panel.add(label2);
            
            return panel;
          }
        }
      }
    }

我为一个 label 覆盖 getToolTipText()

如何尝试覆盖JTable#getToolTipText(MouseEvent)方法而不是JLabel

import java.awt.*;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.table.*;

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

  public Test2() {
    EventQueue.invokeLater(() -> {
      JFrame frame = new JFrame("Testing");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(new TestPane());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
    });
  }
}

class TestPane extends JPanel {
  public TestPane() {
    super(new BorderLayout());
    int rows = 4;
    int cols = 3;
    DefaultTableModel model = new DefaultTableModel(0, cols);
    for (int row = 0; row < rows; row++) {
      Object[] data = new Object[cols];
      for (int col = 0; col < cols; col++) {
        data[col] = row + "x" + col;
      }
      model.addRow(data);
    }

    JTable table = new JTable(model) {
      @Override public String getToolTipText(MouseEvent e) {
        Point pt = e.getPoint();
        int vrow = rowAtPoint(pt);
        int vcol = columnAtPoint(pt);
        TableCellRenderer tcr = getCellRenderer(vrow, vcol);
        Component c = prepareRenderer(tcr, vrow, vcol);
        if (c instanceof JPanel) {
          Rectangle r = getCellRect(vrow, vcol, true);
          c.setBounds(r);
          c.doLayout();
          pt.translate(-r.x, -r.y);
          Component l = SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y);
          if (l instanceof JLabel) {
            return ((JLabel) l).getToolTipText();
          }
        }
        return super.getToolTipText(e);
      }
    };
    table.setDefaultRenderer(Object.class, new TestCellRenderer());
    add(new JScrollPane(table));
  }
}

class TestCellRenderer extends DefaultTableCellRenderer {
  @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
    JLabel label1 = new JLabel("a Banana @" + value.toString());
    label1.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    label1.setToolTipText("AA");

    JLabel label2 = new JLabel("b Banana @" + value.toString());
    label2.setBorder(BorderFactory.createLineBorder(Color.BLACK));
    label2.setToolTipText("BB");

    JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.add(label1);
    panel.add(label2);

    return panel;
  }
}

有一些旧代码允许您覆盖用作渲染器的面板的getToolTipText(...)方法。

不幸的是,它似乎只在将 GridLayout 用作面板的布局管理器时才起作用。

使用aterai提供的“布局”代码,我也能够使代码适用于 FlowLayout。 (没有尝试其他布局管理器):

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

public class TableRendererPanelHelp
{
    static class MultiLabelRenderer implements TableCellRenderer
    {
        private JTable table;
        private int row;
        private int column;

        private JPanel panel;
        private JLabel red;
        private JLabel blue;

        public MultiLabelRenderer()
        {
            red = new JLabel();
            red.setForeground(Color.RED);
            blue = new JLabel();
            blue.setForeground(Color.BLUE);

            panel = new JPanel( new FlowLayout(0, 0, FlowLayout.LEFT) )
            {
                public String getToolTipText(MouseEvent e)
                {
                    String tooltip = null;

                    Rectangle r = table.getCellRect(row, column, true);
                    setBounds(r);
                    doLayout();

                    Component c = getComponentAt( e.getPoint() );

                    if (c instanceof JLabel)
                    {
                        JLabel label = (JLabel)c;
                        tooltip = label.getToolTipText();
                    }

                    return tooltip;
                }
            };

            panel.add(red);
            panel.add(blue);
        }

        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, final int row, final int column)
        {
            this.row = row;
            this.column= column;
            this.table = table;

            panel.setBackground( isSelected ? table.getSelectionBackground() : table.getBackground() );

            if (value == null || value.toString().isEmpty())
            {
                red.setText("");
                blue.setText("");
            }
            else
            {
                String text = value.toString();
                red.setText( text.substring(0, 3) );
                red.setToolTipText( red.getText() );
                blue.setText( text.substring(3) );
                blue.setToolTipText( blue.getText() );
            }

            return panel;
        }
    }

    public static void createAndShowGUI()
    {
        JTable table = new JTable(5, 3);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        table.getColumnModel().getColumn(0).setCellRenderer( new MultiLabelRenderer());
        JScrollPane scrollPane = new JScrollPane( table );

        table.setValueAt("abcde", 0, 0);
        table.setValueAt("123456789", 1, 0);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( scrollPane );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }

    public static void main(String[] args) throws Exception
    {
        java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
    }

}

这种方法的一个好处是所有逻辑都包含在渲染器 class 中,您不需要覆盖 JTable。

此外,此方法尝试重用 JPanel 和 JLabels,因此您不必在每次呈现单元格时都不断创建新组件。

也许晚了,但这里有一个类似的方法,不应该依赖于布局管理器。

所有代码都在直接扩展 JPanel 的 CellRenderer 中,然后将 getToolTip 请求重新抛出到适应 MouseEvent 的子组件。

package test;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class TestTooltipTable {

    Border labelBorder = BorderFactory.createLineBorder(Color.black);

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

    public TestTooltipTable() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {
        public TestPane() {
            setLayout(new BorderLayout());
            int rows = 4;
            int cols = 3;
            DefaultTableModel model = new DefaultTableModel(0, cols);
            for (int row = 0; row < rows; row++) {
                Object[] data = new Object[cols];
                for (int col = 0; col < cols; col++) {
                    data[col] = row + "x" + col;
                }
                model.addRow(data);
            }

            JTable table = new JTable(model);
//          table.setToolTipText("table text");     // this works, but would block tooltips from UI children
            table.setDefaultRenderer(Object.class, new TestCellRenderer());

            add(new JScrollPane(table));
        }

        public class TestCellRenderer extends JPanel implements TableCellRenderer {
            protected JLabel label1;
            protected JLabel label2;
            
            protected Rectangle cellRect;

            public TestCellRenderer() {
                setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
                label1 = new JLabel(" ");
                label2 = new JLabel(" ");

                label1.setBorder(labelBorder);
                label1.setToolTipText("AA"); // this tooltip text does not show up.

                label2.setBorder(labelBorder);
                label2.setToolTipText("BB"); // this tooltip text does not show up.

                add(label1);
                add(label2);

            }

            @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                    boolean hasFocus, int row, int column) {
                // create two labels, put them side-by-side in a panel, and return
                // the panel as the component being rendered.
                label1.setText("a Banana @" + value.toString());
                label1.setToolTipText("AA "+row+"x"+column);

                label2.setText("b Banana @" + value.toString());
                label2.setToolTipText("BB "+row+"x"+column); // this tooltip text does not show up.

                cellRect=table.getCellRect(row, column, true);
                
                return this;
            }

            @Override
            public String getToolTipText(MouseEvent event) {
                if (cellRect==null) {
                    return null;
                }
                
                setBounds(cellRect);
                doLayout();
                Point p=event.getPoint();
                Component c=SwingUtilities.getDeepestComponentAt(this, p.x, p.y);

                if (!(c instanceof JComponent)) {
                    return null;
                }
                p=SwingUtilities.convertPoint(this, p, c);
                MouseEvent newEvent = new MouseEvent(c, event.getID(),
                        event.getWhen(), event.getModifiersEx(),
                        p.x, p.y,
                        event.getXOnScreen(),
                        event.getYOnScreen(),
                        event.getClickCount(),
                        event.isPopupTrigger(),
                        MouseEvent.NOBUTTON);

                return ((JComponent) c).getToolTipText(newEvent);
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM