首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 模擬 QQ 桌面截圖功能:全螢幕遮罩 + 滑鼠選區 + Robot 截圖完整實作

     編輯:Java 相關知識

效果展示

點擊按鈕 → 全螢幕顯示當前桌面截圖 → 滑鼠拖曳選取矩形區域 → 釋放滑鼠 → 完成區域截圖並顯示於主視窗 → ESC/右鍵取消。

核心架構

  1. 主視窗:包含觸發按鈕與預覽區
  2. ScreenWindow (無邊框全螢幕視窗):顯示全螢幕截圖、捕獲滑鼠事件、繪製選區框(需自行實作虛線框)
  3. ScreenImage:封裝 Robot.createScreenCapture 實際截圖

完整程式碼

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;

public class QQScreenCaptureDemo extends JFrame {
    private JLabel previewLabel;

    public QQScreenCaptureDemo() {
        setTitle("QQ 風格截圖 Demo");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(400, 300);
        setLocationRelativeTo(null);

        JButton btn = new JButton("開始截圖 (右鍵取消)");
        btn.addActionListener(e -> startCapture());

        previewLabel = new JLabel("截圖預覽區");
        previewLabel.setHorizontalAlignment(SwingConstants.CENTER);
        previewLabel.setBorder(BorderFactory.createLineBorder(Color.GRAY));

        JScrollPane scroll = new JScrollPane(previewLabel);
        add(btn, BorderLayout.NORTH);
        add(scroll, BorderLayout.CENTER);
        setVisible(true);
    }

    private void startCapture() {
        // 在 EDT 外執行耗時截圖,避免凍結 UI
        new Thread(() -> {
            try {
                // 1. 先截全螢幕作為遮罩背景
                Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
                BufferedImage fullImg = ScreenImage.capture(0, 0, screen.width, screen.height);

                // 2. 建立全螢幕無邊框視窗
                JFrame overlay = new JFrame();
                overlay.setUndecorated(true);
                overlay.setBounds(0, 0, screen.width, screen.height);
                overlay.setAlwaysOnTop(true);

                JLabel imgLabel = new JLabel(new ImageIcon(fullImg));
                imgLabel.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
                overlay.add(imgLabel);

                // 3. 滑鼠選區邏輯
                final Point start = new Point();
                final Rectangle selection = new Rectangle();
                boolean[] dragging = {false};

                imgLabel.addMouseListener(new MouseAdapter() {
                    @Override public void mousePressed(MouseEvent e) {
                        if (SwingUtilities.isRightMouseButton(e)) { overlay.dispose(); return; }
                        start.setLocation(e.getPoint());
                        dragging[0] = true;
                    }
                    @Override public void mouseReleased(MouseEvent e) {
                        if (!dragging[0]) return;
                        dragging[0] = false;
                        Point end = e.getPoint();
                        selection.setFrame(
                            Math.min(start.x, end.x), Math.min(start.y, end.y),
                            Math.abs(end.x - start.x), Math.abs(end.y - start.y)
                        );
                        overlay.dispose();  // 先關閉遮罩

                        // 4. 截取選區
                        if (selection.width > 0 && selection.height > 0) {
                            BufferedImage sub = ScreenImage.capture(
                                selection.x, selection.y, selection.width, selection.height);
                            SwingUtilities.invokeLater(() -> 
                                previewLabel.setIcon(new ImageIcon(sub)));
                        }
                    }
                });
                imgLabel.addMouseMotionListener(new MouseMotionAdapter() {
                    @Override public void mouseDragged(MouseEvent e) {
                        if (!dragging[0]) return;
                        // 這裡可繪製即時選區框(需自行在 imgLabel 上繪製或用 GlassPane)
                        // 為簡潔略過,實際專案建議用 JXLayer 或自定義 GlassPane 繪製虛線框
                    }
                });

                overlay.setVisible(true);
            } catch (Exception ex) {
                ex.printStackTrace();
                SwingUtilities.invokeLater(() -> 
                    JOptionPane.showMessageDialog(this, "截圖失敗:" + ex.getMessage()));
            }
        }).start();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(QQScreenCaptureDemo::new);
    }
}

class ScreenImage {
    public static BufferedImage capture(int x, int y, int w, int h) throws AWTException {
        Robot robot = new Robot();
        Rectangle rect = new Rectangle(x, y, w, h);
        return robot.createScreenCapture(rect);
    }
}

關鍵技術點解析

技術說明
Robot.createScreenCapture跨平台螢幕截圖,返回 BufferedImage,需處理 AWTException
無邊框全螢幕 JFramesetUndecorated(true) + setBounds(screen) + setAlwaysOnTop(true)
滑鼠座標轉換元件座標 = 螢幕座標(因 JFrame 佔全螢幕),直接用 e.getPoint()
選區正規化Math.min/max + Math.abs 確保 width/height 為正
EDT 線程安全截圖耗時操作放入背景執行緒,UI 更新用 SwingUtilities.invokeLater

進階強化方向

  • 即時選區框繪製:使用 JLayer 或 GlassPane 在拖曳時繪製虛線矩形(Graphics2D.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, new float[]{5,5}, 0)))
  • 多螢幕支援:GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() 遍歷所有螢幕,合成虛擬桌面截圖
  • 縮放/高 DPI:Windows/Linux 高 DPI 下 Robot 截圖可能偏移,需配合 sun.java2d.uiScale 或 GDK_SCALE 處理
  • 工具列:選區完成後顯示工具列(筆刷、文字、馬賽克、儲存、複製到剪貼簿)
  • 系統托盤整合:註冊全域熱鍵(JNativeHook)啟動截圖

結語

Java 實作桌面截圖核心在於 Robot 截圖 + 無邊框全螢幕遮罩 + 滑鼠選區幾何計算。本範例提供最小可行性架構,生產級工具需在選區繪製、多螢幕、高 DPI、編輯工具上深度打磨。參考開源專案 ScreenCapture、ShareX (C#) 設計可加速開發。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved