简体   繁体   English

Swing:如何让JFrame滚动流畅?

[英]Swing: How to make JFrame scrolling smooth?

I'm creating a very simple Swing GUI consisting of a scrollable text area. 我正在创建一个非常简单的Swing GUI,它包含一个可滚动的文本区域。 However, I'm having some problems with the responsiveness of the UI. 但是,我在UI的响应性方面遇到了一些问题。 Here is the class I am using to try some different configurations: 这是我用来尝试一些不同配置的类:

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()
    );
  }
}

Here I have tried several different method bodies for the setViews() method with the following results: 这里我为setViews()方法尝试了几个不同的方法体,结果如下:

Adding textArea in a JPanel 在JPanel中添加textArea

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

Scrolls by 1 or 2 rows instead of by pixel (not smooth). 滚动1或2行而不是按像素(不平滑)。 Also flashes white when scrolling quickly (repainting issue?). 快速滚动时也会闪烁白色(重新绘制问题?)。

Adding textArea in a Viewport 在视口中添加textArea

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

Same results as JPanel. 与JPanel相同的结果。

Adding textArea directly 直接添加textArea

    frame.add(textArea);

Same results as JPanel. 与JPanel相同的结果。

Adding textArea in a ScrollPane 在ScrollPane中添加textArea

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

Doesn't seem to handle scrolling properly - it doesn't respond to the scrollwheel (only clicking the scrollbar). 似乎没有正确处理滚动 - 它不响应滚轮(只单击滚动条)。 Scrolls by ~0.5 row instead of by pixel. 滚动约0.5行而不是像素。

Also, in each of the above cases, when the scrollbar is dragged with the mouse it prints the following (error? IDEA shows it in red) to the stdout: 此外,在上述每种情况下,当用鼠标拖动滚动条时,它会将以下内容(错误?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

If it matters, I'm on OS X. 如果重要的话,我就是OS X.

My question is how can I make it scroll smoothly (pixel by pixel) without flashing white and without printing errors? 我的问题是如何使其平滑滚动(逐个像素)而不会闪烁白色且没有打印错误?

Don't use a TextArea that is an AWT component. 不要使用作为AWT组件的TextArea。

Instead you should be using a JTextArea which is the Swing component. 相反,你应该使用一个JTextArea ,它是Swing组件。

The basic code is: 基本代码是:

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

Edit: 编辑:

it still scrolls by full rows instead of by pixel 它仍然按整行而不是按像素滚动

A scroll pane support the concept of unit scrolling and block scrolling. 滚动窗格支持单元滚动和块滚动的概念。 Unit scrolling for a JTextArea is one row of text and block scrolling is the size of the viewport window. JTextArea的单位滚动是一行文本,块滚动是视口窗口的大小。 When using a mouse the scrolling (in windows) is based on a multiple of the unit scrolling which on my component is 3 * the unit scrolling. 当使用鼠标时,滚动(在窗口中)基于单位滚动的多个,在我的组件上滚动3 *单位滚动。

If your concern is the amount of scrolling done by the mouse wheel then maybe you can use the Mouse Wheel Controller which allows you to change the multiplier to a different value. 如果您担心的是鼠标滚轮完成的滚动量,那么您可以使用鼠标滚轮控制器 ,它允许您将乘数更改为不同的值。 So you could set it to 1. 所以你可以把它设置为1。

If you concern is the actual unit increment amount then you can change the default by using: 如果您关注的是实际的单位增量金额,那么您可以使用以下方法更改默认值:

scrollPane.getVerticalScrollBar().setUnitIncrement(1);

As camickr pointed out, I should have been using a JTextArea instead of a TextArea . 正如camickr指出的那样,我应该使用JTextArea而不是TextArea That fixed the white flashes which I assume were repaint issues. 这修复了我认为是重绘问题的白色闪光。

To make scrolling smooth without being laggy, I had to adjust the unit increment, which is the number of pixels the view will move by when one of the scrollbar arrows is pressed: 为了使滚动变得平滑而不是滞后,我不得不调整单位增量,即当按下其中一个滚动条箭头时视图将移动的像素数:

scrollPane.getVerticalScrollBar().setUnitIncrement(1);

This ended up causing a bunch of lag because when I scrolled the program had to continuously calculate and redraw the screen at 1px intervals. 这最终导致一堆延迟,因为当我滚动程序时必须连续计算并以1px间隔重绘屏幕。 To fix this, I had to change the viewport scroll mode: 要解决这个问题,我不得不改变视口滚动模式:

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

It turns out it was using BLIT_SCROLL_MODE by default. 事实证明它默认使用BLIT_SCROLL_MODE

What I have now is an app that scrolls smoothly (doesn't jump pixels), doesn't lag and doesn't flash white when I scroll too fast. 我现在拥有的是一个平滑滚动的应用程序(不跳跃像素),不会滞后,当我滚动太快时不会闪烁白色。 That's pretty good progress. 这是非常好的进展。 The one thing I haven't managed to figure out is that now scrolling is fairly slow - eg giving the mouse wheel a good spin doesn't get me too far down the page. 我还没弄清楚的一点是,现在滚动速度相当慢 - 例如,给鼠标滚轮一个好的旋转不会让我在页面上走得太远。 This is obviously because I'm only moving one pixel per notch (that's what setUnitIncrement() did). 这显然是因为我每个凹口仅移动一个像素(这就是setUnitIncrement()所做的)。 What I want is to go a good distance down the page when I scroll agressively, just like in other apps like Chrome or Intellij. 我想要的是在我滚动的时候在页面上走得很远,就像Chrome或Intellij等其他应用程序一样。 But for now I'm pretty happy with where I've got it. 但是现在我对我得到它的地方非常满意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM