我正在使用以下代码将图像添加到JScrollPane内部的JPanel中。我希望滚动窗格滚动到底部,但它似乎没有意识到图像已经添加,直到一段时间后,即使我在SwingUtilities包装器中调用它。
private void addImage(final String image){
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
imagePanel.addImage(image);
final JScrollBar vScroll = imageScrollPane.getVerticalScrollBar();
vScroll.setValue(vScroll.getMaximum());
}
});
}
imagePanel中的addImage代码如下所示:
public void addImage(String image){
System.out.println("Pre-height: " + getHeight());
add(createImageLabel(image));
System.out.println("After-height: " + getHeight());
revalidate();
System.out.println("Revalidate-height: " + getHeight());
}
看起来这会产生以下结果,例如:
Pre-height: 690
After-height: 690
Revalidate-height: 690
如果我在通话结束后进入循环状态,则实际更改高度似乎需要大约200毫秒。
我在这里的代码总是在滚动时结束1张图片。滚动到底部的最佳方式是什么,以至于我实际知道底部在哪里?我对Swing约定只有一点熟悉,但我认为,因为一切都发生在SwingUtilities调用中,它会知道它在做什么。
完整可执行代码演示此问题的示例:
package com.foo.bar
import java.awt.Dimension;
import java.awt.Image;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
public class ScrollImageExampleFrame extends JFrame{
private ScrollImageExamplePanel siePanel;
public ScrollImageExampleFrame(){
setSize(1024, 768);
siePanel = new ScrollImageExamplePanel();
getContentPane().add(siePanel);
}
class ScrollImageExamplePanel extends JPanel {
ImageViewExamplePanel imagePanel = new ImageViewExamplePanel();
JScrollPane imageScrollPane = new JScrollPane(imagePanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
public ScrollImageExamplePanel(){
setLayout(new MigLayout("nogrid"));
imageScrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(30, 0));
add(imageScrollPane, "east, width 300!, height 100%");
}
private void addImageOuter(final String image){
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
imagePanel.addImageInner(image);
imagePanel.revalidate();
final JScrollBar vScroll = imageScrollPane.getVerticalScrollBar();
vScroll.setValue(vScroll.getMaximum());
}
});
}
}
class ImageViewExamplePanel extends JPanel {
public ImageViewExamplePanel() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
}
public void addImageInner(String image){
URL imageUrl = ImageViewExamplePanel.class.getResource("/com/foo/bar/" + image);
ImageIcon ii = resizeImage(imageUrl, 360, 270);
JLabel label = new JLabel();
label.setIcon(ii);
add(label);
revalidate();
}
private ImageIcon resizeImage(URL url, int x, int y){
Image image = null;
try{
image = ImageIO.read(url);
Image newImage = image.getScaledInstance(x, y, Image.SCALE_SMOOTH);
return new ImageIcon(newImage);
} catch (IOException ioe){
ioe.printStackTrace();
return null;
}
}
}
public static void main(String[] args) throws InterruptedException {
ScrollImageExampleFrame frame = new ScrollImageExampleFrame();
frame.setVisible(true);
frame.siePanel.addImageOuter("foo.png");
Thread.sleep(1000);
frame.siePanel.addImageOuter("foo.png");
Thread.sleep(1000);
frame.siePanel.addImageOuter("foo.png");
Thread.sleep(1000);
frame.siePanel.addImageOuter("foo.png");
}
}
答案 0 :(得分:1)
为此目的使用下一个技巧:
private void addImage(final String image){
imagePanel.addImage(image);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JScrollBar vScroll = imageScrollPane.getVerticalScrollBar();
vScroll.setValue(vScroll.getMaximum());
}
});
}
在这种情况下,将添加,验证和绘制所有组件,然后在invokeLater
中,您可以更改JScrollBar
的位置。它可以帮助你。
答案 1 :(得分:0)
@ alex2410确定了一个解决方案 - 通过在包含的JFrame上调用revalidate(),我需要时正确计算了我的组件大小。我能够通过替换addImageOuter方法来修复我的示例代码,如下所示:
private void addImageOuter(final String image){
final JFrame frame = (JFrame) SwingUtilities.getWindowAncestor(this);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
imagePanel.addImageInner(image);
frame.revalidate();
final JScrollBar vScroll = imageScrollPane.getVerticalScrollBar();
vScroll.setValue(vScroll.getMaximum());
}
});
}
答案 2 :(得分:-1)
也许试试这个......
imagePanel.updateUI();