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

C# 實作類 QQ 螢幕截圖工具:全螢幕遮罩、矩形選取、剪貼板輸出

     編輯:關於C語言

前言

參考 QQ 截圖體驗:全螢幕半透明遮罩、滑鼠拖曳選取矩形、雙擊/Enter 確認輸出剪貼板、右鍵/ESC 取消。本文提供完整 WinForms 實作,核心技術包含 `Graphics.CopyFromScreen`、雙緩衝繪圖、`ControlPaint.DrawReversibleFrame` 反色框選、多螢幕支援。

架構設計

  • MainForm:主視窗,含「開始截圖」按鈕。
  • ScreenCaptureForm:全螢幕無邊框表單 (`FormBorderStyle=None`, `TopMost=true`),背景為桌面截圖,負責選取邏輯與繪製。

核心代碼

1. 主視窗啟動截圖


public partial class MainForm : Form
{
    public MainForm() { InitializeComponent(); }

    private void btnCapture_Click(object sender, EventArgs e)
    {
        // 隱藏主視窗避免被截到
        this.Hide();
        
        // 稍微延遲確保視窗已隱藏
        Task.Delay(100).ContinueWith(_ => 
        {
            this.Invoke((Action)(() =>
            {
                using (var captureForm = new ScreenCaptureForm())
                {
                    captureForm.ShowDialog();
                }
                this.Show(); // 截圖結束恢復主視窗
            }));
        });
    }
}

2. 截圖表單完整實作


public class ScreenCaptureForm : Form
{
    private Bitmap _screenBitmap;      // 全螢幕截圖
    private Rectangle _selectionRect;  // 選取矩形
    private Point _startPoint;         // 滑鼠按下起點
    private bool _isSelecting;         // 是否正在選取
    private bool _selectionDone;       // 選取完成待確認

    public ScreenCaptureForm()
    {
        // 表單設定
        FormBorderStyle = FormBorderStyle.None;
        WindowState = FormWindowState.Maximized;
        TopMost = true;
        ShowInTaskbar = false;
        DoubleBuffered = true; // 雙緩衝減少閃爍
        Cursor = Cursors.Cross;

        // 事件訂閱
        MouseDown += OnMouseDown;
        MouseMove += OnMouseMove;
        MouseUp += OnMouseUp;
        MouseDoubleClick += OnDoubleClick;
        KeyDown += OnKeyDown;
        Paint += OnPaint;
        Load += OnLoad;
    }

    private void OnLoad(object sender, EventArgs e)
    {
        // 1. 截取所有螢幕虛擬桌面範圍
        Rectangle bounds = SystemInformation.VirtualScreen;
        _screenBitmap = new Bitmap(bounds.Width, bounds.Height);
        using (Graphics g = Graphics.FromImage(_screenBitmap))
        {
            g.CopyFromScreen(bounds.Location, Point.Empty, bounds.Size);
        }
        BackgroundImage = _screenBitmap; // 設為背景自動繪製
        BackgroundImageLayout = ImageLayout.None;
    }

