【问题标题】:How do I display an Image in Java Swing MVC architecture?如何在 Java Swing MVC 架构中显示图像?
【发布时间】:2020-12-07 04:43:32
【问题描述】:

在我的 java 应用程序中,我的目标是使用 MVC 架构显示或输出图像。我的 java 应用程序由 imagecontroller(main)、imageview 和 image model 组成。我目前能够选择图像,编译器会确认从 c: 驱动器中选择图像的位置,但它不会输出或显示图像。下面是我的代码的副本:

package imagecontroller;

import javax.swing.SwingUtilities;
import java.io.File;

    public class ImageController {
    
    private final ImageModel model;
    private final ImageView view; 

public ImageController () {
    this.view = new ImageView(this);
    this.model = new ImageModel(this.view);

public static void launch () {
    new ImageController();

}
    public static void main(String[] args) {
    SwingUtilities.invokeLater(ImageController::launch);   
    } 
}   

package imagecontroller;

import java.awt.Dimension;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.filechooser.FileNameExtensionFilter;    

      public class ImageView extends JFrame{
       
     private final ImageController controller;
    
        public ImageView(ImageController controller) {
            this.controller = controller;
    
            JFileChooser Chooser = new JFileChooser();
            FileNameExtensionFilter filter = new FileNameExtensionFilter("JPG & PNG Images", "jpg", "png");
            Chooser.addChoosableFileFilter(filter);
            Chooser.setCurrentDirectory(new File(System.getProperty("user.home")));
            Chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            int result 

      

         Chooser.showOpenDialog(null);
            if (result == JFileChooser.APPROVE_OPTION) {
                Chooser.setAcceptAllFileFilterUsed(true);
                File selectedFile = Chooser.getSelectedFile();
                System.out.println("Selected file: " + selectedFile.getAbsolutePath());
    
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.setTitle("ImageAnnotator");
                frame.setVisible(true);
                frame.setSize(new Dimension (500,500));
        
        } 
        
        }
    }

package imagecontroller;


import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
    
    
        public class ImageModel extends JComponent  {    
            private final ImageView view;
            private BufferedImage image;
           
            public ImageModel(ImageView view) {
                this.view = view;
            }
            public void CustomComponent (File png) {
                BufferedImage image = null; 
                setPreferredSize(new Dimension(400, 400));
              try {
                    this.image = ImageIO.read(new File("640px-Pleiades_large.png"));
                } catch (IOException x) {
                    JOptionPane.showMessageDialog(null, "Not an ImageFile, Please Select an Image");
                }
            }
            @Override
             public void paintComponent(Graphics g){
                super.paintComponent(g);
                g = g.create();
                g.setColor(Color.WHITE);
                g.fillRect(0, 0, getWidth(), getHeight());
                int margin = 20;
                int w = (getWidth() - (2 * margin + 2)) / 2;
                int h = this.image.getHeight() * w / this.image.getWidth();
                g.drawImage(image, h, h, WIDTH, HEIGHT, view);
        
        }
        }

【问题讨论】:

  • 类名以大写字符开头。方法名称以小写字符开头。字段名称以小写字符开头。您的模型应该是一个普通的 Java 类,其中包含 BufferedImage 和 BufferedImage 的文件路径。您的视图将只包含用于显示 BufferedImage 的 Swing 组件代码。一个 JFrame 和一个绘图 JPanel 就足够了。您的控制器负责确定您的图像在文件系统上的位置并检索图像。

标签: java swing model-view-controller


【解决方案1】:

MVC模式之所以叫MVC模式,是因为顾名思义。换句话说,创建模型,然后是视图,然后是控制器。

这是我整理的图像显示 GUI。

那么,让我们从模型开始。对于图像查看器 GUI,模型非常简单。

public class ImageDisplayModel {
    
    private BufferedImage image;
    
    private File file;

    public BufferedImage getImage() {
        return image;
    }

    public void setImage(BufferedImage image) {
        this.image = image;
    }

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }
    
}

