Java 自定义Swing组件和更新JScrollPane滚动条

Java 自定义Swing组件和更新JScrollPane滚动条,java,swing,custom-controls,Java,Swing,Custom Controls,我已经创建了一个自定义JComponent,它在paintComponent中绘制文本。将它放在滚动窗格中,我想在附加文本超出视口时自动显示scollbar。当我调整整个框架的大小时,滚动条会正确更新。但是我想用编程的方式来做。我尝试了几个#validate()和#invalidate()调用,但都没有成功 如何使用自定义组件作为客户端更新滚动窗格的滚动条 我创建了一个简单的可运行示例来说明我的意思: package swingscroll; 导入java.awt.Color; 导入java.a

我已经创建了一个自定义JComponent,它在paintComponent中绘制文本。将它放在滚动窗格中,我想在附加文本超出视口时自动显示scollbar。当我调整整个框架的大小时,滚动条会正确更新。但是我想用编程的方式来做。我尝试了几个#validate()和#invalidate()调用,但都没有成功

如何使用自定义组件作为客户端更新滚动窗格的滚动条

我创建了一个简单的可运行示例来说明我的意思:

package swingscroll;
导入java.awt.Color;
导入java.awt.Dimension;
导入java.util.logging.Level;
导入java.util.logging.Logger;
导入javax.swing.BorderFactory;
导入javax.swing.JComponent;
导入javax.swing.JFrame;
导入javax.swing.JScrollPane;
导入javax.swing.SwingUtilities;
公共级SwingScroll{
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
createAndShowGUI();
}
});
}
公共静态void createAndShowGUI(){
final JFrame=newjframe(SwingScroll.class.getSimpleName());
最终JComponent myComponent=新JComponent(){
私有维度优先选择大小;
@凌驾
public void setPreferredSize(维度preferredSize){
super.setPreferredSize(preferredSize);
this.preferredSize=preferredSize;
}
@凌驾
公共维度getPreferredSize(){
返回此参数。首选大小;
}
};
myComponent.setPreferredSize(新维度(380,50));
最终JScrollPane滚动窗格=新JScrollPane(myComponent);
frame.getContentPane().add(滚动窗格);
框架。设置尺寸(400100);
frame.setVisible(true);
//模拟myComponent中preferredSize的内部变化
新线程(newrunnable()){
@凌驾
公开募捐{
试一试{
睡眠(1000);
}捕获(中断异常例外){
Logger.getLogger(SwingScroll.class.getName()).log(Level.SEVERE,null,ex);
}
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
//这会触发滚动条,对吗?
myComponent.setPreferredSize(新维度(3801000));
//TODO插入代码以更新滚动条
}
});
}
}).start();
}
}
刚才看到你的评论:

在我的简单示例中添加重新验证和重新绘制时,滚动条仍然不会得到更新

WorkForme-虽然您的示例的问题是滚动条总是显示,所以看起来好像什么都没有发生。调整大小,这样一开始就没有垂直滚动条,然后更新到一定高度,以显示滚动条刚刚好

顺便说一句:我假设示例中的setPref只是用于演示,而不是用于生产代码

刚才看到你的评论:

在我的简单示例中添加重新验证和重新绘制时,滚动条仍然不会得到更新

WorkForme-虽然您的示例的问题是滚动条总是显示,所以看起来好像什么都没有发生。调整大小,这样一开始就没有垂直滚动条,然后更新到一定高度,以显示滚动条刚刚好


顺便说一句:我假设示例中的setPref只是为了演示,而不是在生产代码中。

“我创建了一个绘制文本的自定义JComponent…”自定义代码做了什么(除了失败之外)在
JLabel
JTextField
JTextArea
中做不到的事情,
JEditorPane
等?它允许拖动垂直标尺(文本右对齐)和或多或少的智能文本选择。我不确定不能使用JTextComponent或类似的工具来完成。用jlabel替换自定义组件并调用#setText操作正常。但我在#setText中看到的只是重新验证和重新喷漆。在我的简单示例中添加重新验证和重新绘制时,滚动条仍然不会得到更新。我不能按照代码来做其他必要的事情。JLabel如何更新滚动条?“我已经创建了一个自定义JComponent来绘制文本…”“自定义代码做了什么(除了失败)在
JLabel
JTextField
JTextArea
JEditorPane
中无法完成的事情?”它允许拖动垂直标尺(文本右对齐)以及或多或少的智能文本选择。我不确定不能使用JTextComponent或类似的工具来完成。用jlabel替换自定义组件并调用#setText操作正常。但我在#setText中看到的只是重新验证和重新喷漆。在我的简单示例中添加重新验证和重新绘制时,滚动条仍然不会得到更新。我不能按照代码来做其他必要的事情。JLabel如何更新滚动条?谢谢,它可以工作。是的,setPref只是演示而已。我现在在自定义组件的paintComponent()方法的末尾添加了revalidate(),解决了我的问题。不知怎的,我觉得我做错了。paintComponent渲染文本并缓存每个文本的矩形,以便getPreferredSize可以使用这些缓存的矩形来计算整个组件所需的高度。是否应该这样做?你的感觉是正确的-在绘画时永远不要改变组件的状态。相反,更改状态,然后根据需要调用repaint/revalidate。谢谢,它可以工作。是的,setPref只是演示而已。我现在在我的paintComponent()方法的末尾添加了revalidate()
// TODO insert code to update scrollbars
myComponent.revalidate();