【问题标题】:Set cursor for jTabbedPane's tab in java在java中为jTabbedPane的选项卡设置光标
【发布时间】:2014-09-22 15:04:27
【问题描述】:

我创建了一个自定义 jTabbedPane 类,它扩展了 BasicTabbedPaneUI 并成功创建了我想要的 jTabbedPane 但现在的问题是如何在我的自定义 jTabbedPane 中为每个选项卡设置手形光标强>?

我试图用这个设置光标

tabbedPane.setUI(new CustomMainMenuTabs());
tabbedPane.setCursor(new Cursor((Cursor.HAND_CURSOR)));

这会为整个 jTabbedPane 设置光标,但我只想在鼠标悬停在其中的任何选项卡上时设置光标。

如何在 jTabbedPane 中为标签设置手形光标?

我的代码是

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.plaf.basic.BasicTabbedPaneUI;


public class HAAMS 
{
  //My Custom class for jTabbedPane
  public static class CustomMainMenuTabs extends BasicTabbedPaneUI
  {
    protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected)
    {
        Graphics2D g2 = (Graphics2D) g;

        Color color;

        if (isSelected) { color = new Color(74, 175, 211); } 
        else if (getRolloverTab() == tabIndex) {  color = new Color(45, 145, 180); } 
        else {color = new Color(68, 67, 67);}

        g2.setPaint(color);
        g2.fill(new RoundRectangle2D.Double(x, y, w, h, 30, 30));

        g2.fill(new Rectangle2D.Double(x + 100,y,w,h));
    }
  }

   public static void main(String[] args) 
   {
     JFrame MainScreen = new JFrame("Custom JTabbedPane");
     MainScreen.setExtendedState(MainScreen.getExtendedState() | JFrame.MAXIMIZED_BOTH);

     //Setting UI for my jTabbedPane implementing my custom class CustomMainMenuTabs
     JTabbedPane jtpane = new JTabbedPane(2);
     jtpane.setUI(new CustomMainMenuTabs());
     jtpane.add("1st Tabe", new JPanel());
     jtpane.add("2nd Tabe", new JPanel());
     jtpane.add("3rd Tabe", new JPanel());

     MainScreen.getContentPane().add(jtpane);
     MainScreen.setVisible(true);
  }
}

当鼠标悬停在任何选项卡上时,如何将光标设置为 HAND_CURSOR 光标,而不是 jpanel 或任何其他组件。如果没有鼠标监听器,那就太好了。

【问题讨论】:

  • 您需要在您的 UI 中提供鼠标支持。只需添加一个鼠标侦听器,当鼠标进入选项卡标题组件时将光标设置为手。
  • @SergiyMedvynskyy 检测 jtabbedpane 的选项卡标题组件的方法是什么,以便我可以添加鼠标侦听器。
  • 你为什么要发布赏金,你已经得到了答案?当您添加 MouseMotionListener 并使用 tabForCoordinate(...) 方法时,该代码对我来说很好。还是因为我原来的答案建议使用 MouseListener 而遇到问题?我希望您知道其中的区别,但由于您没有发布您的 SSCCE,我不确定这是否是您的问题。
  • @camickr 我发布了所有我得到的。我也尝试了你的建议,但这对我不起作用。这就是为什么我问你是否可以给我一个代码示例以便我理解它。而且我也在搜索是否可以不使用鼠标监听器
  • @AbdulJabbarWebBestow, I tried your suggestion as well but that didn't work for me. 并且您已被要求两次发布 SSCCE 以显示您尝试过的内容。向我们证明您已努力听取建议。基本代码很简单。如果tabForCoordinate() 方法返回-1,则将光标设置为空,否则将光标设置为手形光标。我离开了几天,所以在我回来之前我不能发表评论。对于您的其他问题,我也有一个想法,但是由于您尚未发布可编译的 SSCCE,因此我不打算花时间编译您的代码。

标签: java swing focus jtabbedpane mouse-cursor


【解决方案1】:

我在这里看到很多过于复杂的答案(自定义 UI、额外的侦听器、图形等)。

基本上,camickr 会为您说明。这是一个简单的演示:

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

