在 WinForms 中實現圖片的滑鼠拖曳移動,不需重繪,僅調整 PictureBox.Location。關鍵在於座標系轉換(螢幕座標 ↔ 容器座標)與拖曳狀態管理。
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsApplication2
{
public partial class Form1 : Form
{
// Base64 編碼的游標資料(省略完整字串)
static string strDown = @"AAACAAEAICAAAAsACQAwAQAAFgAAACgAAAAgAAAAQAAAAAEAAQAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...";
static string strUp = @"AAACAAEAICAAAAoACAAwAQAAFgAAACgAAAAgAAAAQAAAAAEAAQAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...";
Cursor curUp = new Cursor(new MemoryStream(Convert.FromBase64String(strUp)));
Cursor curDown = new Cursor(new MemoryStream(Convert.FromBase64String(strDown)));
bool bDragging = false;
Point pClicked;
public Form1()
{
InitializeComponent();
pictureBox1.Cursor = curUp;
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
bDragging = true;
pClicked = new Point(e.X, e.Y); // 記錄滑鼠在 PictureBox 內的相對位置
pictureBox1.Cursor = curDown;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (bDragging)
{
// 1. 取得滑鼠當前螢幕座標
// 2. 轉為表單用戶區座標
// 3. 減去點擊時的相對偏移,得到 PictureBox 新左上角
Point screenPos = pictureBox1.PointToScreen(new Point(e.X, e.Y));
Point clientPos = this.PointToClient(screenPos);
clientPos.Offset(-pClicked.X, -pClicked.Y);
pictureBox1.Location = clientPos;
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
bDragging = false;
pictureBox1.Cursor = curUp;
}
}
}
MouseDown 切換為「抓取」狀態,MouseUp 恢復。e.X, e.Y:PictureBox 用戶區座標PointToScreen → 螢幕絕對座標PointToClient → 表單用戶區座標Offset(-pClicked.X, -pClicked.Y) → 扣除點擊偏移,獲得 PictureBox 新 LocationbDragging 防止非拖曳時移動;pClicked 固定滑鼠在控件內的相對位置,避免控件「跳」到滑鼠左上角。Capture = true 可接收滑鼠離開控件後的訊息,簡化邏輯,但需注意釋放捕獲。掌握座標系轉換(Screen ↔ Client ↔ Control)是 WinForms 拖曳功能的核心。本範例展示最基礎且穩健的實作,可直接套用至任何 Control 衍生類別。