/**在這裡貼上我注釋滿滿的代碼 求一語道破 求建議 求批評
沒有貼main 方法 隨便寫個main方法便可運行 */
`
package com.subimaga;
import java.awt.AWTException;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import com.sun.awt.AWTUtilities;
public class ScreenCapture extends JFrame implements MouseListener,
MouseMotionListener {
private BufferedImage bufferedImage = null;// 用來存放圖像
// 獲取屏幕的大小
private int width = Toolkit.getDefaultToolkit().getScreenSize().width;
private int height = Toolkit.getDefaultToolkit().getScreenSize().height;
private Point point = new Point(0, height); // 截圖的左上角
private Point point2 = new Point(0, 0);// 截圖右下角
private Point point3 = new Point(0, 0);// 用來處理point 與point2 的關系
// 是畫筆的透明度可控制
private AlphaComposite composite;
boolean isStarCut = false, isEndCut = false;// isStarCut 為開始選區
// isEndCut為截圖結束僅標記結束選區
public ScreenCapture() {
// 初始化窗口
this.InitScr();
}
private void InitScr() // 初始化
{
// 截取整個桌面作為窗口的背景
try {
bufferedImage = new Robot().createScreenCapture(new Rectangle(0, 0,
width, height));
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 去掉窗體結構
this.setUndecorated(true);
// 設置窗體大小
this.setSize(width, height);
// 設置畫筆的透明度
composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f);
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.setVisible(true);
this.setAlwaysOnTop(true);
repaint();
}
public void paint(Graphics g) {
// 配置截圖環境
BufferedImage buff = new BufferedImage(width, height,
BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2 = buff.createGraphics(); // 畫筆一
Graphics2D g3 = buff.createGraphics(); // 畫筆二 用兩個畫筆主要是因為需要不同的透明度
g2.drawImage(bufferedImage, 0, 0, null);
g2.setColor(Color.gray);
g2.setComposite(composite);
g2.fillRect(0, 0, width, height);
// 截圖的工作
if (isStarCut == true || isEndCut == true) { // 當
confirmArea(); // 處理坐標的方法
/**
* 我實現的原理是 在鋪了全屏截圖的窗口上鋪上一層灰色 透明為0.6 的實心矩形
* 根據用戶在窗口拖動的坐標再另外截取一張相對應的圖片鋪在上面
*/
g3.drawImage(bufferedImage.getSubimage(point.x, point.y, Math
.abs(point2.x - point.x), Math.abs(point2.y - point.y)),
point.x, point.y, null);
// 畫出一個綠色的空心矩形
g3.setColor(Color.green);
g3.drawRect(point.x, point.y, point2.x - point.x, point2.y
- point.y);
}
// 功能框的顯示
if (isEndCut == true) { // 當選區結束 才會繪出此框
action();
// 背景框
g2.fillRect(point3.x, point3.y + 5, 200, 30);
g2.setColor(Color.red);
// 完成
g3.drawRect(point3.x, point3.y + 5, 60, 30);
g3.setColor(Color.white);
g3.drawString("完成", point3.x + 20, point3.y + 25);
// 重截
g2.drawRect(point3.x + 70, point3.y + 5, 60, 30);
g2.drawString("重截", point3.x + 20 + 70, point3.y + 25);
// 退出
g2.drawRect(point3.x + 140, point3.y + 5, 60, 30);
g2.drawString("退出", point3.x + 20 + 140, point3.y + 25);
}
// 雙緩沖
g.drawImage(buff, 0, 0, this);
}
// 調節功能框位置的方法
public void action()
{
if (point2.x <= width - 200 && point2.y < height - 35) {
point3.x = point2.x;
point3.y = point2.y;
} else if (point.x >= 200 && point.y >= 35) {
point3.x = point.x;
point3.y = point.y - 50;
}
else if (point.x <= 200 && point2.x >= width - 200 && point.y >= 35) {
point3.x = point2.x - 205;
point3.y = point.y - 50;
} else if (point.y >= 35 && point2.y <= height - 35
&& point2.x >= width - 200) {
point3.x = point2.x;
point3.y = point2.y;
} else {
point3.x = point2.x - 205;
point3.y = point.y;
}
}
public void confirmArea() {
int temp;
point.x = point3.x; // 每一次開始都是和原點坐標比較
point.y = point3.y;
if (point2.x < point.x && point2.y < point.y) {
temp = point.x;
point.x = point2.x;
point2.x = temp;
temp = point.y;
point.y = point2.y;
point2.y = temp;
} else if (point2.x < point.x) {
temp = point.x;
point.x = point2.x;
point2.x = temp;
} else if (point2.y < point.y) {
temp = point.y;
point.y = point2.y;
point2.y = temp;
}
}
public void actoinCut(MouseEvent e) // 操作功能框的方法
{
if (isEndCut) {
// 完成
if (e.getX() >= point3.x && e.getX() <= point3.x + 60
&& e.getY() >= point3.y + 5 && e.getY() <= point3.y + 35) {
// //將截好的圖保存起來 原理是利用點下完成的“按鈕”時的坐標 即是最後一次決定的選區 對圖片進行截圖保存
try {
ImageIO.write(bufferedImage.getSubimage(point.x, point.y,
Math.abs(point2.x - point.x), Math.abs(point2.y
- point.y)), "jpg", new File("D:/D.jpg"));
} catch (IOException e1) {
// // TODO Auto-generated catch block
e1.printStackTrace();
}
;
System.exit(0); // 保存完畢馬上退出 這裡的保存夠工作有點簡單因為只是用來測試此截圖工具的bug
// 具體的功能先不實現先
}
// 重截
else if (e.getX() >= point3.x + 70
&& e.getX() <= point3.x + 70 + 60
&& e.getY() >= point3.y + 5 && e.getY() <= point3.y + 35) {
isEndCut = false; // 重新截圖 一切進入初始狀態 這個 重截一直搞不好 求大神
isStarCut = false;
// 點擊重截後鼠標依然保持手型樣式 所以要恢復默認
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
// 重繪
repaint();
}
// 退出
else if (e.getX() >= point3.x + 140
&& e.getX() <= point3.x + 140 + 60
&& e.getY() >= point3.y + 5 && e.getY() <= point3.y + 35) {
System.exit(0);
}
}
}
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
if (e.getButton() == MouseEvent.BUTTON3) // 雙擊 右鍵退出程序
{
if (e.getClickCount() == 2)
System.exit(0);
}
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
// 只有當初始化狀態才生效
if (isStarCut == false && isEndCut == false
&& e.getButton() == MouseEvent.BUTTON1) {
point.x = e.getX();
point.y = e.getY();
point3.x = e.getX();
point3.y = e.getY();
isStarCut = true;
}
// 進入重截的條件
else if (isEndCut) {
this.actoinCut(e);
}
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
// 截圖開始生效
if (isStarCut && isEndCut == false
&& e.getButton() == MouseEvent.BUTTON1) {
isEndCut = true; // 鼠標一放開馬上標記截圖結束
isStarCut = false; // 重新標記未開始選區狀態
repaint();// 重繪
}
}
@Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
// 拖動是改變矩形的坐標點
if (isStarCut || isEndCut) {
point2.x = e.getX();
point2.y = e.getY();
repaint();
}
}
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
// 在功能框上顯示手型狀態
if (isEndCut) {
// 完成
if (e.getX() >= point3.x && e.getX() <= point3.x + 60
&& e.getY() >= point3.y + 5 && e.getY() <= point3.y + 35) {
setCursor(new Cursor(Cursor.HAND_CURSOR));
}
// 重截
else if (e.getX() >= point3.x + 70
&& e.getX() <= point3.x + 70 + 60
&& e.getY() >= point3.y + 5 && e.getY() <= point3.y + 35) {
setCursor(new Cursor(Cursor.HAND_CURSOR));
}
// 退出
else if (e.getX() >= point3.x + 140
&& e.getX() <= point3.x + 140 + 60
&& e.getY() >= point3.y + 5 && e.getY() <= point3.y + 35) {
setCursor(new Cursor(Cursor.HAND_CURSOR));
} else {
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
}
}
}
int needWh = Math.abs(point2.x - point.x);
int needhg = Math.abs(point2.y - point.y);
if ((isStarCut || isEndCut) && needWh != 0 && needhg != 0) {
confirmArea(); // 處理坐標的方法
//將選擇的矩形圖片截出來
BufferedImage needScr = bufferedImage.getSubimage(point.x, point.y, needWh, needhg);
//截出來以後重新畫在jframe上,覆蓋原先背景圖片,以不同的透明度
g3.drawImage(needScr,point.x, point.y, null);
g3.setColor(Color.RED);
g3.drawRect(point.x, point.y, point2.x - point.x, point2.y - point.y);
}
確定所選區域為正方形才繼續截圖,這樣就不會報錯。
其實最根本的原因在這個地方,就是當你點擊完成、重截、退出的時候同樣會觸發mouseReleased事件,只要加一個標志就可以了:
boolean isRecapt = false; //標記是否是重新截圖
boolean isComplt = false; //標記是否完成截圖
boolean isExit = false; //標記是否是退出
public void actoinCut(MouseEvent e) // 操作功能框的方法
{
if (isEndCut) {
// 完成
if (e.getX() >= point3.x && e.getX() <= point3.x + 60
&& e.getY() >= point3.y + 5 && e.getY() <= point3.y + 35) {
isComplt = true;
//將截好的圖保存起來 原理是利用點下完成的“按鈕”時的坐標 即是最後一次決定的選區 對圖片進行截圖保存
try {
ImageIO.write(bufferedImage.getSubimage(point.x, point.y,
Math.abs(point2.x - point.x), Math.abs(point2.y
- point.y)), "jpg", new File("JAVA截圖_" + System.currentTimeMillis() + ".jpg"));
} catch (IOException e1) {
e1.printStackTrace();
};
System.exit(0);
}
// 重截
else if (e.getX() >= point3.x + 70
&& e.getX() <= point3.x + 70 + 60
&& e.getY() >= point3.y + 5 && e.getY() <= point3.y + 35) {
isEndCut = false; // 重新截圖 一切進入初始狀態 這個 重截一直搞不好 求大神
isStarCut = false;
isRecapt = true; //重新截圖置為true
// 點擊重截後鼠標依然保持手型樣式 所以要恢復默認
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
// 重繪
repaint();
}
// 退出
else if (e.getX() >= point3.x + 140
&& e.getX() <= point3.x + 140 + 60
&& e.getY() >= point3.y + 5 && e.getY() <= point3.y + 35) {
isExit = true;
System.exit(0);
}
}
}
public void mouseReleased(MouseEvent e) {
//當點擊完成、重截、退出以後,現有程序會將釋放鼠標(Release)的動作視為截圖動作的開始,這顯然是錯誤的,因此要過濾掉。
if (isRecapt || isComplt || isExit){
System.out.println("我return了 mouseReleased");
isRecapt = false;
repaint();// 重繪
return ;
}
// 截圖開始生效
if (isStarCut && isEndCut == false
&& e.getButton() == MouseEvent.BUTTON1) {
isEndCut = true; // 鼠標一放開馬上標記截圖結束
isStarCut = false; // 重新標記未開始選區狀態
repaint();// 重繪
}
}