public class JTabbedPaneCursorDemo implements Runnable
{
  JTabbedPane tabbedPane;

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new JTabbedPaneCursorDemo());
  }

  public void run()
  {
    JPanel panelA = new JPanel();
    JPanel panelB = new JPanel();

    tabbedPane = new JTabbedPane();
    tabbedPane.addTab("A", panelA);
    tabbedPane.addTab("B", panelB);

    tabbedPane.addMouseMotionListener(new MouseMotionListener()
    {
      public void mouseDragged(MouseEvent e) {}

      public void mouseMoved(MouseEvent e)
      {
        adjustCursor(e);
      }
    });

    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 200);
    frame.getContentPane().add(tabbedPane, BorderLayout.CENTER);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  private void adjustCursor(MouseEvent e)
  {
    TabbedPaneUI ui = tabbedPane.getUI();
    int index = ui.tabForCoordinate(tabbedPane, e.getX(), e.getY());

    if (index >= 0)
    {
      tabbedPane.setCursor(new Cursor((Cursor.HAND_CURSOR)));
    }
    else
    {
      tabbedPane.setCursor(null);
    }
  }
}

【讨论】:

  • +1,这基本上是我的建议,除了我会在侦听器中使用JTabbedPane tabbedPane = (JTabbedPane)e.getSource();,因此您不需要使用实例变量。
【解决方案2】:

我想在鼠标移到其中的任何选项卡上时设置光标。

我猜您需要将 MouseMotionListener 添加到选项卡式窗格中。然后,当mouseMoved(...) 事件生成时,您检查鼠标是否在选项卡上。

您应该能够使用BasicTabbePaneUItabForCoordinate(...) 方法来确定鼠标是否在选项卡上。

【讨论】:

  • 抱歉,如何使用 tabForCoordinate 检测鼠标是否在选项卡上?可以给个代码示例吗?
  • @AbdulJabbarWebBestow,我不明白这个问题?您使用 MouseEvent 中的鼠标点并调用该方法。
  • Camickr 您建议我应该使用 tabForCoordinate(...) 来确定鼠标是否在选项卡上,tabForCoordinate(...) 给出了鼠标的坐标,所以我该如何检测那么如果鼠标在选项卡上?请您提供一些代码示例,以便我理解您的意思吗?
  • tabForCoordinate(...) gives the cordinates of the mouse 不,它没有。它给出了标签。你读过 API 吗?如果您需要更多帮助,请发布您的 SSCCE,说明您是如何尝试使用此方法的。
  • @AbdulJabbarWebBestow,我已经离开 5 天了,您仍然没有使用我提出的建议发布适当的 SSCCE。我猜你对答案不感兴趣。当您甚至不愿意为我们发布代码时,您为什么期望我们所有人都为您发布代码。你是一个寻求帮助的人,所以你应该努力。你得到你所给予的,而你没有给我们任何东西。
【解决方案3】:

步骤:

  • 创建一个MouseMotionListener 并将其添加到您的JTabbedPane
  • 在侦听器内部 -> mouseMoved 方法,检查鼠标的当前位置是否在选项卡的边界内
    • 如果为真,则将光标更改为手形光标
    • 否则显示默认光标

1.检查鼠标是否在标签范围内的方法:

private static int findTabPaneIndex(Point p, JTabbedPane tabbedPane) {
    for (int i = 0; i < tabbedPane.getTabCount(); i++) {
        if (tabbedPane.getBoundsAt(i).contains(p.x, p.y)) {
            return i;
        }
    }
    return -1;
}

2.鼠标监听:

    MouseMotionListener listener = new MouseMotionAdapter() {
        public void mouseMoved(MouseEvent e) {
            JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
            if (findTabPaneIndex(e.getPoint(), tabbedPane) > -1) {
                tabbedPane.setCursor(new Cursor((Cursor.HAND_CURSOR)));
            } else {
                tabbedPane.setCursor(new Cursor((Cursor.DEFAULT_CURSOR)));
            }
        }
    };

3.将监听器添加到JTabbedPane:

    jtpane.addMouseMotionListener(listener);

相关文档:

最终代码:

将所有部分放在一起,您会得到以下结果:

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicTabbedPaneUI;

public class HAAMS {
    // My Custom class for jTabbedPane
    public static class CustomMainMenuTabs extends BasicTabbedPaneUI {
        protected void paintTabBackground(Graphics g, int tabPlacement,
                int tabIndex, int x, int y, int w, int h, boolean isSelected) {
            Graphics2D g2 = (Graphics2D) g;
            Color color;
            if (isSelected) {
                color = new Color(74, 175, 211);
            } else if (getRolloverTab() == tabIndex) {
                color = new Color(45, 145, 180);
            } else {
                color = new Color(68, 67, 67);
            }
            g2.setPaint(color);
            g2.fill(new RoundRectangle2D.Double(x, y, w, h, 30, 30));
            g2.fill(new Rectangle2D.Double(x + 100, y, w, h));
        }
    }

