java FX 截图仿照qq截图并保存本地

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34651026/article/details/88873443

功能:任意截图,保存至本地,确定截图,否定截图

效果图:

保存:

 

fx的资料也太少了,自己也查了资料 找到了一个Swing的然后将它改了改添加到项目里了,上代码

import com.melloware.jintellitype.HotkeyListener;
import com.melloware.jintellitype.JIntellitype;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinUser;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import static com.sun.jna.platform.win32.WinUser.*;

public class imageScreenshot implements HotkeyListener {
    HashMap<Integer, Rectangle> winLayer = null;
    static final int shotHotKey = 88;
    public volatile boolean enterBusy = false;//防止和全局热键冲突。
    private String lastPath = null;
    public volatile boolean shotBusy = false;//防止重复截图。
    public volatile boolean isProcess = false;//第一次拖拽完成后,需要进行处理,这时候需要重新利用click,drag和release函数。
    /**拖拽参数**/
    private static final int BREADTH = 7;//边界拉伸范围
    private static final int BREADTH2 = 14;//边界拉伸范围
    private  int dragType;
    private static final int DRAG_NONE = 0;
    private static final int DRAG_MOVE = 1;
    private static final int DRAG_UP = 2;
    private static final int DRAG_UPLEFT = 3;
    private static final int DRAG_UPRIGHT = 4;
    private static final int DRAG_LEFT = 5;
    private static final int DRAG_RIGHT = 6;
    private static final int DRAG_BOTTOM = 7;
    private static final int DRAG_BOTTOMLEFT = 8;
    private static final int DRAG_BOTTOMRIGHT = 9;
    private Cursor getNewCursor(){
        return Toolkit.getDefaultToolkit().createCustomCursor(new ImageIcon(imageScreenshot.class.getResource("cursor.png")).getImage(),new Point(0,0),"myCursor");
    }
    public void onHotKey(int key) {
        switch (key) {
            case shotHotKey:
                if(shotBusy) return;
                shotBusy = true;
                saveLayer();//保存窗口层次。
                registerESC();//注册窗体全局热键
                shotProcess();
                break;
            default:
                System.exit(0);
        }

    }
    /**屏幕窗体层次保存**/
    public void saveLayer() {
        User32 u32 = User32.INSTANCE;
        printAllNextWin(u32.GetWindow(u32.GetForegroundWindow(), new WinDef.DWORD(GW_HWNDFIRST)));
    }

    public HWND getNextWindow(HWND hWnd) {
        return User32.INSTANCE.GetWindow(hWnd, new DWORD(GW_HWNDNEXT));
    }

    public boolean CheckLegal(HWND hWnd, Rectangle rt) {
        WINDOWINFO winInfo = new WINDOWINFO();
        User32.INSTANCE.GetWindowInfo(hWnd, winInfo);
        int style = winInfo.dwStyle;
        if ((style & WS_VISIBLE) == 0) {
            return false;//去掉不可视窗口
        }
        if ((style & WS_DISABLED) != 0) {
            return false;//去掉disable窗口
        }
        if (rt.width < 10 || rt.height < 10) {
            return false;//去掉小不点窗口
        }
        if ((style & WS_MINIMIZE)!=0) {
            return false;//去掉最小化状态的窗口
        }
        if((rt.getWidth() == screenSize.getWidth()) && (rt.getHeight() == screenSize.getHeight())){
            return false;//去掉底层屏幕窗口
        }
        return true;
    }
    /**   遍历桌面所有窗体,如果是合法的就加入到winLayer        **/
    public void printAllNextWin(HWND h) {
        HashMap<Integer, Rectangle> layerInfo = new HashMap<>();//0是最高层
        HWND hWnd = h;
        RECT r = new RECT();
        int layerPos = 0;
        Rectangle rect;
        while ((hWnd = getNextWindow(hWnd)) != null) {
            User32.INSTANCE.GetWindowRect(hWnd, r);
            rect = r.toRectangle();
            if (!CheckLegal(hWnd, rect)) continue;
            layerInfo.put(layerPos++, rect);
        }
        winLayer = layerInfo;
    }

