JScrollPane автоматически устанавливает позицию ViewPort в (0,0)

У меня есть JScrollPane, окно просмотра которого является подклассом JPanel. Эта панель выложена с помощью BoxLayout, и при взаимодействии с пользователем горизонтальная ширина компонентов может измениться. При наличии достаточного количества компонентов, таких как полосы прокрутки, изменение горизонтального размера компонента и последующий вызов revalidate() в подклассе JPanel (вид области просмотра) всегда приводит к сбросу панели прокрутки на (0,0).

Я хотел бы сохранить текущее представление, поэтому я настроил прослушиватель компонентов и на componentMoved() я сохраняю значение в getLocation() (все это находится в подклассе JPanel или в окне просмотра). Сразу после вызова revalidate() я вызываю setLocation() с сохраненным местоположением (в потоке отправки событий). Однако это вызывает дрожание, когда позиция просмотра установлена ​​​​на (0,0), а затем немедленно переходит к сохраненному местоположению. Есть ли способ остановить возвращение JScrollPane к (0,0)? Есть ли лучший способ сказать, что размер окна просмотра изменился?

Я попытался выяснить, откуда берется (0,0), создав подкласс JScrollBar и переопределив setValue() и поставив точку останова, но он не попадает туда (но происходит, когда я перемещаю колесо прокрутки), поэтому я предполагаю, что он устанавливается внутри. Кто-нибудь знает, что может происходить?


person user450775    schedule 09.08.2013    source источник
comment
Чтобы быстрее получить помощь, опубликуйте свой код как SSCCE, демонстрирующий вашу проблему. Это позволяет пользователям копировать/вставлять и воспроизводить вашу проблему.   -  person Duncan Jones    schedule 09.08.2013
comment
Я бы так и сделал, но SSCCE, который я разработал для этого вопроса, не показывал проблему. Казалось бы, из-за того, что он был таким маленьким, условия гонки не произошло (я никогда не мог визуально увидеть прыжок). У меня такой большой проект, что я не мог просто опубликовать его, поэтому я надеялся, что мое описание было достаточно хорошим :(   -  person user450775    schedule 09.08.2013


Ответы (1)


Попробуйте другой способ вызвать код после revalidate() buf до repaint().

scrollPane.getViewport().setViewPosition(new Point(x,y));

В качестве альтернативы вы можете попробовать позвонить panel.scrollRectToVisible(Rectangle)

person StanislavL    schedule 09.08.2013
comment
Спасибо, я попробую. Когда вы говорите перед перекрашиванием(), вы имеете в виду до того, как я напрямую вызову перерисовку()? Разве revalidate() не вызывает repaint() в конце концов после перекомпоновки своих компонентов? На самом деле я сам не вызываю repaint() после revalidate(), возможно, мне это нужно (я не вызывал, потому что я мог видеть обновление экрана, поэтому я решил, что он вызывается где-то внутри repaint()). - person user450775; 09.08.2013
comment
Хорошо, я попробовал то, что вы сказали, и это не сработало. Но это заставило меня задуматься. Попробовав целую кучу других вещей (удаление некоторых вызовов, изменение некоторых и т. д.), я вернулся, чтобы сделать именно то, что вы сказали. Я пошел с revalidate();repaint(); и это сработало! Единственное отличие состоит в том, что я не вызываю для него setSize(). Я думал, что мне нужно, так как размер компонента изменился, но только то, что getPreferredSize() возвращает правильный размер, заставило все работать. TL;DR: убедился, что единственными вызовами, которые у меня были, были revalidate(); и перекрасить(); не нужно было запоминать позицию и устанавливать ее - person user450775; 10.08.2013