    public static void main(String[] args) {
        JFrame MainScreen = new JFrame("Custom JTabbedPane");
        MainScreen.setExtendedState(MainScreen.getExtendedState()
                | JFrame.MAXIMIZED_BOTH);
        JTabbedPane jtpane = new JTabbedPane(2);
        jtpane.setUI(new CustomMainMenuTabs());
        MouseMotionListener listener = new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent e) {
                JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
                if (findTabPaneIndex(e.getPoint(), tabbedPane) > -1) {
                    tabbedPane.setCursor(new Cursor((Cursor.HAND_CURSOR)));
                } else {
                    tabbedPane.setCursor(new Cursor((Cursor.DEFAULT_CURSOR)));
                }
            }
        };
        jtpane.add("1st Tabe", new JPanel());
        jtpane.add("2nd Tabe", new JPanel());
        jtpane.add("3rd Tabe", new JPanel());
        jtpane.addMouseMotionListener(listener);
        MainScreen.getContentPane().add(jtpane);
        MainScreen.setVisible(true);
    }

    private static int findTabPaneIndex(Point p, JTabbedPane tabbedPane) {
        for (int i = 0; i < tabbedPane.getTabCount(); i++) {
            if (tabbedPane.getBoundsAt(i).contains(p.x, p.y)) {
                return i;
            }
        }
        return -1;
    }
}

【讨论】:

  • 我已经是您建议的代码,但这样的问题是光标仍保留在 HAND_CURSOR 上,即使已从选项卡头移动到其面板。
  • 您可以尝试将鼠标移到选项卡上并单击它。然后您可以看到,当您在选项卡的面板内移动鼠标时,它仍然是 HAND_CURSOR。这就是我在问题的最后两行中提出的问题。
  • 我希望我的光标只有在标签头而不是面板或任何其他组件内时才更改为 HAND_CURSOR。
【解决方案4】:

你可以使用:

public void setTabComponentAt(int index,
                     Component component)

然后你做

component.addMouseListener(yourListener)

【讨论】:

  • 正如 Infinite Recursion 所说,这种方式将光标设置在整个 jtabbedpane 上,而不仅仅是选项卡头。
  • 否,因为您仅为选项卡设置了新组件。例如,您将新组件上的侦听器设置为标签。
  • 这不会按预期工作,因为 MouseEvents 源将是作为选项卡渲染器的组件,当鼠标悬停在选项卡上时,不会将鼠标事件传输到选项卡式窗格。因此,当鼠标单击时,选项卡式窗格不会在选项卡之间切换,因为此鼠标侦听器覆盖了默认行为。
  • 好吧,如果发生这种情况,您可以使用 MouseListener 模拟标签单击标签(我们假设我们放置的组件是标签),以便何时可以实现标签行为。
  • 不,它不是一个标签,它是带有标签窗格的纯标签头。
【解决方案5】:

我已根据您的需要更改了主要方法,即手形光标仅在选项卡标题上可见。检查它是否能解决您的问题

工作代码

public static void main(String[] args)
{
    JFrame MainScreen = new JFrame("Custom JTabbedPane");
    MainScreen.setExtendedState(MainScreen.getExtendedState() | JFrame.MAXIMIZED_BOTH);

    MouseListener listener = new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            JTabbedPane jp=(JTabbedPane)(e.getComponent().getParent().getParent());
            jp.setSelectedIndex(jp.indexAtLocation(e.getComponent().getX(),e.getComponent().getY()));
       }

        @Override
        public void mouseEntered(MouseEvent e) {
            e.getComponent().setCursor(new Cursor((Cursor.HAND_CURSOR)));
        }


    };

    JLabel jlabel1=new JLabel("1st Tabe");
    jlabel1.addMouseListener(listener);
    JLabel jlabel2=new JLabel("2nd Tabe");
   jlabel2.addMouseListener(listener);
    JLabel jlabel3=new JLabel("3rd Tabe");
   jlabel3.addMouseListener(listener);

    //Setting UI for my jTabbedPane implementing my custom class CustomMainMenuTabs
    JTabbedPane jtpane = new JTabbedPane(2);

   jtpane.setUI(new CustomMainMenuTabs());
    jtpane.add("1st Tabe", new JPanel());
    jtpane.setTabComponentAt( 0, jlabel1);
    jtpane.add("2nd  Tabe", new JPanel());
    jtpane.setTabComponentAt(1, jlabel2);
    jtpane.add("3rd  Tabe", new JPanel());
    jtpane.setTabComponentAt( 2, jlabel3);




    MainScreen.getContentPane().add(jtpane);
    MainScreen.setVisible(true);
}

