【问题标题】:Swing: How to make JFrame scrolling smooth?Swing:如何使 JFrame 滚动流畅?
【发布时间】:2016-03-20 13:44:39
【问题描述】:

我正在创建一个由可滚动文本区域组成的非常简单的 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 上。

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

【问题讨论】:

    标签: java macos swing


    【解决方案1】:

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

    相反,您应该使用 JTextArea,它是 Swing 组件。

    基本代码是:

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

    编辑:

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

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

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

    如果您关心的是实际的单位增量,那么您可以使用以下方法更改默认值:

    scrollPane.getVerticalScrollBar().setUnitIncrement(1);
    

    【讨论】:

    • 谢谢!这解决了重绘问题。但是,它仍然按整行而不是按像素滚动,使动画非常粗粒度。我怎样才能顺利滚动?拖动滚动条时,(错误?)消息仍会打印到标准输出。不确定这是否符合预期。
    • 谢谢。我按照你的建议使用了setUnitIncrement()。这使滚动更加流畅,但不幸的是滞后。从阅读文档中,我收集到整个视图都在每个像素滚动上重新计算。我添加了一个JViewport,根据文档,它只会更新必要的区域并预加载整个组件。我现在有一个JTextArea 在一个JViewport 在一个JScrollPane 在一个JFrame 里面。但是,这可能会导致滚动条消失,因为视口本身在滚动面板的大小范围内。如何获取文本区域的滚动条?
    • @tytk,我给了你在 JScrollPane 中使用 JTextArea 所需的 3 行代码。您永远不必使用视口。视口由滚动窗格管理。我从未经历过延迟滚动,但我使用的是 Windows。我建议您发布正确的SSCCE,以便使用 OSX 的人可以测试您的代码,看看他们是否遇到同样的问题。否则我不知道该说什么。使用滚动窗格没有什么魔力。
    【解决方案2】:

    正如 camickr 所指出的,我应该使用 JTextArea 而不是 TextArea。这解决了我认为是重绘问题的白色闪烁。

    为了使滚动平滑而不滞后,我必须调整单位增量,即按下滚动条箭头之一时视图将移动的像素数:

    scrollPane.getVerticalScrollBar().setUnitIncrement(1);
    

    这最终导致了一堆延迟,因为当我滚动时,程序必须以 1px 的间隔连续计算和重绘屏幕。为了解决这个问题,我不得不改变视口滚动模式:

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

    原来它默认使用BLIT_SCROLL_MODE

    我现在拥有的是一个滚动流畅(不会跳跃像素)、不会滞后并且在我滚动太快时不会闪烁白色的应用。这是相当不错的进步。我还没有弄清楚的一件事是现在滚动速度相当慢 - 例如,让鼠标滚轮旋转得很好不会让我在页面上走得太远。这显然是因为我每个槽口只移动一个像素(这就是setUnitIncrement() 所做的)。当我积极滚动时,我想要的是在页面下方走一段很长的距离,就像在 Chrome 或 Intellij 等其他应用程序中一样。但就目前而言,我对自己拥有它的地方感到非常满意。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-29
      • 1970-01-01
      • 2014-12-06
      • 2018-01-30
      • 1970-01-01
      相关资源
      最近更新 更多