Comment puis-je implémenter un panneau Zoom avec les bibliothèques Java Swing


J'ai implémenté un JFrame avec des bibliothèques Java Swing pour visualiser une carte. Je voudrais réaliser une fonction de zoom dans ce cadre. Ceci est le code de mon JFrame:

package components;

import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JScrollPane;




public class MyFrame extends JFrame {

private static final long serialVersionUID = 1L;
private Container contentPane;
public static final int startWidth = 1280;
public static final int startHeight = 800;
public static MyPanel EarthPanel;

public MyFrame(){
    initComponents();
}


public void initComponents(){
    contentPane = getContentPane();
    this.setTitle("TLE Graphic Propagator");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setSize(startWidth, startHeight);
    this.setLocation(0,0);
    this.setLayout(new BorderLayout());
    EarthPanel = new MyPanel(startWidth,startHeight);
    JScrollPane scroll = new JScrollPane(EarthPanel,     JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    MySlider slider = new MySlider();
    contentPane.add(scroll, BorderLayout.CENTER);
    contentPane.add(slider, BorderLayout.SOUTH);
}
}

Comme vous pouvez le voir ci-dessus, le cadre contient un JPanel dans un JScrollPane et un JSlider que j'utilise pour la fonction zoom. Il suit le code du panneau..

package components;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class MyPanel extends JPanel{

private static final long serialVersionUID = 1L;
private BufferedImage img;
private int width, height;
private String path = "images/earth1280x800.jpg";
private static final int UPDATE_RATE = 10;  //#volte al secondo


public MyPanel(int larghezzaFrame, int altezzaFrame){   

    width = larghezzaFrame;
    height = altezzaFrame;

    this.setPreferredSize(new Dimension(width, height));

    img = loadImage();
}


public BufferedImage loadImage() {
    BufferedImage bimg = null;
    BufferedImage ret = null;
    try {
        bimg = ImageIO.read(new File(path));
    } catch (Exception e) {
        e.printStackTrace();
    }
    ret = new BufferedImage(bimg.getWidth(), bimg.getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = ret.createGraphics();
    g.drawImage(bimg, 0, 0, null);
    g.dispose();

    return ret;
}

@Override
protected void paintComponent(Graphics g) {
    setOpaque(false);

    Graphics2D g2d = (Graphics2D)g;
    g2d.scale(MySlider.SCALE, MySlider.SCALE);
    g2d.drawImage(img, 0, 0, null); 
    super.paintComponent(g2d);
}

}

..et celui du curseur:

package components;

import java.awt.Dimension;

import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class MySlider extends JSlider implements ChangeListener{

private static final long serialVersionUID = 1L;
public static double SCALE = 1;

public MySlider(){
    super(JSlider.HORIZONTAL, 100, 400, 100);
    setMajorTickSpacing(50);  
    setMinorTickSpacing(10);  
    setPaintTicks(true);  
    setPaintLabels(true);  
    addChangeListener(this);   
}

@Override
public void stateChanged(ChangeEvent arg0) {
    int value = ((JSlider) arg0.getSource()).getValue();  
    SCALE = value/100.0; 
    MyFrame.EarthPanel.setPreferredSize(new Dimension((int)(MyFrame.startWidth * MySlider.SCALE),(int)(MyFrame.startHeight * MySlider.SCALE)));
    MyFrame.EarthPanel.repaint();
}

}

Pour exécuter le code, il vous suffit d'insérer la fonction principale suivante:

package main;

import components.MyFrame;

public class MainPersonalFrame {
public static void main(String[] args){
    MyFrame frame = new MyFrame();
    frame.setVisible(true);
}
}

Remarque: Ce sera nécessaire d'insérer un paquet " images "dans le même chemin du code source avec une image appelée" earth1280x800.jpg " dans ça.

Le problème qui ressort généralement est que lorsque j'utilise la fonction zoom, en faisant défiler vers la droite/la gauche et vers le haut/le bas, parfois l'image n'est plus contenue par le cadre. J'aimerais obtenir un rafraîchissement automatique des barres de défilement et que l'image ne sorte pas des bordures. Comment dois-je faire?

Merci à tous.

Author: Giordano, 2015-06-13

1 answers

Je ne suis pas sûr à 100% du problème, mais je soupçonne qu'un problème est que vous ne modifiez pas la taille préférée de votre image JPanel lorsque l'image change de taille. Si c'est le cas, une solution serait de remplacer getPreferredSize() dans l'image affichant JPanel et de renvoyer une dimension qui correspond à celle de l'image zoomée.


Edit, non, vous faites en quelque sorte cela, mais vous ne revalidez ni ne repeignez la fenêtre de JScrollPane, et c'est ce que vous devez faire.

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class MainPersonalFrame {
   public static void main(String[] args) {
      MyFrame frame = new MyFrame();
      frame.setVisible(true);
   }
}

class MyFrame extends JFrame {

   private static final long serialVersionUID = 1L;
   private Container contentPane;
   public static final int startWidth = 1280;
   public static final int startHeight = 800;

   // !! This should be private and not static
   private MyPanel earthPanel;

   // !! this should be a field
   private JScrollPane scroll;

   public MyFrame() {
      initComponents();
   }

   public void initComponents() {
      contentPane = getContentPane();
      this.setTitle("TLE Graphic Propagator");
      this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      // !! avoid setting sizes if possible
      this.setSize(startWidth, startHeight);
      this.setLocation(0, 0);
      this.setLayout(new BorderLayout());
      earthPanel = new MyPanel(startWidth, startHeight);

      // !! again, scroll is now a field
      scroll = new JScrollPane(earthPanel,
            JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
            JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
      MySlider slider = new MySlider(this);
      contentPane.add(scroll, BorderLayout.CENTER);
      contentPane.add(slider, BorderLayout.SOUTH);
   }

   // !! to avoid having classes directly manipulate other class's fields
   public void setEarthPanelSize(Dimension size) {
      earthPanel.setPreferredSize(size);
   }

   // !! allow other classes the ability to revalidate/repaint viewport
   public void revalidateViewport() {
      scroll.getViewport().revalidate();
      scroll.getViewport().repaint();
   }
}

class MyPanel extends JPanel {

   private static final long serialVersionUID = 1L;
   private BufferedImage img;
   private int width, height;

   // !! changes so that I can run your program
   // !! with an internet image
   // !! private String path = "images/earth1280x800.jpg";
   private String urlPath = "http://image.desk7.net/"
         + "Space%20Wallpapers/1422_1280x800.jpg";

   // !! private static final int UPDATE_RATE = 10; // !! never used

   public MyPanel(int larghezzaFrame, int altezzaFrame) {
      setOpaque(false); // !! this should be here
      width = larghezzaFrame;
      height = altezzaFrame;

      this.setPreferredSize(new Dimension(width, height));

      img = loadImage();
   }

   public BufferedImage loadImage() {
      BufferedImage bimg = null;
      BufferedImage ret = null;
      try {
         URL imgUrl = new URL(urlPath);
         // !! bimg = ImageIO.read(new File(path)); // !!
         bimg = ImageIO.read(imgUrl); // !! use image available to all
         // !! } catch (Exception e) {
         // e.printStackTrace();
      } catch (IOException e) {
         // !! use more specific exception
         e.printStackTrace();
      }
      ret = new BufferedImage(bimg.getWidth(), bimg.getHeight(),
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g = ret.createGraphics();
      g.drawImage(bimg, 0, 0, null);
      g.dispose();

      return ret;
   }

   @Override
   protected void paintComponent(Graphics g) {
      // !! this shouldn't be in paintComponent:
      // !! setOpaque(false); 

      Graphics2D g2d = (Graphics2D) g;
      g2d.scale(MySlider.SCALE, MySlider.SCALE);
      g2d.drawImage(img, 0, 0, null);
      super.paintComponent(g2d);
   }

}

class MySlider extends JSlider implements ChangeListener {

   private static final long serialVersionUID = 1L;
   public static double SCALE = 1;
   private MyFrame myFrame;

   public MySlider(MyFrame myFrame) {
      super(JSlider.HORIZONTAL, 100, 400, 100);
      this.myFrame = myFrame;
      setMajorTickSpacing(50);
      setMinorTickSpacing(10);
      setPaintTicks(true);
      setPaintLabels(true);
      addChangeListener(this);
   }

   @Override
   public void stateChanged(ChangeEvent arg0) {
      int value = ((JSlider) arg0.getSource()).getValue();
      SCALE = value / 100.0;
      int w = (int) (MyFrame.startWidth * MySlider.SCALE);
      int h = (int) (MyFrame.startHeight * MySlider.SCALE);
      Dimension size = new Dimension(w, h);
      myFrame.setEarthPanelSize(size); // !!
      myFrame.revalidateViewport(); // !!
      // !! MyFrame.earthPanel.repaint(); // No, don't do this
   }
}
 1
Author: Hovercraft Full Of Eels, 2015-06-13 19:33:13