【讨论】:

  • 没有帮助也没有
  • 你能详细说明哪里出了问题吗?我会努力改进代码。
  • 如前所述,我已经为 TabbedPane 创建了自己的自定义 L&F 类,并且我的 jtabbedPane 实现了该类,而我的 custon L&F 类有一个适用于 jTabbedPane 的长代码,因此我无法再次为 JLabels 完成所有工作.请我希望它在不使用 jlabels 的情况下在我的选项卡标题本身上工作,因为这样我也必须在 jLabels 的 l&F 上做很多工作。
  • 我想你如果你可以控制 tab ui ,然后在鼠标运动监听器上,比较鼠标移动的像素的颜色,因为你已经为 tab header 定义了颜色,比较颜色并相应地更改 Cursor .
  • 颜色比较不是很好的解决方案,所以我想比较标签的 x 和 y 坐标,但效果不佳。
【解决方案6】:

只需将此代码添加到您的CustomMainMenuTabs

  public static class CustomMainMenuTabs extends BasicTabbedPaneUI
  {
    protected void paintTabBackground(Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected)
    {
    // ...
    }
    private static final Cursor DEFAULT_CURSOR = Cursor.getDefaultCursor();
    private static final Cursor HAND_CURSOR = new Cursor((Cursor.HAND_CURSOR));
    protected void setRolloverTab(int index) {
        tabPane.setCursor((index != -1) ? HAND_CURSOR : DEFAULT_CURSOR);
        super.setRolloverTab(index);
    }
  }

说明

由于您已经在扩展 BasicTabbedPaneUI,您可以简单地扩展用于绘制翻转选项卡的机制,该机制已经在那里实现,无需使用更多侦听器或自己计算坐标。

翻转是自 Java 5 以来组件中存在的一种机制,这是一个适当的扩展,只需要覆盖和扩展该方法。每当鼠标在选项卡组件中移动时(它会影响选项卡区域但不影响子项)都会调用此方法并保持更新。

我已经用这个添加尝试了你的代码 sn-p 并且工作正常。

【讨论】:

    【解决方案7】:

    这实际上比安装自定义 UI 委托要容易得多。

    您可以将自己的标签安装为选项卡组件(选项卡句柄内的组件),它们将拥有自己的光标。以下是一个简单的示例,其中包含 3 个选项卡,选项卡式窗格的主体和每个选项卡都有一个不同的光标:

    import java.awt.*;
    import javax.swing.*;
    
    public class TestTabCursor extends JFrame {
    
        private JTabbedPane contentPane;
    
        public TestTabCursor() {
            super("Test tab cursor");
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(640, 480);
            setLocation(100, 100);
            createContentPane();        
            setCursors();
        }
    
        private void createContentPane() {
            contentPane = new JTabbedPane();
    
            addTab(contentPane);
            addTab(contentPane);
            addTab(contentPane);
    
            setContentPane(contentPane);
        }
    
        private void addTab(JTabbedPane tabbedPane) {
            int index = tabbedPane.getTabCount() + 1;
    
            JLabel label = new JLabel("Panel #" + index);
            label.setHorizontalAlignment(SwingConstants.CENTER);
            label.setFont(label.getFont().deriveFont(72f));
    
            JPanel panel = new JPanel(new BorderLayout());
            panel.setBackground(Color.white);
            panel.add(label, BorderLayout.CENTER);
    
            JLabel title = new JLabel("Tab " + index);
    
            tabbedPane.add(panel);
            tabbedPane.setTabComponentAt(index - 1, title);
        }
    
        private void setCursors() {
            contentPane.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
    
            contentPane.getTabComponentAt(0).setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
            contentPane.getTabComponentAt(1).setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
            contentPane.getTabComponentAt(2).setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));     
        }
    
        public static void main(String... args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    JFrame frame = new TestTabCursor();
                    frame.setVisible(true);
                }
            });
        }
    }
    

    【讨论】:

    • 为什么投反对票?这是工作代码,解决了问题中的问题。
    猜你喜欢
    • 1970-01-01
    • 2017-12-15
    • 2014-12-06
    • 1970-01-01
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    相关资源
    最近更新 更多