JScrollPane 不会在 JSplitPane 上更新 JScrollBar



我想创建能够编辑图像的简单应用程序。应用程序的主视图包含带有两个JScrollPaneJSplitPane。每个JScrollPane都包含JPanel .右边JPanel有几个按钮等,左边JPanel是我的绘图区域。

这是我的问题...

当我第一次创建JPanelDrawingArea时,我可以设置首选大小。如果大小大于 JScrollPane 的大小,则显示JScrollBars(默认情况下相等)。但是当我将图像加载到JPanelDrawingArea滚动条不会更新时。尽管我设置了新的首选大小JPanelDrawingArea(大于JScrollPane的大小),但除非我手动更改JSplitPanes分隔线位置,否则滚动条不会更新。

这是我JSplitPane自定义类:

public class DrawingPaneView extends JSplitPane{
private DrawingWorkMode drawingWorkMode;
private ImageWorkerView imageWorker;
JScrollPane workScrollPane;
JScrollPane pictureScrollPane;
private DrawingPaneController controller;
private Dimension minimumSize = new Dimension(100, 200);
private JPanel imagePanel;

public DrawingPaneView() {
    setPreferredSize(new Dimension(ConfigClass.APP_WIDTH,ConfigClass.DRAWING_PANE_HEIGHT));
    controller = new DrawingPaneController(this); 
    //Panel
    drawingWorkMode = new DrawingWorkMode();
    workScrollPane = new JScrollPane(drawingWorkMode);
    //Image
    imageWorker = new ImageWorkerView();
    pictureScrollPane = new JScrollPane(imageWorker);

    workScrollPane.setMinimumSize(minimumSize);
    pictureScrollPane.setMinimumSize(minimumSize);

    //addJPanels
    this.setOrientation(JSplitPane.HORIZONTAL_SPLIT);
    this.setRightComponent(workScrollPane);
    this.setLeftComponent(pictureScrollPane);
    //addLeftPanelWithJButtonOnly
    imagePanel = new ImagePanelView();
    pictureScrollPane.setRowHeaderView(imagePanel);
    this.setDividerLocation(ConfigClass.DRAWING_PANE_WIDTH);
    this.setOneTouchExpandable(true);
}
//Change mode
public void changeMode(String mode){
    drawingWorkMode.changeMode(mode);
}      
}

还有我的自定义JPanel执行绘图:

public class ImageWorkerView extends JPanel {
private BufferedImage img;
private ImageWorkerController controller;
private int defaultBounds = 50;
private double scale=1.0;
int imgW;
int imgH;
public ImageWorkerView() {
    //setLayout(new BorderLayout(0, 0));
    controller = new ImageWorkerController(this);
}

public void setScale(double scale) {
    this.scale = scale;
}
public void setImage(File image) {
    try {
        img = ImageIO.read(image);
        if (img.getType() != BufferedImage.TYPE_INT_RGB) {
            BufferedImage img2 =
                new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB);
            Graphics big = img2.getGraphics();
            big.drawImage(img, 0, 0, null);
            img = img2;
        }
    } catch (IOException e) {
        System.out.println("Image could not be read");
    }
}
private void adjustPreferredSize(Boolean defaultSize){
    if(defaultSize){
        //Calculate the proper size of drawing area
        imgW = ConfigClass.DRAWING_PANE_WIDTH - ImagePanelView.PREFERRED_WIDTH-10;
        imgH = ConfigClass.DRAWING_PANE_HEIGHT-50;
        setPreferredSize(new Dimension(imgW,imgH));
        controller.setWindowHeight(imgH);
    }
    else{
        imgW = (int)(img.getWidth() * scale + (defaultBounds*2));
        imgH = (int)(img.getHeight() * scale + (defaultBounds*2));
        setPreferredSize(new Dimension(imgW,imgH));
        controller.setWindowHeight(imgH);
    }   
}
@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    if(img!=null){
        if(scale!=1.0){
            AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
            AffineTransformOp aop =
                new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC);
            g2.drawImage(img, aop, defaultBounds, defaultBounds);
        }
        else
            g2.drawImage(img, defaultBounds, defaultBounds, null);
        adjustPreferredSize(false);
    }
    else{
        adjustPreferredSize(true);
    }

}
}

以及我如何加载图像:

public class ImageWorkerController {
ImageWorkerView view;
ImageModel model;

public ImageWorkerController(ImageWorkerView workerView) {
    this.view = workerView;
    this.model = ApplicationContext.getObject(ImageModel.class);
    //Load image
    ApplicationContext.getObject(Context.class).addPropertyChangeListener(new PropertyChangeListener() {
        public void propertyChange(PropertyChangeEvent evt) {
            if(Context.IMAGE_LOADED.equals(evt.getPropertyName())){
                view.setImage((File) evt.getNewValue());
                view.repaint();
            }
        }
    });
public void setWindowHeight(int h){
    model.setDrawingWindowHeight(h);
}

}

如您所见,adjustPreferredSize()方法,当它第一次被调用时,它设置preferredSize大于JScrollPaneJScrollBars出现。但是当它再次被调用时,它什么也不做。

有趣的是,当我手动更改分隔线的位置JScrollBars显示时,在下面的屏幕上您有一个示例:

http://s17.postimage.org/e1nkja3zx/liliebead.jpg

所以有某种事件,使JScrollPane更新?我尝试了几种方法:updateUI()repaint()revalidate()。他们都没有工作。

知道我做错了什么吗?

简而言之,您需要revalidate()您的ImageWorkerView(就在您调用repaint()的地方)。这将要求组件及其父组件"重新布局",进而触发滚动条的必要调整。

感谢您的回答!你的建议让我思考。实际上我做错的是repaint()后立即调用revalidate(),所以实际上revalidate()ImageWorkerView paintComponent方法之前执行(我在调试过程中发现了这一点)。正确的方法是:

ApplicationContext.getObject(Context.class).addPropertyChangeListener(new PropertyChangeListener() {
        public void propertyChange(PropertyChangeEvent evt) {
            if(Context.IMAGE_LOADED.equals(evt.getPropertyName())){
                view.setImage((File) evt.getNewValue());
                //view.repaint();
                view.paintImmediately(new Rectangle(1, 1));
                view.revalidate();
            }
        }
    });

所以现在paintComponent设置首选大小,然后revalidate()调整滚动条。

相关内容

  • 没有找到相关文章