2015-06-13 18 views
1

我已经使用Java Swing库实现了JFrame以可视化地图。我想在这个框架内实现缩放功能。 这是我的JFrame的代码:如何使用Java Swing库实现缩放面板

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); 
} 
} 

正如你可以在上面看到,该框架包含一个JPanel在JScrollPane和JSlider一个我使用变焦功能。 它遵循面板的代码..

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); 
} 

} 

..和滑块的一个:

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(); 
} 

} 

运行的代码,你只需要插入以下主要功能:

package main; 

import components.MyFrame; 

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

注意:有必要在源代码的同一路径中插入一个名为“earth1280x800.jpg”的图像包“images”。

通常会出现的问题是,当我使用缩放功能时,向右/向左和向上/向下滚动,有时图像不再包含在框架中。 我想要自动刷新滚动条,并且图像不会从边界出来。 我该怎么做?

感谢大家。

回答

1

我不是100%确定问题是什么,但我怀疑问题在于,当图像更改大小时,您并未更改图像JPanel的首选大小。如果是这样,那么解决方案是在显示JPanel的图像中覆盖getPreferredSize()并返回与缩放图像相匹配的尺寸。


编辑,不,你有点做到这一点,但你没有重新验证,也没有重新油漆JScrollPane的视口,这是你必须做的。

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 
    } 
} 
+0

这正是我所需要的。感谢澄清我所有的疑惑:) – Giordano

+0

@Giordano:不客气,并很高兴它帮助。请注意我是如何更改代码的,以便它使用公共可用的图像文件并且是一个单独的Java文件,以便任何人都可以运行它并对其进行测试,并保持不变。如果您有将来的类似帖子,请考虑这样做。祝你好运。 –

+0

嗨,很抱歉再次打扰你。我想问你,我必须做些什么才能放大图片的中间位置,而不是左侧的较高角落。我尝试了Graphics2D类的翻译()方法 ,但不幸的是面板不会从参考系统的原点转移。谢谢你的时间。 – Giordano