我的問題滾動位置很相似,這一個:JScrollPane的:後重新驗證
Set the vertical scroll to current position after revalidate
不同的是,我不想捲回至0,而是從更新前我救的位置子組件如下:
final int oldPos = scrollPanel.getVerticalScrollBar().getValue();
removeAll(); // Removes all components from the JPanel
add(mList()); // Adds a bunch of content
revalidate();
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
ml.getVerticalScrollBar().setValue(oldPos);
}
});
此代碼獲取另一componenent的鼠標移動偵聽器觸發因此它被稱爲相當頻繁。
即使最初jscrollpane滾動到頂部有時oldPos不爲零,導致窗格向下滾動,儘管設置了該值。
即使我用力滾動到頂部,只要登錄oldPos價值,它並不總是0:
final int oldPos = scrollPanel.getVerticalScrollBar().getValue();
removeAll();
add(mList());
revalidate();
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
System.out.println(oldPos); // Sometimes this is > 2000
ml.getVerticalScrollBar().setValue(0); // scroll to the top
}
});
我想如果oldPos = ...
代碼先前執行的invokeLater的塊之前執行這種情況被調用。我怎樣才能解決這個問題?
更新:
我創建了一個SSCCE的建議通過@mKorbel:
更新2:我更新了SSCCE允許的JTextArea/JLabel的之間的切換,啓用/禁用的重新綁定監聽器,並在jTextArea和從jTextArea繼承的自定義類之間切換,覆蓋scrollRectToVisible方法。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
public class Main {
static class MyTextArea extends JTextArea {
@Override
public void scrollRectToVisible(final Rectangle aRect) {
// supress scrollToRect in textarea
}
}
static final Box inner = Box.createVerticalBox();
// if the jtextarea should contain text
private static boolean textEnabled = true;
private static boolean usejLabel = false;
private static boolean useRebinding = false;
private static boolean useLock = true;
private static boolean customTextarea = false;
private static boolean _locked = false;
public static void main(final String[] args) {
final JFrame frame = new JFrame();
final JPanel insideScroll = insideScroll();
final JScrollPane scrollpane = new JScrollPane(insideScroll);
scrollpane.setAutoscrolls(false);
scrollpane
.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
final JPanel rightPanel = new JPanel();
rightPanel.setPreferredSize(new Dimension(300, 300));
final MouseMotionAdapter listener = new MouseMotionAdapter() {
@Override
public void mouseDragged(final MouseEvent e) {
super.mouseDragged(e);
final boolean rebind = useRebinding;
final MouseMotionAdapter self = this;
if (rebind) {
rightPanel.removeMouseMotionListener(self);
}
final int pos = scrollpane.getVerticalScrollBar().getValue();
if (!useLock || !_locked) {
if (useLock) {
_locked = true;
}
update();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (rebind) {
rightPanel.addMouseMotionListener(self);
}
if (useLock) {
_locked = false;
}
}
});
}
}
};
rightPanel.addMouseMotionListener(listener);
// Add labels describing the problem
rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.PAGE_AXIS));
final JButton toggleButton = new JButton("Toggle text");
final JButton toggleButtonLabel = new JButton("Toggle JLable/JTextArea");
final JButton toggleButtonRebind = new JButton("Turn rebinding on");
final JButton toggleButtonCustomTextArea = new JButton(
"Toggle Custom Textarea");
rightPanel.add(toggleButton);
rightPanel.add(toggleButtonLabel);
rightPanel.add(toggleButtonRebind);
rightPanel.add(toggleButtonCustomTextArea);
rightPanel
.add(new JLabel(
"<html>If the text is disabled, you can press/drag<br> your mouse on on right side of the<br> window and the scrollbar will<br> stay in its position."));
rightPanel
.add(new JLabel(
"<html><br/>If the text is enabled, the scrollbar<br> will jump around when dragging<br> on the right side."));
rightPanel
.add(new JLabel(
"<html><br/>The problem does not occur when using JLabels instead of JTextArea"));
// enable/disable the text when the button is clicked.
toggleButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
textEnabled = !textEnabled;
update();
}
});
toggleButtonLabel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
usejLabel = !usejLabel;
update();
}
});
toggleButtonRebind.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
useRebinding = !useRebinding;
toggleButtonRebind.setText(useRebinding ? "Turn rebinding off"
: "Turn rebinding on");
update();
}
});
toggleButtonCustomTextArea.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
customTextarea = !customTextarea;
update();
}
});
final JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
scrollpane, rightPanel);
frame.add(split);
// initialize the scrollpane content
update();
frame.pack();
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
// initializes the components inside the scrollpane
private static JPanel insideScroll() {
final JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(inner, BorderLayout.NORTH);
return panel;
}
// replaces all components inside the scrollpane
private static void update() {
inner.removeAll();
for (int i = 0; i < 30; i++) {
inner.add(buildRow(i));
}
inner.revalidate();
}
// build a single component to be inserted into the scrollpane
private static JPanel buildRow(final int i) {
final JPanel row = new JPanel();
final Color bg = i % 2 == 0 ? Color.DARK_GRAY : Color.LIGHT_GRAY;
row.setBackground(bg);
row.setPreferredSize(new Dimension(300, 80));
row.setLayout(new BorderLayout());
row.add(textarea(bg), BorderLayout.CENTER);
return row;
}
// build the textarea to be inserted into the cells in the scroll pane
private static Component textarea(final Color bg) {
final String text = String.format("%d", (int) (1000 * Math.random()))
+ " Lorem ipsum dolor si amet. Lorem ipsum dolor si amet. Lorem ipsum dolor si amet";
if (usejLabel) {
final JLabel textarea = new JLabel();
textarea.setBackground(bg);
if (textEnabled) {
textarea.setText(text);
}
return textarea;
} else {
final JTextArea textarea;
if (customTextarea) {
textarea = new MyTextArea();
textarea.setDisabledTextColor(Color.cyan);
} else {
textarea = new JTextArea();
textarea.setDisabledTextColor(Color.black);
}
textarea.setEnabled(false);
textarea.setLineWrap(true);
textarea.setBackground(bg);
textarea.setEditable(false);
if (textEnabled) {
textarea.setText(text);
}
return textarea;
}
}
}
通過這樣做,我意識到,只有當jscroll包含有自己的文字設置爲一個字符串的JTextArea元素出現問題。 在我真正的應用程序中,我需要自動換行的textareas,但即使禁用換行也會出現問題。
我該如何解決這個問題? ==爲了更好地幫助發佈SSCCE/MVCE,短,可運行,可編譯 – mKorbel
考慮使用['scrollRectToVisible'](http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent。 HTML#scrollRectToVisible(java.awt中。矩形))你想要滾動的組件 – MadProgrammer
@MadProgrammer如何獲得矩形? –