mt_MinF 2014-03-30 01:12 采纳率: 50%
浏览 2955
已采纳

我用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 2014-04-12 10: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();// 重绘
    
    }
    

    }

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大