參考 QQ 截圖體驗:全螢幕半透明遮罩、滑鼠拖曳選取矩形、雙擊/Enter 確認輸出剪貼板、右鍵/ESC 取消。本文提供完整 WinForms 實作,核心技術包含 `Graphics.CopyFromScreen`、雙緩衝繪圖、`ControlPaint.DrawReversibleFrame` 反色框選、多螢幕支援。
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(); // 截圖結束恢復主視窗
}));
});
}
}
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` |
核心流程:**截全螢幕 → 全螢幕表單顯示背景 → 滑鼠選取矩形 → 反色框選+半透明遮罩視覺回饋 → 確認裁切寫入剪貼板**。`ControlPaint.DrawReversibleFrame` 是簡單實現專業級選取框的關鍵。現代專案可考慮引用開源庫 ShareX / ScreenToGif 核心邏輯,或直接呼叫系統 `SnippingTool` (`Win+Shift+S`)。