EVALUATION
Before evaluation there is need to know a couple details of JScrollPane implementation:
1. ScrollBar visibility are set in ScrollPaneLayout#layoutContainer. That method is invoked after invalidate is invoked, therefore the layoutContainer method isn't invoked directly but postponed like invokeLater does.
2. ScrollBar values are set in the BasicScrollPaneUI#syncScrollPaneWithViewport method. That method is invoked from JViewport#fireStateChanged and can be invoked from the ScrollPaneLayout#layoutContainer method if viewport.bounds are changed, for example.
Below are four lines of code from the attached Test.java that shows the problem with comments:
textarea.setText(null);
/* BasicScrollPaneUI#syncScrollPaneWithViewport will be invoked and scrollbars will be initialized for empty text. Note: scrollbars visibility is not corrected yet, but postponed by invalidate */
pane.setViewportView(textarea);
/* Set new text and postpone JScrollBar invalidation. Note: syncScrollPaneWithViewport is not invoked here, but can be invoked later by ScrollPaneLayout#layoutContainer while invalidation (if needed) */
textarea.setText("after###1###\nafter###1###\nafter###1###\nafter###1###\nafter###1###\n");
/* Restore caret position, so JScrollPane will stay at the same view position */
textarea.setCaretPosition(0);
After that code while ScrollPaneLayout#layoutContainer it looks for JScrollPane that there is no need to synchronize scrollbars, because view size and position remain the same as in last layout.
Suggestion: I'm suggesting to force BasicScrollPaneUI#syncScrollPaneWithViewport invocation while first layout after viewports view is changed. This fix looks small and safe.
|