    private void OnMouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            _isSelecting = true;
            _selectionDone = false;
            _startPoint = e.Location;
            _selectionRect = new Rectangle(e.Location, Size.Empty);
        }
        else if (e.Button == MouseButtons.Right)
        {
            CancelCapture();
        }
    }

    private void OnMouseMove(object sender, MouseEventArgs e)
    {
        if (!_isSelecting) return;

        // 計算矩形 (支援任意方向拖曳)
        int x = Math.Min(_startPoint.X, e.X);
        int y = Math.Min(_startPoint.Y, e.Y);
        int w = Math.Abs(_startPoint.X - e.X);
        int h = Math.Abs(_startPoint.Y - e.Y);
        _selectionRect = new Rectangle(x, y, w, h);
        
        Invalidate(); // 觸發重繪
    }

    private void OnMouseUp(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left && _isSelecting)
        {
            _isSelecting = false;
            _selectionDone = (_selectionRect.Width > 5 && _selectionRect.Height > 5);
            Invalidate();
        }
    }

    private void OnDoubleClick(object sender, MouseEventArgs e)
    {
        if (_selectionDone && _selectionRect.Contains(e.Location))
        {
            ConfirmCapture();
        }
    }

    private void OnKeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Escape) CancelCapture();
        else if (e.KeyCode == Keys.Enter && _selectionDone) ConfirmCapture();
    }

    private void OnPaint(object sender, PaintEventArgs e)
    {
        if (_selectionRect.Width == 0 || _selectionRect.Height == 0) return;

        // 1. 繪製半透明遮罩 (全螢幕除選取區外)
        using (var brush = new SolidBrush(Color.FromArgb(120, 0, 0, 0)))
        {
            // 利用 Region 排除選取區
            using (var region = new Region(ClientRectangle))
            {
                region.Exclude(_selectionRect);
                e.Graphics.FillRegion(brush, region);
            }
        }

        // 2. 繪製選取邊框 (反色框選,自動適應背景)
        ControlPaint.DrawReversibleFrame(
            RectangleToScreen(_selectionRect), 
            Color.White, 
            FrameStyle.Dashed);

        // 3. 顯示尺寸資訊
        string sizeText = $"{_selectionRect.Width} x {_selectionRect.Height}";
        var textSize = e.Graphics.MeasureString(sizeText, Font);
        Point textPos = new Point(
            _selectionRect.Right - (int)textSize.Width - 5,
            _selectionRect.Top - (int)textSize.Height - 5);
        if (textPos.Y < 0) textPos.Y = _selectionRect.Bottom + 5;
        
        using (var bgBrush = new SolidBrush(Color.Black))
        using (var fontBrush = new SolidBrush(Color.White))
        {
            e.Graphics.FillRectangle(bgBrush, new Rectangle(textPos, textSize.ToSize()));
            e.Graphics.DrawString(sizeText, Font, fontBrush, textPos);
        }
    }

    private void ConfirmCapture()
    {
        // 1. 裁切選取區域 (需轉換為螢幕座標)
        Rectangle screenRect = RectangleToScreen(_selectionRect);
        using (var cropped = new Bitmap(screenRect.Width, screenRect.Height))
        using (var g = Graphics.FromImage(cropped))
        {
            g.CopyFromScreen(screenRect.Location, Point.Empty, screenRect.Size);
            Clipboard.SetImage(cropped); // 寫入剪貼板
        }
        DialogResult = DialogResult.OK;
        Close();
    }

    private void CancelCapture()
    {
        DialogResult = DialogResult.Cancel;
        Close();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing) _screenBitmap?.Dispose();
        base.Dispose(disposing);
    }
}

關鍵技術點解析

技術用途關鍵代碼
虛擬桌面截圖支援多螢幕、任務列、不同 DPI`SystemInformation.VirtualScreen` + `CopyFromScreen`
反色虛線框任何背景下清晰可見,無需手動計算對比色`ControlPaint.DrawReversibleFrame`
半透明遮罩視覺聚焦選取區,`Region.Exclude` 排除矩形`FillRegion` + `SolidBrush(Color.FromArgb(120,0,0,0))`
雙緩衝拖曳過程無閃爍`DoubleBuffered = true`
座標轉換表單座標 → 螢幕座標 → 裁切`RectangleToScreen` + `CopyFromScreen`

進階擴展建議

  • 編輯工具列:選取完成後顯示工具列(筆刷、文字、馬賽克、箭頭),在 `_screenBitmap` 上繪製後再裁切。
  • 固定比例/尺寸:`Shift` 鍵鎖定 1:1/16:9/4:3,`Ctrl` 鍵從中心擴展。
  • 釘選/延遲截圖:`Timer` 延遲 N 秒啟動,支援選單截圖。
  • 高 DPI 感知:`app.manifest` 設定 `True/PM`,或 .NET 6+ `Application.SetHighDpiMode(HighDpiMode.PerMonitorV2)`。
  • 跨平台:Avalonia/MAUI 使用 `PixelBuffer`/`Skia` 實作類似邏輯。

總結

核心流程:**截全螢幕 → 全螢幕表單顯示背景 → 滑鼠選取矩形 → 反色框選+半透明遮罩視覺回饋 → 確認裁切寫入剪貼板**。`ControlPaint.DrawReversibleFrame` 是簡單實現專業級選取框的關鍵。現代專案可考慮引用開源庫 ShareX / ScreenToGif 核心邏輯,或直接呼叫系統 `SnippingTool` (`Win+Shift+S`)。

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