2 pcw550 pcw550 于 2014.03.30 09:12 提问

我用Java 写的一个简单截图小工具 但是出现一些在重截时出现bug 跪求大神

/**在这里贴上我注释满满的代码 求一语道破 求建议 求批评
没有贴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));
        }

    }

}

}

1个回答

wodeqiantu2010
wodeqiantu2010   2014.04.12 18:24
已采纳
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();// 重绘

}

}

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!