JScrollPane和缩放图像

时间:2016-09-13 13:26:26

标签: java swing jscrollpane javax.imageio

我试图编写一个从JPanel扩展的简单类,它可以放大和缩小图像,然后在顶层使用JScrollPane,允许某人在缩放图像上来回滚动。我在使用JScrollPane部分时遇到了麻烦。

单击其中一个缩放按钮(无论是进入,退出还是重置)时,必须单击该按钮两次才能显示JScrollBars(或者在重置按钮的情况下,消失)。即使在他们继续放大或缩小后出现它们,也不会根据新的缩放级别进行更新。调整窗口大小可以解决这个问题,但我正在寻找更具体的解决方案。

ImagePanel代码:

package com.zephyr.graphics;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ImagePanel extends JPanel implements PropertyChangeListener{

    private File imageFile;

    private BufferedImage image;

    private double zoomMultiplier;

    public ImagePanel()
    {
        imageFile = null;

        image = null;

        zoomMultiplier = 1;
    }

    public ImagePanel(File imageFile)
    {
        this.imageFile = imageFile;

        try {
            image = ImageIO.read(imageFile);
        } catch (IOException e) {
            image = null;
        }

        zoomMultiplier = 1;
    }

    public void setImageFile(File imageFile)
    {
        this.imageFile = imageFile;

        if(imageFile == null)
        {
            image = null;
        }
        else
        {
            try {
                image = ImageIO.read(imageFile);
            } catch (IOException e) {
                image = null;
            }
        }

        zoomMultiplier = 1;

        this.revalidate();
        this.repaint();
    }

    public File getImageFile()
    {
        return imageFile;
    }

    public void paintComponent(Graphics g)
    {
        g.clearRect(0, 0, this.getWidth(), this.getHeight());

        if(image == null)
        {
            this.setPreferredSize(new Dimension(this.getParent().getWidth(), this.getParent().getHeight()));
            g.setColor(Color.black);
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
        }
        else
        {
            double preferredWidth = this.getParent().getWidth() * zoomMultiplier;
            double preferredHeight = this.getParent().getHeight() * zoomMultiplier;

            this.setPreferredSize(new Dimension((int)preferredWidth, (int)preferredHeight));

            Image scaled = image.getScaledInstance((int)preferredWidth, (int)preferredHeight, Image.SCALE_DEFAULT);

            g.drawImage(scaled, 0, 0, null);
        }
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if(evt.getPropertyName().equals("Image File"))
        {
            setImageFile((File)evt.getNewValue());
        }
        else if(evt.getPropertyName().equals("Zoom In"))
        {
            double additive = ((Number)evt.getNewValue()).doubleValue();

            zoomMultiplier += additive;

            this.revalidate();
            this.repaint();
        }
        else if(evt.getPropertyName().equals("Zoom Out"))
        {
            double subtractive = ((Number)evt.getNewValue()).doubleValue();

            zoomMultiplier -= subtractive;

            this.revalidate();
            this.repaint();
        }
        else if(evt.getPropertyName().equals("Zoom Reset"))
        {
            zoomMultiplier = 1;

            this.revalidate();
            this.repaint();
        }
    }
}

主类

package com.zephyr.graphics;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeSupport;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class Main {

    public static void main(String[] args)
    {
        PropertyChangeSupport pcs = new PropertyChangeSupport(Main.class);

        JFileChooser chooser = new JFileChooser(System.getProperty("user.home"));
        chooser.setDialogTitle("Select an image");
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

        File file = null;

        if(chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
        {
            file = chooser.getSelectedFile();
        }
        else
        {
            System.err.println("NO FILE WAS SELECTED OR THE WINDOW WAS CLOSED");
            return;
        }

        JFrame frame = new JFrame("ImagePanel Tester");
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        ImagePanel iPanel = new ImagePanel(file);
        pcs.addPropertyChangeListener(iPanel);

        JScrollPane iScroll = new JScrollPane(iPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        iScroll.setPreferredSize(new Dimension(1024, 768));

        JPanel controlPanel = new JPanel();
        controlPanel.setLayout(new FlowLayout(FlowLayout.CENTER));

        JButton zoomIn = new JButton("Zoom In");
        zoomIn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                 pcs.firePropertyChange("Zoom In", null, new Double(.25));
                 frame.revalidate();
                 frame.repaint();
            }

        });
        controlPanel.add(zoomIn);

        JButton zoomOut = new JButton("Zoom Out");
        zoomOut.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                pcs.firePropertyChange("Zoom Out", null, new Double(.25));
                frame.revalidate();
                frame.repaint();
            }

        });
        controlPanel.add(zoomOut);

        JButton zoomReset = new JButton("Zoom Reset");
        zoomReset.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                pcs.firePropertyChange("Zoom Reset", null, null);
                frame.revalidate();
                frame.repaint();
            }

        });
        controlPanel.add(zoomReset);

        JButton changeImage = new JButton("Change Image");
        changeImage.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if(chooser.showOpenDialog(frame) == JFileChooser.APPROVE_OPTION)
                {
                    File tempFile = chooser.getSelectedFile();
                    pcs.firePropertyChange("Image File", null, tempFile);
                    frame.revalidate();
                    frame.repaint();
                }
            }

        });
        controlPanel.add(changeImage);

        frame.add(iScroll, BorderLayout.CENTER);
        frame.add(controlPanel, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);
        frame.revalidate(); //Shouldn't really be necessary, but seems to be helping

    }
}

1 个答案:

答案 0 :(得分:0)

经过一番繁重的挖掘,Scrollable界面救了我。在此example之后实现此方法及其各自的方法以及从paintComponent中删除preferredSize引用可修复我遇到的问题。