Search code examples
javaimagedrawingjscrollpanejscrollbar

JScrollPane doesn't update JScrollBar on JSplitPane


I want to create simple app able to edit images. Main view of app contains JSplitPane with two JScrollPane. Each JScrollPane contains JPanel. The right JPanel has several buttons etc. and the left JPanel is my drawing area.

Here is my problem...

When I first created JPanelDrawingArea I could set preferred size. If the size is bigger than size of JScrollPane the JScrollBars show up (in default it is equal). But when I load image to JPanelDrawingArea scroll bars don't update. Despite the fact I set new preferred size of JPanelDrawingArea (bigger than size of JScrollPane) scroll bars don't update unless I manually change the JSplitPanes divider position.

Here is my JSplitPane custom class:

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);
}      
}

And there is my custom JPanel which perform drawing:

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);
    }



}
}

And how i load image:

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);
}

}

As you can see there is adjustPreferredSize() method, when it is first called, and it sets preferredSize bigger than JScrollPane, JScrollBars appear. But when it is called again it does nothing.

What is interesting, when I manually change divider's location JScrollBars show up, on screen below you have an example:

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

So there is some kind of event, which makes JScrollPane to update? I've tried several ways: updateUI(), repaint(), revalidate(). None of them worked.

Any ideas what I am doing wrong?


Solution

  • In short, you need to revalidate() your ImageWorkerView (right where you call repaint()). This will ask the component and its parent for "re-layout" and that in turn will trigger necessary adjustments for the scroll bars.