我想创建能够编辑图像的简单应用程序。应用的主视图包含JSplitPane
,其中包含两个JScrollPane
。每个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
大于JScrollPane
时,会出现JScrollBars
。但是当它被再次调用时它什么也没做。
有趣的是,当我手动更改分隔符的位置JScrollBars
时,在屏幕下方有一个示例:
http://s17.postimage.org/e1nkja3zx/liliebead.jpg
所以有某种事件会使JScrollPane
更新?我尝试了几种方法:updateUI()
,repaint()
,revalidate()
。他们都没有工作。
任何想法我做错了什么?
答案 0 :(得分:2)
简而言之,您需要revalidate()
ImageWorkerView
(您呼叫repaint()
的地方)。这将要求组件及其父组件“重新布局”,这反过来将触发滚动条的必要调整。
答案 1 :(得分:0)
感谢您的回答!你的建议让我思考。实际上我错误的是在revalidate()
之后立即调用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()
调整滚动条。