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

工業控制管道流動控件:從漸層繪製到雙緩衝動畫的完整實作

     編輯:關於VC++

專案緣起與設計目標

中小型工控專案常面臨「買昂貴組態軟體授權」vs「自行開發圖形元件」的抉擇。本文實作一個可復用的 管道流動控件,支援:

  • 水平/垂直兩種管道模式
  • 四向流向(左→右、右→左、上→下、下→上)
  • 多種流體單元外觀(矩形、圓形、雙線箭頭、三角形)
  • 無閃爍雙緩衝動畫
  • 純 MFC/C++ 實作,零第三方授權成本

核心資料結構定義


// 管道模式
enum FLOWPATTERN { FP_HORIZONTAL = 0, FP_VERTICAL = 1 };

// 流向
enum DIRECTIONTYPE {
    LEFT_TO_RIGHT = 0, RIGHT_TO_LEFT = 1,
    TOP_TO_BOTTOM = 2, BOTTOM_TO_TOP = 3
};

// 單元外觀
enum UNITPATTERN {
    UP_RECTANGLE = 0, UP_CIRCLE = 1,
    UP_DLINE = 2,   // >> 箭頭
    UP_TRIANGLE = 3
};

管道本體繪製:漸層模擬 3D 圓管效果

原理:管道邊緣與中心使用同色系深/淺色交替(淺-深-淺 → 凹面;深-淺-深 → 凸面),產生視覺立體感。採用 單像素寬/高記憶體位圖 + StretchBlt 拉伸 的高效漸層算法:


void CPipeImpl::DrawGradient(CDC* pDC) {
    CRect rcClient; m_pOwner->GetClientRect(&rcClient);
    int nWidth = (m_pOwner->GetFlowPattern() == FP_HORIZONTAL) ? rcClient.Height() : rcClient.Width();

    // 1. 產生漸層色表
    RGBTRIPLE* pRGBTriple = new RGBTRIPLE[nWidth];
    m_Gradient.MakeEntries(pRGBTriple, nWidth); // 自訂漸層產生器

    // 2. 建立 1 x nWidth (或 nWidth x 1) 記憶體位圖
    CBitmap MemBmp; CDC MemDC;
    MemBmp.CreateCompatibleBitmap(pDC,
        (m_pOwner->GetFlowPattern() == FP_HORIZONTAL) ? 1 : rcClient.Width(),
        (m_pOwner->GetFlowPattern() == FP_HORIZONTAL) ? rcClient.Height() : 1);
    MemDC.CreateCompatibleDC(pDC);
    CBitmap* pOldBmp = MemDC.SelectObject(&MemBmp);

    // 3. 逐像素寫入漸層色
    for (int i = 0; i < nWidth; ++i) {
        CPoint pt = (m_pOwner->GetFlowPattern() == FP_HORIZONTAL) ? CPoint(0, i) : CPoint(i, 0);
        COLORREF cr = RGB(pRGBTriple[i].rgbtRed, pRGBTriple[i].rgbtGreen, pRGBTriple[i].rgbtBlue);
        MemDC.SetPixelV(pt, cr);
    }

    // 4. 拉伸貼回實際客戶區
    if (m_pOwner->GetFlowPattern() == FP_HORIZONTAL)
        pDC->StretchBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(),
                        &MemDC, 0, 0, 1, nWidth, SRCCOPY);
    else
        pDC->StretchBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(),
                        &MemDC, 0, 0, nWidth, 1, SRCCOPY);

    MemDC.SelectObject(pOldBmp);
    delete[] pRGBTriple;
}

優點:管道背景靜態,僅在屬性變更時重繪一次,極大降低動畫幀的繪圖負擔。

流體單元:多態繪製與動態位置計算

單元繪製 CFlowUnit::Draw()

依 UNITPATTERN 切換繪圖邏輯,支援矩形、圓形、雙線箭頭(四向)、三角形(四向指向)。關鍵點:

  • 使用 NULL_PEN 避免邊框干擾
  • 三角形頂點座標依 DIRECTIONTYPE 動態計算,確保箭頭朝向正確
  • 雙線箭頭以五段折線模擬 >> 形狀

動畫引擎 CFlowImpl::CalculateFlowUnit()

核心邏輯:

  1. 維護 CList m_arrayFlowUnit 單元鏈表
  2. InitFlowUnit() 依管道長/寬、單元尺寸/間距預填滿管道
  3. 定時器觸發 → 遍歷鏈表 → 每單元位置 DeflateRect 位移 UNIT_STEP 像素
  4. 單元移出管道邊界 → 從鏈表頭/尾移除 → 在對側補入新單元 → 形成無限循環
  5. 雙緩衝:OnPaint 先畫管道背景到記憶體 DC,再疊加所有單元,最後 BitBlt 一次貼到螢幕,零閃爍

// 水平左→右範例
if (dir == LEFT_TO_RIGHT) {
    rcUnit.DeflateRect(UNIT_STEP, 0, -UNIT_STEP, 0); // 右移
    if (rcUnit.left >= rcClient.right) { // 移出右邊
        // 取頭部單元座標作為新單元生成參考
        CRect rcAdd = ...; // 計算左側新位置
        CFlowUnit* pNew = new CFlowUnit(); pNew->SetRect(rcAdd); ...
        m_arrayFlowUnit.AddHead(pNew); // 新單元加入頭部
        m_arrayFlowUnit.RemoveAt(pos); // 移除舊尾部
    }
}
// 垂直、反向邏輯對稱,詳見原始碼

控件整合與介面

  • 主類別 CFlowCtrl : public CStatic,處理 WM_PAINT、WM_TIMER、雙緩衝 DC
  • 內含 CPipeImpl(管道靜態繪製)與 CFlowImpl(動畫邏輯)兩組件,職責分離
  • 公開屬性介面:SetFlowPattern()、SetDirectionType()、SetUnitPattern()、SetUnitBackColor() 等,支援執行期動態切換外觀

執行效果與擴充建議

未來可擴充:

  • 彎管、三通、閥門等複雜拓撲(以節點/邊圖形建模)
  • 流速/流量數值綁定,單元密度/顏色動態反映實時數據
  • 支援 GDI+ / Direct2D 進階渲染(抗鋸齒、材質貼圖)
  • 封裝為 ActiveX / .NET 控件跨平台複用

完整原始碼已開源,歡迎交流改進。

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