swing 使用Graphic2D 繪制圖片,要實(shí)現(xiàn)對(duì)圖片進(jìn)行縮放和自由拖動(dòng)。
1.以鼠標(biāo)所在的位置為中心,滾輪控制縮放
2.縮放后再支持鼠標(biāo)拖動(dòng)。
基本原理:
利用scale() 函數(shù)。進(jìn)行縮放。但是要注意的地方是,如果是在?public void paintComponent(Graphics g) 里面通過這個(gè)Graphics g 參數(shù)獲取graphic對(duì)象進(jìn)行繪制,scale不會(huì)影響下一次的繪制。
一:所以,我們可以自行創(chuàng)建一個(gè) “繪圖區(qū)”, 創(chuàng)建一個(gè)空的ImageBuffer, 然后獲取這個(gè)ImageBuffer的 Graphics,? 后續(xù)全部往這個(gè)ImageBuffer的 Graphics 繪制.
二:? 最后在frame的paintComponent把我們這個(gè) 繪圖區(qū)原樣展示出來即可。 即,frame的paintComponent只是固定將 繪圖區(qū)作為一個(gè)圖片繪制。
三:甚至可以創(chuàng)建多個(gè)ImageBuffer ,實(shí)現(xiàn)類似于ps多圖層的樣子,各個(gè)圖層獨(dú)立,paitComponent 匯總顯示圖層。
自己創(chuàng)建的ImageBuffer的 Graphics ,每次scale都是以上一次作為基礎(chǔ),累計(jì)的縮放。
利用transrate進(jìn)行移動(dòng),(移動(dòng)的是坐標(biāo)系)。 每次transrate都是以上一次作為基礎(chǔ),累計(jì)的平移。
來實(shí)現(xiàn)我們的關(guān)鍵代碼:
作為demo, 代碼盡量是一個(gè) main()到底:
swingDemo.java文章來源:http://www.zghlxwxcb.cn/news/detail-742206.html
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
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;
public class swingDemo {
public static void main(String args[]) {
new swingDemo();
}
public static Color BG_COLOR = new Color(128, 128, 128);
public swingDemo() {
JFrame mjf = new JFrame("圖片查看");
ImagePanle mImgeView = new ImagePanle();
mImgeView.setPreferredSize(new Dimension(500, 500));
mImgeView.setMinimumSize(new Dimension(500, 500));
mImgeView.setBackground(BG_COLOR);
JMenuBar jmb = new JMenuBar();
JMenu meSetting = new JMenu("文件");
JMenuItem mOpen = new JMenuItem("打開");
mOpen.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
BufferedImage curBufferedImg;
JFileChooser fileChooser = new JFileChooser();
fileChooser.setMultiSelectionEnabled(true);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setMultiSelectionEnabled(false);
int option = fileChooser.showOpenDialog(mjf);
if (option == JFileChooser.APPROVE_OPTION) {
try {
File file = fileChooser.getSelectedFile();
curBufferedImg = ImageIO.read(new File(file.getAbsolutePath()));
mImgeView.updateImage(curBufferedImg);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
});
meSetting.add(mOpen);
jmb.add(meSetting);
mjf.setJMenuBar(jmb);
mjf.add(mImgeView);
mjf.setMinimumSize(new Dimension(800, 600));
mjf.setVisible(true);
mjf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class ImagePanle extends JPanel {
BufferedImage mSrcBuffeImg = null;
private static final long serialVersionUID = 1L;
private double mScale = 1.0;
private static final boolean B_REAL_SIZE = true;
private double mCurX = 0;
private double mCurY = 0;
private double mStartX = 0;
private double mStartY = 0;
private double mTranslateX = 0;
private double mTranslateY = 0;
// 記錄最初原始坐標(biāo)系,用于清除背景
AffineTransform mOriginTransform;
BufferedImage mViewBufferImg;
Graphics2D mViewG2d;
void refreshView() {
clear_buffer(mViewG2d, mOriginTransform, mViewBufferImg);
mViewG2d.drawImage(mSrcBuffeImg, 0, 0, null);
repaint();
}
void clear_buffer(Graphics2D g2d, AffineTransform org, BufferedImage bufImg) {
// 將保存的測(cè)量數(shù)據(jù),重新在經(jīng)過變換后的坐標(biāo)系上進(jìn)行繪制
// 先恢復(fù)一下原始狀態(tài),保證清空的坐標(biāo)是全部,執(zhí)行清空,然后再切會(huì)來
AffineTransform temp = g2d.getTransform();
g2d.setTransform(org);
g2d.clearRect(0, 0, bufImg.getWidth(), bufImg.getHeight());
g2d.setTransform(temp);
}
public void updateImage(BufferedImage srcImage) {
mSrcBuffeImg = srcImage;
mViewBufferImg = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB);
System.out.println("create buff image");
mViewG2d = mViewBufferImg.createGraphics();
mViewG2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
mViewG2d.setBackground(BG_COLOR);
System.out.println("crate bufg2d");
mOriginTransform = mViewG2d.getTransform();
refreshView();
}
private Point internal_getImagePoint(double mouseX, double mouseY) {
// 不管是先平移后縮放還是先縮放后平移,都以 先減 再縮放的方式可以獲取正確
double rawTranslateX = mViewG2d.getTransform().getTranslateX();
double rawTranslateY = mViewG2d.getTransform().getTranslateY();
// 獲取當(dāng)前的 Scale Transform
double scaleX = mViewG2d.getTransform().getScaleX();
double scaleY = mViewG2d.getTransform().getScaleY();
// 不管是先平移后縮放還是先縮放后平移,都以 先減 再縮放的方式可以獲取正確
int imageX = (int) ((mouseX - rawTranslateX) / scaleX);
int imageY = (int) ((mouseY - rawTranslateY) / scaleY);
return new Point(imageX, imageY);
}
public ImagePanle() {
// 啟用雙緩存
setDoubleBuffered(true);
this.addMouseWheelListener((MouseWheelListener) new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (mViewG2d == null) {
return;
}
mCurX = e.getX();
mCurY = e.getY();
int notches = e.getWheelRotation();
if (notches < 0) {
// 滾輪向上,放大畫布
mScale = 1.1;
} else {
// 滾輪向下,縮小畫布
mScale = 0.9;
}
Point imagePoint = internal_getImagePoint(e.getX(), e.getY());
int imageX = imagePoint.x;
int imageY = imagePoint.y;
System.out.println("x:" + e.getX() + "y:" + e.getY() + ",imagex:" + imageX + "x" + imageY);
double tralateX = mScale * imageX - imageX;
double tralateY = mScale * imageY - imageY;
mViewG2d.scale(mScale, mScale);
mViewG2d.translate(-tralateX / mScale, -tralateY / mScale); // 圖片方大,就需要把坐標(biāo)往左移動(dòng),移動(dòng)的尺度是要考慮縮放的
// 先恢復(fù)一下原始狀態(tài),保證清空的坐標(biāo)是全部,執(zhí)行清空,然后再切會(huì)來
AffineTransform temp = mViewG2d.getTransform();
mViewG2d.setTransform(mOriginTransform);
mViewG2d.clearRect(0, 0, mViewBufferImg.getWidth(), mViewBufferImg.getHeight());
mViewG2d.setTransform(temp);
mViewG2d.drawImage(mSrcBuffeImg, 0, 0, null);
repaint(); // 重新繪制畫布
}
});
this.addMouseListener(new MouseListener() {
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("mouseReleased:" + e.getX() + "x" + e.getY());
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("mousePressed----:" + e.getX() + "x" + e.getY());
mStartX = e.getX();
mStartY = e.getY();
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
System.out.println("mouseClicked----:" + e.getX() + "x" + e.getY());
}
});
this.addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
if (mViewG2d == null) {
return;
}
mCurX = e.getX();
mCurY = e.getY();
System.out.println("mouseDragged:" + e.getX() + "x" + e.getY() + "trans:" + (mCurX - mStartX) + ":"
+ (mCurY - mStartY));
// 平移坐標(biāo),也是相對(duì)于變換后的坐標(biāo)系而言的,所以
double scaleX = mViewG2d.getTransform().getScaleX();
double scaleY = mViewG2d.getTransform().getScaleY();
// TODO mCurX - mStartX 太小,比如為2, 而scalX 比較大,比如為3 則移動(dòng)的時(shí)候回發(fā)生 (int)2/3 ==0; 不移動(dòng)。
// 解決方案,把移動(dòng) ,全部在原始坐標(biāo)系上做,也就是最后繪制緩沖區(qū)的時(shí)候,drawimage(transX,transY)
mTranslateX = (mCurX - mStartX) / scaleX;
mTranslateY = (mCurY - mStartY) / scaleY;
// 自身就是累計(jì)的
mViewG2d.translate(mTranslateX, mTranslateY);
mStartX = mCurX;
mStartY = mCurY;
System.out.println("mouseDragged: over+++");
// 先恢復(fù)一下原始狀態(tài),保證清空的坐標(biāo)是全部,執(zhí)行清空,然后再切會(huì)來
AffineTransform temp = mViewG2d.getTransform();
mViewG2d.setTransform(mOriginTransform);
mViewG2d.clearRect(0, 0, mViewBufferImg.getWidth(), mViewBufferImg.getHeight());
mViewG2d.setTransform(temp);
mViewG2d.drawImage(mSrcBuffeImg, 0, 0, null);
repaint();
}
});
}
public void reset_scale() {
// 恢復(fù)到1.0 縮放,0,0 左上角對(duì)齊
mCurX = 0;
mCurY = 0;
mScale = 1.0;
mViewG2d.setTransform(mOriginTransform);
mViewG2d.clearRect(0, 0, mViewBufferImg.getWidth(), mViewBufferImg.getHeight());
mViewG2d.drawImage(mSrcBuffeImg, 0, 0, null);
repaint(); // 重新繪制畫布
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (mViewBufferImg == null) {
return;
}
// 如果有多個(gè)“圖層”要注意圖層的順序
Graphics2D g2d = ((Graphics2D) g);
g2d.drawImage(mViewBufferImg, 0, 0, null);
System.out.println("draw-----------:" + getWidth() + "x" + getHeight());
}
}
}
?文章來源地址http://www.zghlxwxcb.cn/news/detail-742206.html
到了這里,關(guān)于《java 桌面軟件開發(fā)》swing 以鼠標(biāo)為中心放大縮小移動(dòng)圖片的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!