ImageDisplayModel 类是一个普通的 Java 类,它包含一个 BufferedImage 和一个 File 路径。通过保存File路径,下次用户选择图片时,目录将设置为与上一张图片相同。

ImageDisplayModel 类是一个普通的 getter/setter 类。

下一步是创建视图。

public class ImageDisplay implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new ImageDisplay());
    }
    
    private ImageDisplayModel model;
    
    private ImagePanel imagePanel;
    
    private JFrame frame;
    
    public ImageDisplay() {
        this.model = new ImageDisplayModel();
    }
    
    @Override
    public void run() {
        frame = new JFrame("Image Display");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(createMenuBar());
        
        imagePanel = new ImagePanel(model);
        frame.add(imagePanel, BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JMenuBar createMenuBar() {
        JMenuBar menubar = new JMenuBar();
        
        JMenu filemenu = new JMenu("File"); 
  
        JMenuItem openitem = new JMenuItem("Open...");
        openitem.addActionListener(new OpenFileListener(this, model));
        filemenu.add(openitem);
        
        menubar.add(filemenu);
        
        return menubar;
    }
    
    public void updateImagePanel(int width, int height) {
        imagePanel.setPreferredSize(width, height);
        imagePanel.repaint();
        frame.pack();
    }
    
    public JFrame getFrame() {
        return frame;
    }

}

我们通过调用SwingUtilities invokeLater 方法来启动应用程序。此方法确保在Event Dispatch Thread 上创建和执行 Swing 组件。

视图构造函数实例化应用程序模型。

JFrame 代码在 run 方法中。

JMenuBar 方法允许我们选择多个图像,一张接一张。

getFrame 方法允许最终的控制器类访问JFrame 实例。 updateImagePanel 方法允许最终的控制器类更新图像面板。

接下来,我们创建DrawingPanel 类。

public class ImagePanel extends JPanel {

    private static final long serialVersionUID = 1L;
    
    private ImageDisplayModel model;
    
    public ImagePanel(ImageDisplayModel model) {
        this.model = model;
        this.setPreferredSize(649, 480);
    }
    
    public void setPreferredSize(int width, int height) {
        this.setPreferredSize(new Dimension(width, height));
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        BufferedImage image = model.getImage();
        if (image != null) {
            g.drawImage(image, 0, 0, this);
        }
    }
    
}

简单明了。如果存在,我们绘制BufferedImage。我们还调整了JPanel 的大小,以使图像适合。

DrawingPanel 类需要的唯一信息是模型类。绘图面板将绘制图像。期间。

最后,我们创建控制器类。

public class OpenFileListener implements ActionListener {
    
    private ImageDisplay frame;
    
    private ImageDisplayModel model;

    public OpenFileListener(ImageDisplay frame, ImageDisplayModel model) {
        this.frame = frame;
        this.model = model;
    }

    @Override
    public void actionPerformed(ActionEvent event) {
        JFileChooser chooser = new JFileChooser();
        FileNameExtensionFilter filter = new FileNameExtensionFilter(
                "JPG & PNG Images", "jpg", "png");
        chooser.addChoosableFileFilter(filter);
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        
        File file = model.getFile();
        if (file != null) {
            chooser.setCurrentDirectory(file);            
        }
        
        int result = chooser.showOpenDialog(frame.getFrame());
        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = chooser.getSelectedFile();
            model.setFile(selectedFile);
            BufferedImage image;
            try {
                image = ImageIO.read(selectedFile);
                model.setImage(image);
                frame.updateImagePanel(image.getWidth(), 
                        image.getHeight());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
}

控制器类更新模型信息并指示视图重新绘制自己。控制器不关心视图内部。控制器只需要知道视图可以更新。

最后,这是完整的可运行代码。我将类设为内部类,因此我可以将此代码作为一个块发布。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;

public class ImageDisplay implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new ImageDisplay());
    }
    
    private ImageDisplayModel model;
    
    private ImagePanel imagePanel;
    
    private JFrame frame;
    
    public ImageDisplay() {
        this.model = new ImageDisplayModel();
    }
    
    @Override
    public void run() {
        frame = new JFrame("Image Display");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(createMenuBar());
        
        imagePanel = new ImagePanel(model);
        frame.add(imagePanel, BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JMenuBar createMenuBar() {
        JMenuBar menubar = new JMenuBar();
        
        JMenu filemenu = new JMenu("File"); 
  
        JMenuItem openitem = new JMenuItem("Open...");
        openitem.addActionListener(new OpenFileListener(this, model));
        filemenu.add(openitem);
        
        menubar.add(filemenu);
        
        return menubar;
    }
    
    public void updateImagePanel(int width, int height) {
        imagePanel.setPreferredSize(width, height);
        imagePanel.repaint();
        frame.pack();
    }
    
    public JFrame getFrame() {
        return frame;
    }
    
    public class ImagePanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        private ImageDisplayModel model;
        
        public ImagePanel(ImageDisplayModel model) {
            this.model = model;
            this.setPreferredSize(649, 480);
        }
        
        public void setPreferredSize(int width, int height) {
            this.setPreferredSize(new Dimension(width, height));
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            BufferedImage image = model.getImage();
            if (image != null) {
                g.drawImage(image, 0, 0, this);
            }
        }
        
    }
    
    public class OpenFileListener implements ActionListener {
        
        private ImageDisplay frame;
        
        private ImageDisplayModel model;

        public OpenFileListener(ImageDisplay frame, ImageDisplayModel model) {
            this.frame = frame;
            this.model = model;
        }

        @Override
        public void actionPerformed(ActionEvent event) {
            JFileChooser chooser = new JFileChooser();
            FileNameExtensionFilter filter = new FileNameExtensionFilter(
                    "JPG & PNG Images", "jpg", "png");
            chooser.addChoosableFileFilter(filter);
            chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            
            File file = model.getFile();
            if (file != null) {
                chooser.setCurrentDirectory(file);            
            }
            
            int result = chooser.showOpenDialog(frame.getFrame());
            if (result == JFileChooser.APPROVE_OPTION) {
                File selectedFile = chooser.getSelectedFile();
                model.setFile(selectedFile);
                BufferedImage image;
                try {
                    image = ImageIO.read(selectedFile);
                    model.setImage(image);
                    frame.updateImagePanel(image.getWidth(), 
                            image.getHeight());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        
    }
    
    public class ImageDisplayModel {
        
        private BufferedImage image;
        
        private File file;

        public BufferedImage getImage() {
            return image;
        }

        public void setImage(BufferedImage image) {
            this.image = image;
        }

        public File getFile() {
            return file;
        }

        public void setFile(File file) {
            this.file = file;
        }
        
    }

}

【讨论】:

  • 这个例子很好,具体到 OPs 问题 +1
  • 对我的答案添加了更新,以反映使用我的 MVC 类型应用程序解决 OPs 问题的方法。
【解决方案2】:

我真的觉得这很有趣,并想进一步探索它。从The MVC pattern and Swing(我建议您特别阅读accepted answer)获取指针,让我们尝试一下。

解释

要遵循的代码摘要(基于上述链接)

登录视图。视图只是您的 UI 组件,具有用于 LoginController 所需的任何组件的 getter 方法以及实现 view 使用的 PropertyChangeListener 来接收PropertyChangeEvents 可以被我们的LoginControllerLoginModel解雇

LoginController 控制器可以访问 viewmodel。控制器在 views 组件上设置必要的事件,并通过验证来自视图的输入来对它们做出反应,然后要求模型完成它的工作,并可能会改变它的状态。控制器接受您的 views 操作并解释它们。如果您点击一个按钮,控制器的工作就是弄清楚这意味着什么以及应该如何根据该操作操作 模型

控制器还可以通过将视图(实现PropertyChangeListener)订阅到其SwingPropertyChangeSupport 来请求视图进行更改。当 controller 接收到来自 view 的操作时,在这种情况下,按下 Login 按钮,它会验证来自 view 的输入> 并触发必要的验证错误(如果有)。然后它调用 model 进行实际验证。

LoginModel controller 调用模型上的方法,当其状态发生变化时通知 view .当 model 中的某些内容发生变化时,根据您采取的某些操作(例如单击按钮),模型会通过与 controller 相同的机制通知视图其状态已更改>.

视图也可以向模型询问状态。视图直接从模型中获取它显示的状态。例如,如果我们将 model 实例传递给已经将 authenticated 设置为 true 的视图,您将立即收到消息说您已登录(此处未演示,但需要将 model 传递给 views 构造函数,并在初始化 initView() 之后执行类似 onAuthenticatedPropertyChange(model.isAuthenticated()) 的操作。

一些额外的信息是 controllermodel 都实现了observer pattern(因为在视图中观察到 controllermodels 以便对它们做出反应) 控制器还通过SwingWorker在后台线程上执行所有模型,并且所有属性更改侦听器都在EDT上被触发

这是演示上述内容的代码:

TestApp.java

import javax.swing.SwingUtilities;

public class TestApp {

    public TestApp() {
        createAndShowGUI();

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(TestApp::new);
    }

    private void createAndShowGUI() {
        LoginModel model = new LoginModel();
        LoginView view = new LoginView();
        LoginController controller = new LoginController(view, model);
    }
}

LoginView.java:

import java.awt.Color;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;

public class LoginView implements PropertyChangeListener {

    private JFrame frame;
    private JPanel loginPanel;
    private JTextField usernameTextField;
    private JTextField passwordTextField;
    private JLabel errorLabel;
    private JButton loginButton;

    public LoginView() {
        initView();
    }

    private void initView() {
        frame = new JFrame("TestApp");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        loginPanel = createLoginPanel();

        frame.add(loginPanel);
        frame.pack();
        frame.setVisible(true);
    }

    private JPanel createLoginPanel() {
        JPanel panel = new JPanel();
        panel.setBorder(new EmptyBorder(20, 20, 20, 20));
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        JLabel usernameLabel = new JLabel("Username:");
        usernameLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        usernameTextField = new JTextField();
        usernameTextField.setAlignmentX(Component.CENTER_ALIGNMENT);
        usernameTextField.setColumns(20);
        JLabel passwordLabel = new JLabel("Password:");
        passwordLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        passwordTextField = new JTextField();
        passwordTextField.setAlignmentX(Component.CENTER_ALIGNMENT);
        passwordTextField.setColumns(20);
        loginButton = new JButton("Login");
        loginButton.setAlignmentX(Component.CENTER_ALIGNMENT);
        errorLabel = new JLabel();
        errorLabel.setForeground(Color.RED);
        errorLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        errorLabel.setVisible(false);
        panel.add(usernameLabel);
        panel.add(usernameTextField);
        panel.add(passwordLabel);
        panel.add(passwordTextField);
        panel.add(errorLabel);
        panel.add(loginButton);
        return panel;
    }

    public JButton getLoginButton() {
        return loginButton;
    }

    public JTextField getUsernameTextField() {
        return usernameTextField;
    }

    public JTextField getPasswordTextField() {
        return passwordTextField;
    }

    public JFrame getFrame() {
        return frame;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        String propertyName = evt.getPropertyName();
        Object newValue = evt.getNewValue();

        switch (propertyName) {
            case "authenticated":
                // authentication has finished lets do something
                onAuthenticatedPropertyChange((Boolean) newValue);
                break;
            case "authenticating":
                // lets disable the UI as we authenticate
                errorLabel.setVisible(false);
                disableLoginPanelComponents(true);
                break;
            case "usernameInvalid":
                showError((String) newValue);
                break;
            case "passwordInvalid":
                showError((String) newValue);
                break;

        }
    }

    private void onAuthenticatedPropertyChange(Boolean authenticated) {
        if (authenticated == true) {
            errorLabel.setVisible(false);
            JOptionPane.showMessageDialog(frame, "You are in!");
        } else {
            showError("Invalid username or password!");
        }

        // re-enable components after authentication regadless of fail or pass
        disableLoginPanelComponents(false);
    }

    private void showError(String error) {
        errorLabel.setText(error);
        errorLabel.setVisible(true);
    }

    private void disableLoginPanelComponents(boolean disable) {
        for (int i = 0; i < loginPanel.getComponentCount(); i++) {
            Component component = (Component) loginPanel.getComponent(i);
            if (component instanceof JTextField || component instanceof JButton) {
                ((JComponent) loginPanel.getComponent(i)).setEnabled(!disable);
            }
        }
    }

}

登录控制器:

import java.awt.event.ActionEvent;
import javax.swing.SwingWorker;
import javax.swing.event.SwingPropertyChangeSupport;

public class LoginController {

    private final SwingPropertyChangeSupport propertyChangeSupport;
    private final LoginView view;
    private final LoginModel model;

    public LoginController(LoginView view, LoginModel model) {
        this.view = view;
        this.model = model;
        propertyChangeSupport = new SwingPropertyChangeSupport(this, true);
        initController();
    }

    private void initController() {
        // make the view a listener of both the model and controller as both can send events which the view must react too
        model.addPropertyChangeListener(view);
        propertyChangeSupport.addPropertyChangeListener(view);

        view.getLoginButton().addActionListener((ActionEvent e) -> {

            // lets do some basic validation of username and password fields
            String username = view.getUsernameTextField().getText();
            String password = view.getPasswordTextField().getText();

            // validate user input before sending it to the model (this is the contorllers job - besdoes business rules i..e username doesnt exist etc)
            if (username.isEmpty()) {
                propertyChangeSupport.firePropertyChange("usernameInvalid", null, "Username cannot be empty!");
                return;
            }

            if (password.isEmpty()) {
                propertyChangeSupport.firePropertyChange("passwordInvalid", null, "Password cannot be empty!");
                return;
            }

            // call the model to login on a background thread as the model may query the db or hit an API etc
            new SwingWorker<Void, Void>() {
                @Override
                protected Void doInBackground() throws Exception {
                    model.login(username, password);
                    return null;
                }
            }.execute();
        });

    }
}

LoginModel.java:

import java.beans.PropertyChangeListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.SwingPropertyChangeSupport;

public class LoginModel {

    private final SwingPropertyChangeSupport propertyChangeSupport;
    private boolean authenticated;

    public LoginModel() {
        propertyChangeSupport = new SwingPropertyChangeSupport(this, true); // we pass in true to noifty observers on the Event Dispatch Thread
    }

    public void login(String username, String password) {
        
        propertyChangeSupport.firePropertyChange("authenticating", null, true);
        
        // lets simulate query a database or something for 3 seconds
        try {
            Thread.sleep(3000);
        } catch (InterruptedException ex) {
            Logger.getLogger(LoginModel.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        authenticated = username.equals("admin") && password.equals("password");
        propertyChangeSupport.firePropertyChange("authenticated", null, authenticated);
    }

    public void addPropertyChangeListener(PropertyChangeListener prop) {
        propertyChangeSupport.addPropertyChangeListener(prop);
    }
    
    public boolean isAuthenticated() {
        return authenticated;
    }
}

以上内容是通用的,并没有直接回答您的问题,而是为您提供了 Swing 中 MVC 模式的示例。

更新:

这是一个针对您的问题的示例

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
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.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.SwingPropertyChangeSupport;
import javax.swing.filechooser.FileNameExtensionFilter;

public class TestApp {

    public TestApp() {
        createAndShowGUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(TestApp::new);
    }

    private void createAndShowGUI() {
        DisplayImageModel model = new DisplayImageModel();
        DisplayImageView view = new DisplayImageView();
        DisplayImageController controller = new DisplayImageController(view, model);
    }

    class DisplayImageView implements PropertyChangeListener {

        private JFrame frame;
        private ImagePanel imagePanel;
        private JLabel imageLabel;
        private JButton pickImageButton;

        public DisplayImageView() {
            initView();
        }

        private void initView() {
            frame = new JFrame("TestApp");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JPanel panel = createImagePanel();

            frame.add(panel);
            frame.pack();
            frame.setVisible(true);
        }

        private JPanel createImagePanel() {
            JPanel panel = new JPanel();
            panel.setBorder(new EmptyBorder(20, 20, 20, 20));
            panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
            pickImageButton = new JButton("Pick an image");
            pickImageButton.setAlignmentX(Component.CENTER_ALIGNMENT);
            imagePanel = new ImagePanel();
            imagePanel.getPanel().setAlignmentX(Component.CENTER_ALIGNMENT);
            panel.add(imagePanel.getPanel());
            panel.add(pickImageButton);
            return panel;
        }

        public JButton getPickAnImageButton() {
            return pickImageButton;
        }

        public JLabel getImageLabel() {
            return imageLabel;
        }

        public JFrame getFrame() {
            return frame;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            String propertyName = evt.getPropertyName();
            Object newValue = evt.getNewValue();

            switch (propertyName) {
                case "image":
                    onImagePropertyChange((BufferedImage) newValue);
                    break;
            }
        }

        private void onImagePropertyChange(BufferedImage image) {
            imagePanel.setImage(image);
            frame.pack();
        }
    }

    class DisplayImageModel {

        private final SwingPropertyChangeSupport propertyChangeSupport;
        private BufferedImage image;

        public DisplayImageModel() {
            propertyChangeSupport = new SwingPropertyChangeSupport(this, true); // we pass in true to noifty observers on the Event Dispatch Thread
        }

        public void setImage(BufferedImage image) {
            this.image = image;
            propertyChangeSupport.firePropertyChange("image", null, image);
        }

        public void addPropertyChangeListener(PropertyChangeListener prop) {
            propertyChangeSupport.addPropertyChangeListener(prop);
        }

        public BufferedImage getImage() {
            return image;
        }
    }

    class DisplayImageController {

        private final SwingPropertyChangeSupport propertyChangeSupport;
        private final DisplayImageView view;
        private final DisplayImageModel model;

        public DisplayImageController(DisplayImageView view, DisplayImageModel model) {
            this.view = view;
            this.model = model;
            propertyChangeSupport = new SwingPropertyChangeSupport(this, true);
            initController();
        }

        private void initController() {
            // make the view a listener of both the model and controller as both can send events which the view must react too
            model.addPropertyChangeListener(view);
            propertyChangeSupport.addPropertyChangeListener(view);

            view.getPickAnImageButton().addActionListener((ActionEvent e) -> {
                JFileChooser chooser = new JFileChooser();
                FileNameExtensionFilter filter = new FileNameExtensionFilter(
                        "JPG & PNG Images", "jpg", "png");
                chooser.addChoosableFileFilter(filter);
                chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);

                int result = chooser.showOpenDialog(view.getFrame());
                if (result == JFileChooser.APPROVE_OPTION) {
                    File selectedFile = chooser.getSelectedFile();
                    BufferedImage image;
                    try {
                        image = ImageIO.read(selectedFile);
                        model.setImage(image);
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            });

        }
    }

    class ImagePanel {

        private final JPanel panel;
        private BufferedImage image;

        public ImagePanel() {
            this.panel = new JPanel() {
                @Override
                public Dimension getPreferredSize() {
                    if (image != null) {
                        return new Dimension(image.getWidth(), image.getHeight());
                    } else {
                        return new Dimension(200, 200);
                    }
                }

                @Override
                protected void paintComponent(Graphics g) {
                    super.paintComponent(g);
                    if (image != null) {
                        g.drawImage(image, 0, 0, this);
                    }
                }
            };
            panel.setBorder(new LineBorder(Color.GRAY, 1));
        }

        public void setImage(BufferedImage image) {
            this.image = image;
            panel.revalidate();
            panel.repaint();
        }

        public JPanel getPanel() {
            return panel;
        }
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 1970-01-01
    • 2014-12-18
    • 2015-05-16
    • 2017-05-20
    • 1970-01-01
    相关资源
    最近更新 更多