    AWTEventListener al;

    private void registerESC() {
        al = event -> {
            KeyEvent ke = (KeyEvent) event;
            if (ke.getID() == KeyEvent.KEY_PRESSED) {
                if (ke.getKeyCode() == KeyEvent.VK_ESCAPE) {
                    //System.out.println("当前AWT事件监听器数量"+ Toolkit.getDefaultToolkit().getAWTEventListeners().length);
                    clean();
                    unregisterESC();
                    jp.setDrag(false);
                } else if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
                    if(enterBusy){
                        return;
                    }
                    pastePic();
                }
            }
        };
        Toolkit.getDefaultToolkit().addAWTEventListener(al, AWTEvent.KEY_EVENT_MASK);
    }

    private void unregisterESC() {
        Toolkit.getDefaultToolkit().removeAWTEventListener(al);
    }

    JFrame jf;
    Cursor myCursor;
    myContentPane jp;
    BufferedImage bi;
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

    private void shotProcess() {
        jf = new JFrame();
        jf.setUndecorated(true);
        jf.setBounds(0, 0, screenSize.width, screenSize.height);
        jf.setAlwaysOnTop(true);
        jp = new myContentPane(this);
        jp.setOpaque(false);
        jp.setLayout(null);
        Robot rb = null;
        try {
            rb = new Robot();
        } catch (AWTException e) {
            e.printStackTrace();
        }
        bi = rb.createScreenCapture(new Rectangle(screenSize));
        drawMouse(bi);
        img = new ImageIcon(bi);
        mouseEvent e = new mouseEvent(this);
        jp.addMouseListener(e);
        jp.addMouseMotionListener(e);
        jf.add(jp);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);
        myCursor = getNewCursor();
        jf.setCursor(myCursor);//给系统设置彩色光标。
    }
    /**图像添加鼠标:http://blog.csdn.net/eguid_1/article/details/52973508 **/
    private void drawMouse(BufferedImage bi){
        Graphics2D g2d = (Graphics2D)bi.getGraphics();
        g2d.drawImage(bi,0,0,bi.getWidth(),bi.getHeight(),null);
        ImageIcon img = new ImageIcon("");
        Point mp = MouseInfo.getPointerInfo().getLocation();
        g2d.drawImage(img.getImage(),mp.x,mp.y,img.getIconWidth(),img.getIconHeight(),null);
        g2d.dispose();
    }
    ImageIcon img;

    private class myContentPane extends JPanel {
        imageScreenshot ek;

        public myContentPane(imageScreenshot ek) {
            this.ek = ek;
        }

        public volatile boolean moveFlag = false;

        public synchronized boolean isMove() {
            return moveFlag;
        }

        public synchronized void setMove(boolean f) {
            moveFlag = f;
        }

        public volatile boolean dragFlag = false;

        public synchronized boolean isDrag() {
            return dragFlag;
        }

        public synchronized void setDrag(boolean f) {
            dragFlag = f;
        }

        @Override
        protected void paintComponent(Graphics g) {
            /**
             * 设置透明度 https://wenku.baidu.com/view/d90f110d227916888486d7ee.html
             */
            if (img != null)
                g.drawImage(img.getImage(), 0, 0, getWidth(), getHeight(), this);
            AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
            Composite old = ((Graphics2D) g).getComposite();
            ((Graphics2D) g).setComposite(ac);
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, screenSize.width, screenSize.height);
            ((Graphics2D) g).setComposite(old);

            g.drawImage(img.getImage(), start.x, start.y, end.x, end.y, start.x, start.y, end.x, end.y, this);
            g.setColor(new Color(2, 169, 255));
            if (isMove()) {
                Stroke oldS = ((Graphics2D) g).getStroke();
                ((Graphics2D) g).setStroke(new BasicStroke(4.0f));
                g.drawRect(start.x, start.y, end.x - start.x, end.y - start.y);
                ((Graphics2D) g).setStroke(oldS);
                setMove(false);
            } else {
                drawBound(g);
            }
            super.paintComponent(g);
        }

        Point myStart = new Point(0, 0);

        public void correctMyStart() {
            if ((start.x <= end.x) && (start.y <= end.y)) {
                myStart.x = start.x;
                myStart.y = start.y;
            } else if ((start.x <= end.x) && (start.y > end.y)) {
                //右上角
                myStart.x = start.x;
                myStart.y = end.y;
            } else if ((start.x > end.x) && (start.y <= end.y)) {
                //左下角
                myStart.x = end.x;
                myStart.y = start.y;
            } else {
                myStart.x = end.x;
                myStart.y = end.y;
            }
        }

        int offset = 3;
        int[][] point;

        private void drawBound(Graphics g) {
            myStart = new Point(0, 0);
            /**纠正反方向错误**/
            correctMyStart();
            g.drawRect(myStart.x, myStart.y, Math.abs(end.x - start.x), Math.abs(end.y - start.y));
            point = new int[][]{{start.x, start.y}, {(start.x + end.x) / 2, start.y}, {end.x, start.y}, {end.x, (start.y + end.y) / 2}, {end.x, end.y}, {(start.x + end.x) / 2, end.y}, {start.x, end.y}, {start.x, (start.y + end.y) / 2}};
            for (int i = 0; i < point.length; i++)
                g.fillRect(point[i][0] - offset, point[i][1] - offset, 2 * offset, 2 * offset);
        }
    }

    Point start = new Point(0, 0), end = new Point(0, 0);
    Point prePos,startCopy,endCopy;

    /**
     * 根据矩形的start和end两点裁剪出要截取的图形。
     */
    private BufferedImage clipArea(){
        BufferedImage shotArea = new BufferedImage(end.x - start.x, end.y - start.y, BufferedImage.TYPE_INT_RGB);
        Graphics g = shotArea.getGraphics();
        g.drawImage(bi, 0, 0, end.x - start.x, end.y - start.y, start.x, start.y, end.x, end.y, null);
        return shotArea;
    }
    /**
     * 将图像复制到系统剪贴板上
     **/
    private void pastePic() {
        /**将图片复制到剪贴板,参考链接:http://blog.csdn.net/u010982856/article/details/44747029**/
        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new Images((new ImageIcon(clipArea())).getImage()), null);
        clean();
    }

    private void clean() {
        jf.dispose();
        shotBusy = false;
        isProcess = false;
        start = new Point(0, 0);
        end = new Point(0, 0);
    }

    private class mouseEvent extends MouseAdapter {
        imageScreenshot ss;

        public mouseEvent(imageScreenshot screenShot) {
            this.ss = screenShot;
        }
        private void typeSel(MouseEvent e){
            Point p = e.getPoint();
            if(new Rectangle(start.x-BREADTH,start.y-BREADTH,end.x-start.x+BREADTH2,end.y-start.y+BREADTH2).contains(p)){
                /**在区域内部**/
            }else{
                /**如果不在内部,就结束**/
                isProcess = false;
                pressPro(e);
            }
        }
        public void mousePressed(MouseEvent e) {
            if(isProcess){
                /**
                 * 在处理状态下press时,记录press的点,作为起点。
                 */
                prePos = e.getPoint();
                startCopy = new Point(start);
                endCopy = new Point(end);
                typeSel(e);
            }else{
                pressPro(e);
            }
        }
        private void pressPro(MouseEvent e){
            isSelExist();
            start = e.getPoint();
            end = new Point(start.x,start.y);
            ss.jp.setDrag(true);
            ss.jp.updateUI();
        }
        public void mouseReleased(MouseEvent e) {
            if(isProcess){
                jf.setCursor(myCursor);
                /**修正在反方向拖动时的区域修正及更新面板**/
                correctDir();
                reLocateSel();
                return;
            }else{
                releaseProcess(e);
            }
        }
        private void releaseProcess(MouseEvent e){
            /** 如果只有点击没有拖拽,就进行窗体检测。
             **/
            if (!isDrag) {
                Rectangle r;
                for (int i = 0; i < winLayer.size(); i++) {
                    r = winLayer.get(i);
                    if (r.contains(e.getPoint())) {
                        //System.out.println("当前在矩形"+i+"中");
                        start.x = r.getX() >= 0 ? (int) r.getX() : 0;
                        start.y = r.getY() >= 0 ? (int) r.getY() : 0;
                        end.x = start.x + (int) r.getWidth();
                        end.y = start.y + (int) r.getHeight();
                        ss.jp.updateUI();//这个必须要。
                        break;
                    }
                }
            }
            correctDir();
            isSelExist();
            createSel();
            isDrag = false;
            isProcess = true;
            /**
             * 进入处理状态,如果在指定区域内再次点击,就是拖拽拉伸。
             */
        }
        private void reLocateSel(){
            Point refP;
            //判断按钮会不会超出屏幕
            if ((end.y + 30) >= screenSize.getHeight()) {
                refP = new Point(end.x, start.y - 30);
            } else {
                refP = new Point(end.x, end.y);
            }
            selPanel.setBounds(refP.x-150,refP.y+10,150,20);
            selPanel.updateUI();
        }
        private void createSel() {
            Point refP;
            //判断按钮会不会超出屏幕,上下左右方位都应该判断。
            /***还不完善,左下角会挡住。***/
            if ((end.y + 30) >= screenSize.getHeight()) {
                refP = new Point(end.x, start.y - 30);
            } else {
                refP = new Point(end.x, end.y);
            }
            selPanel = new JPanel(null);
            selPanel.setBounds(refP.x-240,refP.y+10,240,20);
            ok = new JButton("Yes");
            ok.setBounds(160, 0, 80, 20);
            ok.addActionListener(e -> {
                pastePic();
                ss.jp.setDrag(false);
            });
            cancel = new JButton("No");
            cancel.setBounds(80, 0, 80, 20);
            cancel.addActionListener(e -> {
                clean();
                ss.jp.setDrag(false);
            });
            save = new JButton("Save");
            save.addActionListener(e->{savePic();});
            save.setBounds(0, 0, 80, 20);
            selPanel.add(ok);
            selPanel.add(cancel);
            selPanel.add(save);
            ss.jp.add(selPanel);
            ss.jp.updateUI();
        }
        private void savePic(){
            enterBusy = true;
            if(File.separator.equals("\\"))//判断是windows系统
                try {
                    UIManager.setLookAndFeel(com.sun.java.swing.plaf.windows.WindowsLookAndFeel.class.getName());
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            JFileChooser jfc = new JFileChooser(lastPath);
            jfc.setDialogTitle("Save");
            jfc.removeChoosableFileFilter(jfc.getAcceptAllFileFilter());//去除"所有文件"项
            jfc.addChoosableFileFilter(new FileNameExtensionFilter("PNG  (*.png)","png"));
            jfc.addChoosableFileFilter(new FileNameExtensionFilter("BMP  (*.bmp)","bmp"));
            jfc.addChoosableFileFilter(new FileNameExtensionFilter("JPEG  (*.jpg;*.jpeg)","jpg"));
            int retVal = jfc.showSaveDialog(jf);
            if(retVal == JFileChooser.APPROVE_OPTION){
                File f = jfc.getSelectedFile();
                lastPath = jfc.getCurrentDirectory().getAbsolutePath();
                //System.out.println("lastPath changes="+lastPath);
                FileNameExtensionFilter ff = (FileNameExtensionFilter)jfc.getFileFilter();//得到当前的文件过滤器
                String[] extendList = ff.getExtensions();
                String extendName = null; int i;
                //System.out.println("list length is "+extendList.length);
                for(i=0;i<extendList.length;i++){
                    /**如果f扩展名在扩展名列表中就break,否则自动加上,默认第一个**/
                    if(f.getName().endsWith(extendList[i])){
                        extendName = extendList[i];
                        break;
                    }
                }
                if(i == extendList.length){
                    extendName = extendList[0];
                    f = new File(f.getAbsolutePath()+"."+extendName);
                }
                //System.out.println("save as="+f.getName()+"  extension = "+extendName);
                try {
                    ImageIO.write(clipArea(),extendName,f);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(File.separator.equals("\\"))//判断是windows系统
                try {
                    UIManager.setLookAndFeel(javax.swing.plaf.metal.MetalLookAndFeel.class.getName());
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            clean();
            enterBusy = false;
        }
        private void isSelExist() {
            ss.jp.removeAll();
            ss.jp.updateUI();
        }
        JPanel selPanel;
        JButton ok = null, cancel = null, save = null;
        public volatile boolean isDrag = false;
        public void mouseDragged(MouseEvent e) {
            if(isProcess){
                /**
                 * 判断拖拽拉伸类型,然后处理。
                 */
                dragPro(e);
            }else{
                /**获取的新的拖拽点必须加工后才能送到绘图板。**/
                end = e.getPoint();
                ss.jp.updateUI();//这个必须要。
                isDrag = true;
            }
        }
        private void dragPro(MouseEvent e){
            Point curPos = e.getPoint();
            switch(dragType){
                case DRAG_MOVE:
                    start.x = startCopy.x+curPos.x- prePos.x;
                    start.y = startCopy.y+curPos.y-prePos.y;
                    end.x = endCopy.x+curPos.x- prePos.x;
                    end.y = endCopy.y+curPos.y-prePos.y;
                    break;
                case DRAG_UPLEFT:
                    /**  start更新为拖动点         **/
                    start = new Point(curPos);
                    break;
                case DRAG_UP:
                    /**   只需要更新start.y          **/
                    start.y = curPos.y;
                    break;
                case DRAG_UPRIGHT:
                    /** 只需要更新start.y和end.x**/
                    start.y = curPos.y;
                    end.x = curPos.x;
                    break;
                case DRAG_RIGHT:
                    end.x = curPos.x;
                    break;
                case DRAG_BOTTOMRIGHT:
                    end = new Point(curPos);
                    break;
                case DRAG_BOTTOM:
                    end.y = curPos.y;
                    break;
                case DRAG_BOTTOMLEFT:
                    start.x = curPos.x;
                    end.y = curPos.y;
                    break;
                case DRAG_LEFT:
                    start.x = curPos.x;
                    break;
                default:
            }
            reLocateSel();
            ss.jp.updateUI();
        }
        /**
         * 纠正方向使得start始终是矩形左上角,stop始终是矩形右下角。
         **/
        private void correctDir() {
            Point p;
            //一共四个方向。
            //右下角
            if ((start.x <= end.x) && (start.y <= end.y)) {
                return;
            } else if ((start.x <= end.x) && (start.y > end.y)) {
                //右上角
                p = new Point(start);
                start.y = end.y;
                end.y = p.y;
            } else if ((start.x > end.x) && (start.y <= end.y)) {
                //左下角
                p = new Point(end);
                end.y = start.y;
                start.y = p.y;
                swap();
            } else {
                swap();
            }
        }

        private void swap() {
            Point p = start;
            start = end;
            end = p;
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            /**鼠标移动自动判断当前哪个矩形中**/
            if(isProcess){
                Point p = e.getPoint();
                if(new Rectangle(start.x-BREADTH, start.y-BREADTH,BREADTH2,BREADTH2).contains(p)){
                    /**stretch upper-left**/
                    dragType = DRAG_UPLEFT;
                    jf.setCursor(new Cursor(Cursor.NW_RESIZE_CURSOR));
                }else if(new Rectangle(start.x+BREADTH, start.y-BREADTH,end.x-start.x-BREADTH2,BREADTH2).contains(p)){
                    /**stretch upper**/
                    dragType = DRAG_UP;
                    jf.setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
                }else if(new Rectangle(end.x-BREADTH, start.y-BREADTH,BREADTH2,BREADTH2).contains(p)){
                    /**stretch upper-right**/
                    dragType = DRAG_UPRIGHT;
                    jf.setCursor(new Cursor(Cursor.NE_RESIZE_CURSOR));
                }else if(new Rectangle(end.x-BREADTH, start.y+BREADTH,BREADTH2,end.y-start.y-BREADTH2).contains(p)){
                    /**stretch right**/
                    dragType = DRAG_RIGHT;
                    jf.setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
                }else if(new Rectangle(end.x-BREADTH, end.y-BREADTH,BREADTH2,BREADTH2).contains(p)){
                    /**stretch bottom-right**/
                    dragType = DRAG_BOTTOMRIGHT;
                    jf.setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
                }else if(new Rectangle(start.x+BREADTH, end.y-BREADTH,end.x-start.x-BREADTH2,BREADTH2).contains(p)){
                    /**stretch bottom**/
                    dragType = DRAG_BOTTOM;
                    jf.setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));
                }else if(new Rectangle(start.x-BREADTH, end.y-BREADTH,BREADTH2,BREADTH2).contains(p)){
                    /**stretch bottom-left**/
                    dragType = DRAG_BOTTOMLEFT;
                    jf.setCursor(new Cursor(Cursor.SW_RESIZE_CURSOR));
                }else if(new Rectangle(start.x-BREADTH, start.y+BREADTH,BREADTH2,end.y-start.y-BREADTH2).contains(p)){
                    /**stretch left**/
                    dragType = DRAG_LEFT;
                    jf.setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
                }else if(new Rectangle(start.x,start.y,end.x-start.x,end.y-start.y).contains(p)){
                    /**如果在矩形内部,那么就是拖动**/
                    dragType = DRAG_MOVE;
                    jf.setCursor(new Cursor(Cursor.MOVE_CURSOR));
                }else{
                    dragType = DRAG_NONE;
                    jf.setCursor(myCursor);
                }
                return;
            }
            if (ss.jp.isDrag()) {
                return;
            }
            Rectangle r;
            for (int i = 0; i < winLayer.size(); i++) {
                r = winLayer.get(i);
                if (r.contains(e.getPoint())) {
                    //System.out.println("当前在矩形"+i+"中");
                    start.x = r.getX() >= 0 ? (int) r.getX() : 0;
                    start.y = r.getY() >= 0 ? (int) r.getY() : 0;
                    end.x = start.x + (int) r.getWidth();
                    end.y = start.y + (int) r.getHeight();
                    ss.jp.setMove(true);
                    ss.jp.updateUI();//这个必须要。
                    return;//无须往下搜索。
                }
            }
        }
    }


    public class Images implements Transferable {
        private Image image; //得到图片或者图片流

        public Images(Image image) {
            this.image = image;
        }

        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[]{DataFlavor.imageFlavor};
        }

        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return DataFlavor.imageFlavor.equals(flavor);
        }

        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            if (!DataFlavor.imageFlavor.equals(flavor)) {
                throw new UnsupportedFlavorException(flavor);
            }
            return image;
        }
    }
}

调用:new imageScreenshot 对象然后调用onHotKey参数88

              

imageScreenshot is=new imageScreenshot();
is.onHotKey(88);

猜你喜欢

转载自blog.csdn.net/qq_34651026/article/details/88873443
FX