我正在创建一个非常简单的 Swing GUI,其中包含一个可滚动文本区域。但是,我在用户界面的响应能力方面遇到了一些问题。这是我用来尝试一些不同配置的类:
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()
);
}
}
Run Code Online (Sandbox Code Playgroud)
这里我对该方法尝试了几种不同的方法体,setViews()结果如下:
在 JPanel 中添加文本区域
JPanel panel = new JPanel();
panel.add(textArea);
frame.add(panel);
Run Code Online (Sandbox Code Playgroud)
按 1 或 2 行滚动而不是按像素滚动(不平滑)。快速滚动时也会闪烁白色(重新绘制问题?)。
在视口中添加文本区域
JViewport viewport = new JViewport();
viewport.setView(textArea);
frame.add(viewport);
Run Code Online (Sandbox Code Playgroud)
与 JPanel 的结果相同。
直接添加textArea
frame.add(textArea);
Run Code Online (Sandbox Code Playgroud)
与 JPanel 的结果相同。
在 ScrollPane 中添加 textArea
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
frame.add(scrollPane);
Run Code Online (Sandbox Code Playgroud)
似乎无法正确处理滚动 - 它不响应滚轮(仅单击滚动条)。按约 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
Run Code Online (Sandbox Code Playgroud)
如果重要的话,我使用的是 OS X。
我的问题是如何使其平滑滚动(逐像素)而不闪烁白色且没有打印错误?
正如 camickr 指出的那样,我应该使用 aJTextArea而不是TextArea. 这解决了我认为是重画问题的白色闪光。
为了使滚动平滑而不滞后,我必须调整单位增量,即按下滚动条箭头之一时视图将移动的像素数:
scrollPane.getVerticalScrollBar().setUnitIncrement(1);
Run Code Online (Sandbox Code Playgroud)
这最终导致了一堆延迟,因为当我滚动时,程序必须以 1px 的间隔连续计算和重绘屏幕。为了解决这个问题,我必须更改视口滚动模式:
scrollPane.getViewport().setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
Run Code Online (Sandbox Code Playgroud)
原来是BLIT_SCROLL_MODE默认使用的。
我现在拥有的应用程序可以平滑滚动(不会跳跃像素),不会滞后,并且当我滚动太快时不会闪烁白色。这已经是相当不错的进步了。我还没有弄清楚的一件事是,现在滚动速度相当慢 - 例如,使鼠标滚轮旋转良好并不会让我在页面上走得太远。这显然是因为我每个凹口只移动一个像素(这就是所做setUnitIncrement()的)。我想要的是当我积极滚动时,在页面上向下移动一段距离,就像在 Chrome 或 Intellij 等其他应用程序中一样。但目前我对自己所拥有的一切感到非常满意。