• 可以托拽的图片显示控件,JViewport 用法演示


    有人发贴问,一个 JPanel 里的图片太大了,超出了 JPanel 的大小范围,“我想拖动鼠标按住JPanel,拖动JPanel,把那些显示不了的线段“拖回来”。


    这是 JViewport 的典型应用场景,很多人会用 JScrollPane,但是对  JViewport 可能不熟悉,其实 JScrollPane 是整合了几个 JViewport,JScrollBar,以及特别设计的布局的一个控件,其中的 JViewport 单独拿出来也很好用,下面就是示例代码。


    为了显示图片,先做一个 panel,如下


    /*
     * Copyright 2013 (raistlic@gmail.com)
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.Insets;
    import javax.swing.JPanel;
    
    
    /**
     *
     * @author raistlic
     */
    public class JImagePanel extends JPanel {
      
      private static final Color GRID_1 = Color.GRAY.brighter();
      private static final Color GRID_2 = GRID_1.brighter();
      private static final int GRID_SIZE = 10;
      
      private Image image;
      
      public void setImage(Image image) {
        
        // although not checked, this method should be called with-in EDT.
        
        this.image = image;
        revalidate();
        repaint();
      }
      
      @Override
      public Dimension getPreferredSize() {
        
        if( image == null )
          return getMinimumSize();
        else {
          
          Insets i = getInsets();
          return new Dimension(
                  i.left + i.right + image.getWidth(this), 
                  i.top + i.bottom + image.getHeight(this));
        }
      }
      
      @Override
      protected void paintComponent(Graphics g) {
        
        super.paintComponent(g);
        
        int width = getWidth();
        int height = getHeight();
        
        g.setColor(GRID_1);
        g.fillRect(0, 0, width, height);
        
        g.setColor(GRID_2);
        for(int x=0, y=0, line=0; y<height; ) {
          
          g.fillRect(x, y, GRID_SIZE, GRID_SIZE);
          x += 2 * GRID_SIZE;
          if( x > width ) {
            
            y += GRID_SIZE;
            line = (line + 1) % 2;
            x = line * GRID_SIZE;
          }
        }
        
        Insets i = getInsets();
        g.drawImage(image, i.left, i.top, this);
      }
    }
    


    绘制代码中间有大段画格子(类似PS里面对透明部分的表现)的,如果不需要可以无视。


    然后做一个可以“鼠标托拽改变其中控件显示位置”的 JViewport:


    /*
     * Copyright 2013 (raistlic@gmail.com)
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.Point;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import java.awt.event.MouseMotionListener;
    import javax.swing.JViewport;
    
    /**
     *
     * @author raistlic
     */
    public class JDragableViewport extends JViewport {
      
      public JDragableViewport() {
        
        MouseDragHandler handler = this.new MouseDragHandler();
        addMouseListener(handler);
        addMouseMotionListener(handler);
      }
      
      @Override
      public void setViewPosition(Point p) {
        
        p.x = Math.max(0, p.x);
        p.y = Math.max(0, p.y);
        
        Component v = getView();
        if( v != null ) {
          
          Dimension d = v.getPreferredSize();
          Dimension size = getSize();
          p.x = Math.min(d.width - size.width, p.x);
          p.y = Math.min(d.height - size.height, p.y);
        }
        
        super.setViewPosition(p);
      }
      
      private class MouseDragHandler implements MouseListener, MouseMotionListener {
        
        private Point cursor = new Point();
        private Point view = new Point();
    
        @Override
        public void mouseClicked(MouseEvent e) {}
    
        @Override
        public void mouseReleased(MouseEvent e) {}
    
        @Override
        public void mouseEntered(MouseEvent e) {}
    
        @Override
        public void mouseExited(MouseEvent e) {}
    
        @Override
        public void mouseMoved(MouseEvent e) {}
    
        @Override
        public void mouseDragged(MouseEvent e) {
          
          Point p = e.getPoint();
          int dx = cursor.x - p.x;
          int dy = cursor.y - p.y;
          view.x += dx;
          view.y += dy;
          
          setViewPosition(view);
          
          cursor = p;
          view = getViewPosition();
        }
        
        @Override
        public void mousePressed(MouseEvent e) {
          
          cursor = e.getPoint();
          view = getViewPosition();
        }
      }
    }
    


    可以发现,它就是一个普通的 JViewport,加了两个鼠标相关的  listener。


    然后写一个小测试,用于打开图片文件并察看:


    /*
     * Copyright 2013 (raistlic@gmail.com)
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    import java.awt.BorderLayout;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.event.ActionEvent;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.Arrays;
    import javax.imageio.ImageIO;
    import javax.swing.AbstractAction;
    import javax.swing.Action;
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JFileChooser;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.JViewport;
    import javax.swing.SwingUtilities;
    import javax.swing.UIManager;
    import javax.swing.filechooser.FileFilter;
    
    /**
     *
     * @author raistlic
     */
    public class ImageViewDemo extends JPanel {
      
      public static void main(String[] args) {
        
        SwingUtilities.invokeLater(new Runnable() {
    
          @Override
          public void run() {
            
            try {
              
              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
              
              JFrame f = new JFrame("Image View Demo");
              
              f.setContentPane(new ImageViewDemo());
              
              f.setSize(800, 600);
              f.setLocationRelativeTo(null);
              f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              f.setVisible(true);
            }
            catch (Exception e) {
              
              e.printStackTrace();
            }
          }
        });
      }
      
      private static final String LABEL_OPEN_FILE = "Open Image File";
      private static final Iterable<String> SUPPORTED_FILE_EXT = Arrays.asList(
              
              ".jpg", ".png"
      );
      
      private JImagePanel imagePanel;
      private Action openAction;
      private JTextField pathField;
      private JFileChooser fileChooser;
      
      ImageViewDemo() {
        
        super(new BorderLayout(5, 5));
        
        imagePanel = new JImagePanel();
        openAction = new OpenImageFileAction(LABEL_OPEN_FILE);
        pathField = new JTextField();
        pathField.setEditable(false);
        pathField.setOpaque(false);
        
        initLayout();
      }
      
      private void initLayout() {
        
        JViewport viewPort = new JDragableViewport();
        viewPort.setView(imagePanel);
        
        add(viewPort, BorderLayout.CENTER);
        
        JPanel control = new JPanel(new GridBagLayout());
        
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(5, 5, 5, 5);
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1.0;
        gbc.gridx = 0;
        gbc.gridy = 0;
        control.add(pathField, gbc);
        
        gbc.weightx = 0;
        gbc.fill = GridBagConstraints.NONE;
        gbc.gridx += 1;
        control.add(new JButton(openAction), gbc);
        
        control.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        add(control, BorderLayout.SOUTH);
        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
      }
      
      private JFileChooser getFileChooser() {
        
        if( fileChooser == null ) {
          
          fileChooser = new JFileChooser();
          fileChooser.setFileFilter(new FileFilter() {
    
            @Override
            public boolean accept(File f) {
              
              assert f != null;
              
              if( f.isDirectory() ) {
                
                return true;
              }
              else {
                
                String fname = f.getName().toLowerCase();
                for(String s : SUPPORTED_FILE_EXT)
                  if( fname.endsWith(s) )
                    return true;
                
                return false;
              }
            }
    
            @Override
            public String getDescription() {
              
              return "Image Files";
            }
          });
          fileChooser.setDialogTitle(LABEL_OPEN_FILE);
        }
        return fileChooser;
      }
      
      private class OpenImageFileAction extends AbstractAction {
        
        private OpenImageFileAction(String name) {
          
          super(name);
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
          
          JFileChooser jfc = getFileChooser();
          int openResult = jfc.showOpenDialog(ImageViewDemo.this);
          if( openResult == JFileChooser.APPROVE_OPTION ) {
            
            try {
              
              File file = jfc.getSelectedFile();
              BufferedImage image = ImageIO.read(file);
              imagePanel.setImage(image);
              pathField.setText(file.getAbsolutePath());
            }
            catch (IOException ex) {
              
              JOptionPane.showMessageDialog(ImageViewDemo.this, "Failed to open Image : " + ex.getMessage());
            }
          }
        }
      }
    }
    


    代码有些凌乱,作为演示用的小测试也将就了……

    下面是Win 7下的运行截图:




    鼠标可以在图片的任意位置开始托拽,来改变显示的区域。

  • 相关阅读:
    Selenium库的使用
    Win10 常用快捷键
    503.下一个更大元素 II
    456.132模式
    201.数字范围按位与
    78.子集
    299.猜数字游戏
    49.字母异位词分组
    36.有效的数独
    290.单词规律
  • 原文地址:https://www.cnblogs.com/bbsno1/p/3262784.html
Copyright © 2020-2023  润新知