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

C# 實作 CRectTracker:橡膠帶矩形選取與追蹤控制

     編輯:關於C#

前言:從 MFC 移植到 .NET 的幾何追蹤器

MFC 的 CRectTracker 是處理矩形選取、調整大小、拖曳移動的經典工具類。在 .NET 早期缺乏對應功能時,開發者常需自行移植。本文展示一個完整的 C# 版 CRectTracker 實作,支援八向調整控點、橡膠帶選取、游標動態切換,可直接用於 WinForms 繪圖編輯器、報表設計器等場景。

核心類別結構

public class CRectTracker
{
    public Rectangle m_rect;           // 追蹤矩形
    public int m_nStyle;               // 樣式旗標
    public bool m_bAllowInvert;        // 允許反向繪製

    public enum StyleFlags
    {
        resizeInside = 0x01,   // 內部調整控點
        resizeOutside = 0x02,  // 外部調整控點
        hatchInside = 0x04,    // 內部斜線填充
        // ... 其他旗標
    }

    // 核心方法
    public bool Track(Control ctrl, Point pt, bool allowInvert, object reserved);
    public bool TrackRubberBand(Control ctrl, Point pt, bool allowInvert);
    public int HitTest(Point pt);
    public void OnDraw(Graphics g);
    public bool SetCursor(Control ctrl, int nHitTest, Point pt);
    public void GetTrueRect(ref Rectangle rect);
    public void NormalizeRect(ref Rectangle rect);
}

整合至 MDI 架構:Document/View 模式

Document 層持有 Tracker 實例

public class CReportDoc
{
    public CRectTracker m_tracker = null;

    public CReportDoc(MainWindow mainWin)
    {
        m_tracker = new CRectTracker();
        m_tracker.m_rect = new Rectangle(10, 10, 91, 91);  // 初始位置與大小
        m_tracker.m_nStyle = (int)CRectTracker.StyleFlags.resizeInside;
    }
}

View 層處理滑鼠事件與繪製

public class CReportView : Form
{
    private CReportDoc myDoc;

    private void InitializeComponent()
    {
        this.MouseDown += CReportView_MouseDown;
        this.Paint += PaintHandler;
        this.MouseMove += CReportView_MouseMove;  // 替代 MFC OnSetCursor
    }

    private void PaintHandler(object sender, PaintEventArgs e)
    {
        myDoc.m_tracker.OnDraw(e.Graphics);  // 繪製追蹤矩形與控點
    }

    private void CReportView_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left) return;

        Point pt = new Point(e.X, e.Y);
        Rectangle rectSave = new Rectangle();
        myDoc.m_tracker.GetTrueRect(ref rectSave);

        if (myDoc.m_tracker.HitTest(pt) < 0)  // 點擊空白區 → 橡膠帶選取
        {
            CRectTracker tracker = new CRectTracker();
            if (tracker.TrackRubberBand(this, pt, myDoc.m_bAllowInvert))
            {
                tracker.NormalizeRect(ref tracker.m_rect);
                if (tracker.m_rect.IntersectsWith(myDoc.m_tracker.m_rect))
                {
                    // 切換控點樣式:內縮↔外擴
                    if ((myDoc.m_tracker.m_nStyle & (int)CRectTracker.StyleFlags.resizeInside) != 0)
                    {
                        myDoc.m_tracker.m_nStyle &= ~(int)CRectTracker.StyleFlags.resizeInside;
                        myDoc.m_tracker.m_nStyle |= (int)CRectTracker.StyleFlags.resizeOutside;
                    }
                    else
                    {
                        myDoc.m_tracker.m_nStyle &= ~(int)CRectTracker.StyleFlags.resizeOutside;
                        myDoc.m_tracker.m_nStyle |= (int)CRectTracker.StyleFlags.resizeInside;
                    }
                }
            }
            myDoc.UpdateAllViews(null);  // 觸發重繪
        }
        else  // 點擊現有追蹤器 → 拖曳/調整大小
        {
            if (myDoc.m_tracker.Track(this, pt, myDoc.m_bAllowInvert, null))
                myDoc.UpdateAllViews(null);
        }
    }

    private void CReportView_MouseMove(object sender, MouseEventArgs e)
    {
        Point pt = new Point(e.X, e.Y);
        if (!myDoc.m_tracker.SetCursor(this, 0, pt))
            this.Cursor = Cursors.Arrow;  // 預設游標
    }
}

關鍵技術細節解析

1. HitTest:精準判斷點擊區域

回傳值對應:-1=外部、0-7=八個控點、8=矩形內部。此邏輯決定是啟動橡膠帶選取還是進入拖曳/縮放模式。

2. Track vs TrackRubberBand

  • Track:處理現有矩形的移動與八向縮放,內部捕捉滑鼠移動直到按鍵釋放
  • TrackRubberBand:從點擊點拉出新矩形,即時繪製虛線框回饋

3. SetCursor:動態游標回饋

根據滑鼠懸停位置(控點/邊緣/內部)自動切換 Cursors.SizeNWSE、Cursors.SizeWE、Cursors.SizeAll 等,提升操作直覺性。

4. OnDraw:雙緩衝繪製避免閃爍

public void OnDraw(Graphics g)
{
    // 繪製矩形邊框
    g.DrawRectangle(Pens.Black, m_rect);
    // 繪製八個控點
    if ((m_nStyle & (int)StyleFlags.resizeOutside) != 0)
        DrawHandles(g, true);   // 外部控點
    else if ((m_nStyle & (int)StyleFlags.resizeInside) != 0)
        DrawHandles(g, false);  // 內部控點
    // 斜線填充
    if ((m_nStyle & (int)StyleFlags.hatchInside) != 0)
        g.FillRectangle(Brushes.HatchStyle.DiagonalCross, m_rect);
}

現代化改良建議

  • 支援多重選取:將單一 m_tracker 改為 List<CRectTracker>,配合 Shift/Ctrl 鍵實現群組操作
  • 加入磁鐵吸附:Track 過程中檢測與其他物件邊緣距離,自動對齊
  • WPF 移植:改用 Adorner 層繪製追蹤器,利用 Thumb 控制項處理拖曳邏輯
  • 序列化支援:實作 ISerializable,將追蹤器狀態存入專案檔

總結

這個 C# 版 CRectTracker 完整復刻 MFC 核心功能,並適配 WinForms 事件模型。對於需要矩形選取、縮放、拖曳的繪圖類應用,它提供了開箱即用的解決方案。理解其 HitTest → Track/TrackRubberBand → OnDraw 核心流程,有助於擴展更複雜的幾何編輯功能。

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