2012-06-28 58 views
1

我想創建一個簡單的應用程序,可以編輯圖像。應用程序主視圖包含JSplitPane兩個JScrollPane。每個JScrollPane包含JPanel。右邊的JPanel有幾個按鈕等,左邊的JPanel是我的繪圖區。JScrollPane不更新JSplitPane上的JScrollBar

這裏是我的問題...

當我第一次創建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()方法,當它第一次被調用,並且它設置大於JScrollPanepreferredSize時,出現JScrollBars。但是當它再次被調用時,它什麼也不做。

有趣的是,當我手動更改分隔的位置JScrollBars顯示,在屏幕下面你有一個例子:

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

因此有某種事件,這使得JScrollPane更新?我嘗試了幾種方法:updateUI(),repaint(),revalidate()。他們都沒有工作。

任何想法我做錯了什麼?

回答

2

總之,你需要revalidate()你的ImageWorkerView(正確的地方,你叫repaint())。這將要求組件及其父級進行「重新佈局」,這又會觸發滾動條的必要調整。

0

感謝您的回答!你的建議讓我想到了。實際上我做錯了什麼是立即在repaint()之後,所以其實revalidate()執行paintComponent方法ImageWorkerView(我在調試過程中發現了這一點)。要做到這一點,正確的方法是:

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()調整滾動條。