1

画像を編集できるシンプルなアプリを作りたいです。アプリのメインビューにはJSplitPane2つ含まれていJScrollPaneます。それぞれJScrollPaneにが含まれますJPanel。右JPanelはボタンなどがいくつかあり、左JPanelは私の描画エリアです。

これが私の問題です...

私が最初に作成したとき、私JPanelDrawingAreaは好みのサイズを設定することができました。サイズが表示のサイズよりも大きい場合JScrollPaneJScrollBarsデフォルトでは同じです)。しかし、画像を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()

私が間違っていることについて何か考えはありますか?

4

2 に答える 2

2

要するに、あなたはrevalidate()あなたのImageWorkerView(あなたが電話する場所repaint())に行く必要があります。これにより、コンポーネントとその親に「再レイアウト」が要求され、スクロールバーに必要な調整がトリガーされます。

于 2012-06-29T03:17:58.870 に答える
0

ご回答有難うございます!あなたの提案は私に考えさせました。実際に私が間違っていたのは、revalidate()直後に呼び出すrepaint() ため、実際にはメソッドのrevalidate()前に実行されます(デバッグ中にこれを見つけました)。これを行う適切な方法は次のとおりです。paintComponentImageWorkerView

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()スクロール バーを調整します。

于 2012-06-29T06:41:38.690 に答える