2017-07-19 191 views
-1

我只想在鼠标悬停时才在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();} 
+1

为了得到体面的帮助下,可以考虑创建和发布一个体面[SSCCE的最好机会](http://SSCCE.org)。 –

+0

再次请创建并发布您的[mcve]。此外,您的代码不符合Swing线程规则,您需要查看的规则。请阅读[并发在Swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/)。 –

回答

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

这是行得通的!非常感谢你 –

0

我编辑了我的答案,包括下面的评论。

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); 
+3

你意识到你打破了Swing的单线程规则 - 而是使用'Thread',你应该使用'EventQueue.invokeLater'并将'Runnable'传递给它 – MadProgrammer

+0

这是正确的答案。 – BaneDad

+0

不,它不是从美国东部时间以外的环境更新ui的状态,这明显违反了api的单线程本质 – MadProgrammer