gpt4 book ai didi

java - 插入组件后使 JScrollPane 滚动到底部的正确方法是什么?

转载 作者:行者123 更新时间:2023-11-30 06:19:53 24 4
gpt4 key购买 nike

这个问题我已经看过好几次了,但在我看来,我找到的答案有点“糟糕”。

所以,基本上我有一个 JScrollPane 可以插入组件。每次插入组件时,我都希望 JScrollPane 滚动到底部。很简单。

现在,合乎逻辑的做法是向我要插入的容器添加一个监听器 (componentAdded)。

然后该监听器将简单地滚动到底部。但是这样是行不通的,因为此时组件高度还没有计算完,所以滚动失败。

我看到的答案通常涉及将滚动行放在一个(或什至几个链接的)“invokeLater”线程中。

在我看来,这就像一个“丑陋的黑客”。一旦完成所有高度计算,当然应该有更好的方法来实际移动滚动条,而不是仅仅将滚动条“延迟”一段未知的时间?

我还阅读了一些关于您应该使用 SwingWorker 的答案,但我从未真正理解这些内容。请赐教:)

这里有一些代码供您修改(阅读“make work”):

JScrollPane scrollPane = new JScrollPane();
add(scrollPane);

JPanel container = new JPanel();
scrollPane.setViewportView(container);

container.addContainerListener(new ContainerAdapter() {
public void componentAdded(ContainerEvent e) {
JScrollPane scrollPane = (JScrollPane) value.getParent().getParent();
JScrollBar scrollBar = scrollPane.getVerticalScrollBar();
scrollBar.setValue(scrollBar.getMaximum());
}
});

JPanel hugePanel = new JPanel();
hugePanel.setPreferredSize(new Dimension(10000, 10000);
container.add(hugePanel);

更新:添加了一些代码来测试理论。但是,它似乎工作正常,所以我想我的程序中的其他地方有问题:)

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ContainerAdapter;
import java.awt.event.ContainerEvent;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.LineBorder;


public class ScrollTest extends JFrame {

private static final long serialVersionUID = -8538440132657016395L;

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ScrollTest().setVisible(true);
}
});

}

public ScrollTest() {

UIManager.put("swing.boldMetal", Boolean.FALSE);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Scroll Test");
setSize(1000, 720);
setLocationRelativeTo(null);

JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
add(container);

//Create 3 scollpanels
final JScrollPane scrollPane1 = new JScrollPane();
scrollPane1.setBorder(new LineBorder(Color.RED, 2));
container.add(scrollPane1);

final JScrollPane scrollPane2 = new JScrollPane();
scrollPane2.setBorder(new LineBorder(Color.GREEN, 2));
container.add(scrollPane2);

final JScrollPane scrollPane3 = new JScrollPane();
scrollPane3.setBorder(new LineBorder(Color.BLUE, 2));
container.add(scrollPane3);

//Create a jpanel inside each scrollpanel
JPanel wrapper1 = new JPanel();
wrapper1.setLayout(new BoxLayout(wrapper1, BoxLayout.Y_AXIS));
scrollPane1.setViewportView(wrapper1);
wrapper1.addContainerListener(new ContainerAdapter() {
public void componentAdded(ContainerEvent e) {

SwingUtilities.invokeLater(new Runnable() {
public void run() {
scrollPane1.getVerticalScrollBar().setValue(scrollPane1.getVerticalScrollBar().getMaximum());
}
});

}
});

JPanel wrapper2 = new JPanel();
wrapper2.setLayout(new BoxLayout(wrapper2, BoxLayout.Y_AXIS));
scrollPane2.setViewportView(wrapper2);
wrapper2.addContainerListener(new ContainerAdapter() {
public void componentAdded(ContainerEvent e) {

SwingUtilities.invokeLater(new Runnable() {
public void run() {
scrollPane2.getVerticalScrollBar().setValue(scrollPane2.getVerticalScrollBar().getMaximum());
}
});

}
});

JPanel wrapper3 = new JPanel();
wrapper3.setLayout(new BoxLayout(wrapper3, BoxLayout.Y_AXIS));
scrollPane3.setViewportView(wrapper3);
wrapper3.addContainerListener(new ContainerAdapter() {
public void componentAdded(ContainerEvent e) {

SwingUtilities.invokeLater(new Runnable() {
public void run() {
scrollPane3.getVerticalScrollBar().setValue(scrollPane3.getVerticalScrollBar().getMaximum());
}
});

}
});

//Add come stuff into each wrapper
JPanel junk;
for(int x = 1; x <= 1000; x++) {
junk = new JPanel();
junk.setBorder(new LineBorder(Color.BLACK, 2));
junk.setPreferredSize(new Dimension(100, 40));
junk.setMaximumSize(junk.getPreferredSize());
wrapper1.add(junk);
}

for(int x = 1; x <= 1000; x++) {
junk = new JPanel();
junk.setBorder(new LineBorder(Color.BLACK, 2));
junk.setPreferredSize(new Dimension(100, 40));
junk.setMaximumSize(junk.getPreferredSize());
wrapper2.add(junk);
}

for(int x = 1; x <= 1000; x++) {
junk = new JPanel();
junk.setBorder(new LineBorder(Color.BLACK, 2));
junk.setPreferredSize(new Dimension(100, 40));
junk.setMaximumSize(junk.getPreferredSize());
wrapper3.add(junk);
}



}

}

最佳答案

正确的 - 即不浪费时间重新发明轮子 - 将组件滚动到任何你想要的地方的方法是这样的:

wrapper1.addContainerListener(new ContainerAdapter() {
@Override
public void componentAdded(final ContainerEvent e) {

SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JComponent comp = (JComponent) e.getChild();
Rectangle bounds = new Rectangle(comp.getBounds());
comp.scrollRectToVisible(bounds);
}
});

}
});

你正在避免的气味:

  • 不引用任何封闭的父级(如 scrollPane)
  • 不深入任何父级的内部结构(如滚动条)
  • 无需自定义模型

关于 invokeLater,引用它的 api 文档(粗体由我添加):

Causes doRun.run() to be executed asynchronously on the AWT event dispatching thread. This will happen after all pending AWT events have been processed

因此您可以相当确定在执行代码之前处理了内部结构。

关于java - 插入组件后使 JScrollPane 滚动到底部的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22529802/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com