【问题标题】:Show scrollbars only when mouse is over仅在鼠标悬停时显示滚动条
【发布时间】:2017-07-19 21:01:33
【问题描述】:

我只想在鼠标悬停时在 JScrollPane 中显示滚动条。我尝试使用下面显示的方法将 MouseAdapter 作为 MouseListener 添加到 JScrollbar,但效果不佳。当鼠标移到滚动条上方时,滚动条会闪烁。

有什么建议吗?

@Override
public void mouseEntered(java.awt.event.MouseEvent evt) {

    Runnable runner = new Runnable()
    {
        public void run() {

            JScrollPane sp = (JScrollPane) evt.getSource();
            sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);


        }

    };   

    Thread t = new Thread(runner, "Enter Thread");
    t.start();

}
@Override
public void mouseExited(java.awt.event.MouseEvent evt) {

    Runnable runner = new Runnable()
    {
        public void run() {

            JScrollPane sp = (JScrollPane) evt.getSource();
            sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
            sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        }

    }; 
    Thread t = new Thread(runner, "Exit Thread");
    t.start();}

【问题讨论】:

  • 为了获得体面帮助的最佳机会,请考虑创建并发布一个体面的SSCCE
  • 再次,请创建并发布您的minimal reproducible example。此外,您的代码不符合 Swing 线程规则,即您要查看的规则。请阅读Concurrency in Swing

标签: java swing hover mouseevent jscrollbar


【解决方案1】:
import java.awt.*;
import java.awt.event.*;
import java.util.Collections;
import javax.swing.*;
import javax.swing.plaf.LayerUI;

public class ScrollPaneMouseOverTest {
  public JComponent makeUI() {
    String text = String.join("\n", Collections.nCopies(100, "aaaaa"));
    JTextArea ta = new JTextArea(
        "Mouse cursor flickers over the JScrollBar.\n" + text);
    ta.addMouseListener(new MouseAdapter() {
      @Override public void mouseEntered(MouseEvent e) {
        JScrollPane sp = (JScrollPane) SwingUtilities.getAncestorOfClass(
            JScrollPane.class, (Component) e.getSource());
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      }
      @Override public void mouseExited(MouseEvent e) {
        JScrollPane sp = (JScrollPane) SwingUtilities.getAncestorOfClass(
            JScrollPane.class, (Component) e.getSource());
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
      }
    });

    JScrollPane scroll = new JScrollPane(new JTextArea(text));
    scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);

    JPanel p = new JPanel(new GridLayout(2, 1));
    p.add(new JScrollPane(ta));
    p.add(new JLayer<>(scroll, new LayerUI<JScrollPane>() {
      @Override public void installUI(JComponent c) {
        super.installUI(c);
        if (c instanceof JLayer) {
          ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
        }
      }
      @Override public void uninstallUI(JComponent c) {
        if (c instanceof JLayer) {
          ((JLayer) c).setLayerEventMask(0);
        }
        super.uninstallUI(c);
      }
      @Override protected void processMouseEvent(
            MouseEvent e, JLayer<? extends JScrollPane> l) {
        JScrollPane sp = l.getView();
        switch (e.getID()) {
          case MouseEvent.MOUSE_ENTERED:
            sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            break;
          case MouseEvent.MOUSE_EXITED:
            sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
            break;
          default:
            break;
        }
        //super.processMouseEvent(e, l);
      }
    }));
    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new ScrollPaneMouseOverTest().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

【讨论】:

    【解决方案2】:

    我已编辑我的答案以包含以下评论。

        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setPreferredSize(new Dimension(600, 600));
        scrollPane.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(final java.awt.event.MouseEvent evt) {
    
                EventQueue.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        JScrollPane sp = (JScrollPane) evt.getSource();
                        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
                        sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
                    }
                });
    
            }
    
            @Override
            public void mouseExited(final java.awt.event.MouseEvent evt) {
    
                EventQueue.invokeLater(new Runnable() {
    
                    @Override
                    public void run() {
    
                        JScrollPane sp = (JScrollPane) evt.getSource();
                        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
                        sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    
                    }
                });
            }
        });
    
        JPanel panel = new JPanel(new BorderLayout());
        add(panel);
        JTextArea ta = new JTextArea();
        ta.setPreferredSize(new Dimension(500, 500));
        scrollPane.add(ta);
        panel.add(scrollPane);
    

    【讨论】:

    • 你意识到你打破了 Swing 的单线程规则——你应该使用 Thread,而不是使用 EventQueue.invokeLater 并将 Runnable 传递给它
    • 不,不是,它是从 EDT 的上下文之外更新 ui 的状态,这明显违反了 api 的单线程性质
    猜你喜欢
    • 2012-04-18
    • 2019-03-03
    • 2020-01-05
    • 1970-01-01
    • 2013-01-04
    • 2015-07-27
    • 2012-03-19
    • 2021-02-19
    • 1970-01-01
    相关资源
    最近更新 更多