Swing:如何让JFrame滚动流畅?

时间:2016-03-17 16:50:27

标签: java macos swing

我正在创建一个非常简单的Swing GUI,其中包含一个可滚动的文本区域。但是,我在UI的响应性方面遇到了一些问题。这是我用来尝试一些不同配置的类:

public class ComponentSample {
  public void createWindow() {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    TextArea textArea = new TextArea(getFillerText(), 40, 120);

    setViews(frame, textArea);

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

  private void setViews(JFrame frame, TextArea textArea) {
    ...
  }

  private String getFillerText() {
    String threeLines = "Why isn't scrolling smooth? \nSteve Jobs would not approve\n\n";
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < 100; i++) {
      stringBuilder.append(threeLines);
    }
    return stringBuilder.toString();
  }

  public static void main(String[] args) throws Exception {
    SwingUtilities.invokeLater(
      () -> new ComponentSample().createWindow()
    );
  }
}

在这里,我为setViews()方法尝试了几种不同的方法体,结果如下:

在JPanel中添加textArea

    JPanel panel = new JPanel();
    panel.add(textArea);
    frame.add(panel);

滚动1或2行而不是像素(不平滑)。快速滚动时也会闪烁白色(重新绘制问题?)。

在视口中添加textArea

    JViewport viewport = new JViewport();
    viewport.setView(textArea);
    frame.add(viewport);

与JPanel相同的结果。

直接添加textArea

    frame.add(textArea);

与JPanel相同的结果。

在ScrollPane中添加textArea

    JScrollPane scrollPane = new JScrollPane(textArea);
    scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
    frame.add(scrollPane);

似乎没有正确处理滚动 - 它没有响应滚轮(只点击滚动条)。滚动~0.5行而不是像素。

此外,在上述每种情况下,当用鼠标拖动滚动条时,它会将以下内容(错误?IDEA显示为红色)打印到标准输出:

2016-03-17 09:45:33.413 java[40977:2845515] inOptions: {
    JavaCUIThumbStartKey = 0;
    "is.flipped" = 0;
    kCUIOrientationKey = kCUIOrientVertical;
    kCUIThumbProportionKey = "0.1328903585672379";
    max = 0;
    pressedpart = 0;
    state = normal;
    value = 0;
    widget = scrollbar;
}
2016-03-17 09:45:33.413 java[40977:2845515] inOptions: {
    JavaCUIThumbStartKey = 0;
    "is.flipped" = 0;
    kCUIOrientationKey = kCUIOrientVertical;
    kCUIThumbProportionKey = "0.1328903585672379";
    max = 0;
    pressedpart = 0;
    state = normal;
    value = 0;
    widget = scrollbar;
}
2016-03-17 09:45:33.414 java[40977:2845515] outHitPart = 0

如果重要,我就是OS X.

我的问题是如何让它平滑滚动(逐个像素)而不会闪烁白色而且没有打印错误?

2 个答案:

答案 0 :(得分:3)

不要使用作为AWT组件的TextArea。

相反,你应该使用JTextArea这是Swing组件。

基本代码是:

JTextArea textArea = new JTextArea(5, 20);
JScrollPane scrollPane = new JScrollPane( textArea );
frame.add( scrollPane );

编辑:

  

它仍然按整行而不是按像素滚动

滚动窗格支持单元滚动和块滚动的概念。 JTextArea的单位滚动是一行文本,块滚动是视口窗口的大小。使用鼠标时,滚动(在窗口中)基于单位滚动的倍数,在我的组件上滚动3 *单位滚动。

如果您关心的是鼠标滚轮完成滚动的数量,那么您可以使用Mouse Wheel Controller,它允许您将乘数更改为不同的值。所以你可以把它设置为1。

如果您关注的是实际单位增量金额,则可以使用以下方法更改默认值:

scrollPane.getVerticalScrollBar().setUnitIncrement(1);

答案 1 :(得分:1)

正如卡米克所指出的那样,我应该使用JTextArea代替TextArea。这修复了我认为重复问题的白色闪光。

为了使滚动变得平滑而没有延迟,我不得不调整单位增量,即当按下其中一个滚动条箭头时视图将移动的像素数:

scrollPane.getVerticalScrollBar().setUnitIncrement(1);

这导致了一堆延迟,因为当我滚动程序时必须连续计算并以1px间隔重绘屏幕。要解决此问题,我必须更改视口滚动模式:

scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);

事实证明它默认使用BLIT_SCROLL_MODE

我现在拥有的是一个可以平滑滚动的应用程序(不会跳转像素),不会延迟,当我滚动太快时不会闪烁白色。这是非常好的进展。我还没弄清楚的一点是,现在滚动速度相当慢 - 例如,给鼠标滚轮一个好的旋转不会让我在页面上走得太远。这显然是因为我每个凹口仅移动一个像素(这就是setUnitIncrement()所做的)。我想要的是在我滚动的时候在页面上走得很远,就像Chrome或Intellij等其他应用程序一样。但是现在我对我得到它的地方非常满意。