<strike id="kiyse"></strike>
  • <tr id="kiyse"></tr>
  • <strike id="kiyse"></strike><samp id="kiyse"><tbody id="kiyse"></tbody></samp>
    <strike id="kiyse"><s id="kiyse"></s></strike>
    <tr id="kiyse"></tr>
    <noframes id="kiyse"><code id="kiyse"></code></noframes>
    <th id="kiyse"></th>
    <samp id="kiyse"></samp>
  • <th id="kiyse"><s id="kiyse"></s></th>
  • 低成本多通道波形采集顯示方案的軟件實(shí)現(xiàn)方法

     2012-2-23              

            英創(chuàng)ARM9系列嵌入式主板EM9170加上新近推出的數(shù)據(jù)采集擴(kuò)展模塊ETA108,可實(shí)現(xiàn)低成本的多通道波形采集。該方案的硬件平臺(tái)見(jiàn)如下文章:《低成本多通道波形采集方案》。本文將從應(yīng)用的角度詳細(xì)介紹ETA108接口的使用方法,并在此基礎(chǔ)之上實(shí)現(xiàn)一個(gè)完整的多通道波形采集的圖形界面顯示方案。

     

            該方案采用EM9170嵌入式主板,及擴(kuò)展模塊ETA108,可同時(shí)采集8個(gè)通道,最高采樣頻率100KHz,AD轉(zhuǎn)換精度12bit。圖形界面在7寸屏上全屏顯示,以波形圖形式同時(shí)顯示各個(gè)通道AD采樣結(jié)果。用戶可以自由移動(dòng)觀察波形,并通過(guò)鼠標(biāo)指針獲得波形圖中各點(diǎn)詳細(xì)信息。

     

            下圖為ETA108波形采集程序?qū)σ宦氛ê鸵宦啡遣ǖ腁D采樣截圖,采樣頻率為50000Hz。

     

     

            本文介紹該方案中ETA108模塊參數(shù),驅(qū)動(dòng)安裝,接口調(diào)用方法,以及使用C++編程,實(shí)現(xiàn)圖形界面顯示的一些程序開(kāi)發(fā)方法。

     

    1、ETA108模塊參數(shù)

            ETA108是為了進(jìn)一步支持EM9170在儀器儀表,數(shù)據(jù)采集領(lǐng)域應(yīng)用,同時(shí)也是為了方便客戶使用而推出的一款低成本高性能AD采集模塊。ETA108的主要性能如下:

            ? 8通道單端輸入或4通道差分輸入

            ? 單極性輸入量程0~4V或雙極性輸入量程±2V

            ? 每通道具有獨(dú)立的高阻抗增益放大器(PGA),可實(shí)現(xiàn)各種傳感器之間的直接接口連接,并支持用戶配置通道增益(Gain=1/2/4/8)

            ? AD轉(zhuǎn)換精度12bit

            ? AD最高采樣速度100ksps

            ? 可選擇多種平均操作模式,使輸出AD精度達(dá)到14bit

            ? 單5V供電

     

            關(guān)于ETA108的詳細(xì)介紹,可閱讀ETA108的手冊(cè):《ETA108數(shù)據(jù)采集模塊使用手冊(cè)》

     

    2、驅(qū)動(dòng)安裝

            復(fù)制ETA108驅(qū)動(dòng)程序安裝包Emtronix ETA108.cab到EM9170主板NandFlash目錄下。

     

            安裝該文件到NandFlash目錄下。

     

     

            安裝完成后在NandFlash目錄下會(huì)生成驅(qū)動(dòng)文件ETA108V2.dll。安裝完成之后,斷電重啟不需要重復(fù)安裝。

     

    3、ETA108模塊調(diào)用方法

            請(qǐng)參考產(chǎn)品光盤(pán)中ETA108的測(cè)試?yán)蹋诠こ讨刑砑覧TA108.h和ETA108.cpp文件,并添加對(duì)應(yīng)的引用,即可非常方便的使用API控制ETA108模塊。

     

            ETA108驅(qū)動(dòng)程序提供的接口函數(shù)說(shuō)明如下:

     

    (1) BOOL ETA108Open( )
    功能描述:調(diào)用CreateFile函數(shù),打開(kāi)ETA108驅(qū)動(dòng)程序
    返回值:=TRUE:打開(kāi)ETA108成功    = FALSE:打開(kāi)失敗

     

    (2) BOOL Setup( PADS_CONFIG pADSConfig, PADS_CONFIG pADSConfigOut )
    功能描述:設(shè)置AD采集相關(guān)參數(shù),采集通道,采樣長(zhǎng)度等
    輸入?yún)?shù):pADSConfig 配置參數(shù)結(jié)構(gòu)體指針
    輸出參數(shù):pADSConfigOut
    返回值:=TRUE:參數(shù)設(shè)置成功    =FALSE:參數(shù)設(shè)置失敗

     

            ADSConfig結(jié)構(gòu)體是ETA108的配置數(shù)據(jù)結(jié)構(gòu)體,包含了采樣率,采樣長(zhǎng)度,采樣通道設(shè)置,通道寄存器配置等參數(shù)。其定義如下:

     

    typedef struct
    {
            DWORD dwSamplingRate;
            DWORD dwSamplingLength;
            DWORD dwSamplingChannel;
            LPVOID lpContrlWord;
            DWORD dwContrlWordLength;
    } ADS_CONFIG, *PADS_CONFIG;

     

            ADS_CONFIG結(jié)構(gòu)體即可用為函數(shù)的輸入?yún)⒖迹部勺鳛檩敵鰠?shù)使用,其結(jié)構(gòu)體成員含義說(shuō)明如下:

     


    成員

    輸入?yún)?shù)定義

    輸出參數(shù)定義

      dwSamplingRate  設(shè)置每個(gè)AD通道的采樣率  返回總的采樣率(=每通道采樣率*采樣通道數(shù))
      dwSamplingLength

     

      設(shè)置每個(gè)AD通道的采樣長(zhǎng)度

      >0:?jiǎn)未尾蓸?nbsp; =0:連續(xù)采樣

     

      返回總的采樣長(zhǎng)度(=每通道采長(zhǎng)度*采樣通道數(shù))
      dwSamplingChannel*  設(shè)置需要采樣的通道  返回采樣的通道數(shù)
      lpContrlWord

     

      指向AD通道配置的buffer,此參數(shù)用于設(shè)置ETA108的

      寄存器,lpContrlWord =NULL時(shí),系統(tǒng)使用默認(rèn)配置

     


      dwContrlWordLength  lpContrlWord 指向buffer的長(zhǎng)度


     

            *dwSamplingChannel的低8bit(bit0~bit7)依次對(duì)應(yīng)AD通道0~通道7,如果要采集某個(gè)通道的數(shù)據(jù),需要將其對(duì)應(yīng)的位置為1。比如要采集通道0、通道1和通道7的數(shù)據(jù),則應(yīng)設(shè)置dwSamplingChannel=0x83。

     

    (3) BOOL Start( )
    功能描述:?jiǎn)?dòng)AD采集
    返回值:=TRUE 開(kāi)始AD采集    =FALSE 啟動(dòng)AD采集

     

    (4) BOOL WaitDataReady( DWORD dwTimeOut )
    功能描述:等待AD采集完成
    輸入?yún)?shù):dwTimeOut 等待超時(shí)時(shí)間(ms),設(shè)置dwTimeOut=0時(shí),驅(qū)動(dòng)程序?qū)⒆詣?dòng)計(jì)算一個(gè)合適的等待時(shí)間。連續(xù)采樣模式下,此函數(shù)大約250ms返回一次
    返回值:=TRUE AD采集完成,接下來(lái)可讀取采集數(shù)據(jù)    =FALSE 等待超時(shí),AD采集存在錯(cuò)誤

     

    (5) DWORD Read( LPVOID pBuf, DWORD dwReadLength )
    功能描述:讀取采集數(shù)據(jù)
    輸入?yún)?shù):pBuf 用于存放數(shù)據(jù)的buffer    dwReadLength 要讀取的數(shù)據(jù)個(gè)數(shù)(以字節(jié)計(jì)數(shù))即采樣長(zhǎng)度×采樣通道數(shù)×sizeof(UINT32)
    返回值:>0 實(shí)際讀取的字節(jié)數(shù)    =0 無(wú)采集數(shù)據(jù)    =-1 函數(shù)執(zhí)行失敗

     

    (6) BOOL Stop( )
    功能描述:中止當(dāng)前AD采集。
    返回值:=TRUE 函數(shù)執(zhí)行成功    =FALSE 函數(shù)執(zhí)行失敗

     

    (7) void ETA108Close ( )
    功能描述:關(guān)閉ETA108,釋放相關(guān)資源

     

    4、采樣結(jié)果

            使用Read函數(shù),傳入32bit數(shù)組指針。該數(shù)組長(zhǎng)度為ADSConfigOut. dwSamplingChannel,即采樣長(zhǎng)度×采樣通道數(shù)。獲得的采樣數(shù)據(jù)在數(shù)組中按各通道依次排列。

     

            例如:pBuf為數(shù)組指針,采樣通道為AD3和AD5,采樣長(zhǎng)度為5000,那么pBuf長(zhǎng)度為10000,即5000*2*sizeof(UINT32)字節(jié),其中AD3的5000長(zhǎng)度數(shù)據(jù)依次放在pBuf[0]到pBuf[4999],AD5的5000長(zhǎng)度數(shù)據(jù)依次放在pBuf[5000]到pBuf[9999]。

     

            數(shù)組中每一位32bit數(shù)據(jù)具體定義如下:

     

     

     

            其中第0位是單端/差分標(biāo)識(shí)位,第1-3位是通道地址位,第4、5位平均模式下增加的2位分辨率,第6-17為12bit的AD數(shù)據(jù)。

     

            例如:獲得pBuf中第n位的AD數(shù)據(jù)值v,即v = pBuf[n]>>6。

     

            理想情況下,輸入電壓與AD輸出的12bit數(shù)據(jù)定義如下:

     


    描述

    模擬量輸入

    二進(jìn)制數(shù)字輸出

    十六進(jìn)制數(shù)字輸出

      滿量程范圍  V&not;REF&not;

      最小分辨率
    (LSB)
      V&not;REF/4096&not;

      滿量程  V&not;REF-1LSB  1111 1111 1111  FFFF
      1/2量程  V&not;REF/2  1000 0000 0000  8000
      1/2量程-1LSB  V&not;REF/2-1LSB  0111 1111 1111  7FFF
      零  0V  0000 0000 0000  0000


     

    5、連續(xù)采樣

            設(shè)置dwSamplingLength=0時(shí),ETA108工作在連續(xù)采樣模式。在連續(xù)采樣模式下,驅(qū)動(dòng)程序連續(xù)不斷的進(jìn)行數(shù)據(jù)采集,并大約每隔250ms通知一次應(yīng)用程序,以便應(yīng)用程序可將數(shù)據(jù)從驅(qū)動(dòng)緩存中讀出。應(yīng)用程序可從Setup函數(shù)的輸出參數(shù):ADS_CONFIG結(jié)構(gòu)體的dwSamplingLength成員,得到每次可以讀取的數(shù)據(jù)總長(zhǎng)度。

     

     

    6、波形采集程序說(shuō)明

            ETA108波形采集例程實(shí)現(xiàn)了單次采樣的操作,并將采樣的波形繪制成曲線,顯示在界面上。

     

            (1)在對(duì)話框初始化函數(shù)OnInitDialog中初始各個(gè)參數(shù)和界面設(shè)置,然后打開(kāi)ETA108設(shè)備。

     

    // 加載驅(qū)動(dòng)
    if (!ETA108Open())
    {
            AfxMessageBox(L'打開(kāi)設(shè)備失敗');
    }

     

            (2)在“采集”按鈕的響應(yīng)函數(shù)中,根據(jù)界面中選擇的采樣頻率,采樣長(zhǎng)度,采樣通道,將參數(shù)設(shè)置到配制結(jié)構(gòu)體ADSConfig中,執(zhí)行Setup函數(shù)設(shè)置參數(shù)。

     

    ADS_CONFIG adsConfig; // 采樣參數(shù)設(shè)置
    ADS_CONFIG adsConfigOut; // 返回采樣參數(shù)
    adsConfig.dwSamplingRate = m_dwSamplingRate;
    adsConfig.dwSamplingLength = m_dwSamplingLength;
    adsConfig.dwSamplingChannel = m_dwSamplingChannel;

     

    ret = Setup(&adsConfig,&adsConfigOut);
    if (!ret)
    {
            AfxMessageBox(L'參數(shù)設(shè)置失敗');
            return;
    }

     

            (3)根據(jù)采樣長(zhǎng)度申請(qǐng)一段數(shù)組存儲(chǔ)AD數(shù)據(jù)。


    UINT32* pBuf; // 接收區(qū)指針
    if(pBuf != NULL)
    {
            delete [] pBuf;
            pBuf = NULL;
    }
    pBuf = new UINT32[adsConfigOut.dwSamplingLength];
    if( pBuf == NULL )
    {
            AfxMessageBox(L'創(chuàng)建BUFFER失敗');
            return;
    }

     

            (4)執(zhí)行Start函數(shù)開(kāi)始采集。


    ret = Start();
    if (!ret)
    {
            AfxMessageBox(L'執(zhí)行失敗');
            return;
    }

     

            (5)執(zhí)行等待函數(shù)WaitDataReady等待ETA108采樣完成。


    ret = WaitDataReady(0);

     

            (6)在等待完成后執(zhí)行Read函數(shù)讀出AD采樣結(jié)果。


    DWORD dwNumberOfBytesRead;
    dwNumberOfBytesRead = Read( pBuf, adsConfigOut.dwSamplingLength*sizeof(UINT32));
    if (dwNumberOfBytesRead == -1)
    {
            AfxMessageBox(L'讀取失敗');
            return;
    }

     

            (7)處理BUF內(nèi)的數(shù)據(jù),然后根據(jù)實(shí)際需要將數(shù)據(jù)存放數(shù)據(jù)庫(kù),或是曲線形式顯示在界面上。例程中根據(jù)采樣長(zhǎng)度設(shè)置滾動(dòng)條,并執(zhí)行繪制曲線函數(shù)DrawCurve。

     

            (8)程序關(guān)閉函數(shù)中,釋放資源,關(guān)閉ETA108。


    ETA108Close();

     

    7、界面設(shè)計(jì)

            本波形采集程序使用MFC的對(duì)話框程序,繪圖部分使用的GDI函數(shù)。程序界面對(duì)應(yīng)7寸屏,界面大小為800×480。

     

            (1)全屏顯示,隱藏WINCE系統(tǒng)工具欄,設(shè)置對(duì)話框大小為800×480,然后在對(duì)話框初始函數(shù)中添加代碼

            方案一:

            1.然后使用API函數(shù)獲得工具欄窗口句柄。
    HWND hWnd = ::FindWindow(L'HHTaskBar', NULL);

     

            2.重新設(shè)置,隱藏窗口。
    ::ShowWindow(hWnd, SW_MINIMIZE);

            這個(gè)方法在關(guān)閉程序后工具欄不會(huì)恢復(fù),并且每次重啟后,工具欄會(huì)恢復(fù)。如果設(shè)置程序?yàn)樽詥?dòng),希望在系統(tǒng)啟動(dòng)到打開(kāi)程序期間不會(huì)讓用戶看到彈出的工具欄,可以使用方案二。

     

            方案二:

            1.設(shè)置工具欄自動(dòng)隱藏,并設(shè)置工具欄不會(huì)總在最上方,該操作可以右鍵工具欄->屬性,進(jìn)行設(shè)置。

     

     

            代碼實(shí)現(xiàn)為修改注冊(cè)表,然后通知工具欄更新。

     

    /*BOOL bAutoHide = TRUE;
    lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L'Software\\Microsoft\\Shell\\AutoHide', 0, KEY_ALL_ACCESS, &hkey);
    if(lRet != ERROR_SUCCESS) {
            lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, L'Software\\Microsoft\\Shell\\AutoHide', 0, NULL, 0, KEY_ALL_ACCESS,
    NULL, &hkey, &dw);
    }
    if (lRet == ERROR_SUCCESS) {
            RegSetValueEx(hkey, L'', 0, REG_DWORD, (LPBYTE)&bAutoHide, sizeof(DWORD));
            RegCloseKey(hkey);
    }*/
    BOOL bOnTop = FALSE;
    lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L'Software\\Microsoft\\Shell\\OnTop', 0, KEY_ALL_ACCESS, &hkey);
    if(lRet != ERROR_SUCCESS) {
            lRet = RegCreateKeyEx(HKEY_LOCAL_MACHINE, L'Software\\Microsoft\\Shell\\OnTop', 0, NULL, 0, KEY_ALL_ACCESS,
    NULL, &hkey, &dw);
    }
    if (lRet == ERROR_SUCCESS) {
            RegSetValueEx(hkey, L'', 0, REG_DWORD, (LPBYTE)&bOnTop, sizeof(DWORD));
            RegCloseKey(hkey);
    }
    ::PostMessage(hWnd, WM_WININICHANGE, 0, 5000);

     

            (2)程序背景設(shè)計(jì)

            MFC自帶的邊框和標(biāo)題欄顏色比較單調(diào),另外其他控件也過(guò)于樸實(shí)。所以例程里將窗體的Border屬性設(shè)置為None,然后以圖片背景的形式設(shè)計(jì)程序的標(biāo)題欄,及其他控件的背景。

     

            使用繪圖軟件,如Photoshop根據(jù)實(shí)際應(yīng)用狀況,制作一副800×480的界面圖。

     

     

            根據(jù)界面圖調(diào)整各個(gè)控件的位置,MFC的界面設(shè)計(jì)如下。

     

     

            將背景圖片添加到資源文件中,然后新建背景畫(huà)刷,修改對(duì)話框的OnCtlColor函數(shù),在重刷對(duì)話框的時(shí)候,返回背景畫(huà)刷。

     

    Brush brBk;
    BOOL CETA108_TESTDlg::OnInitDialog()
    {
            …
            CBitmap bmp;
            bmp.LoadBitmap(IDB_BITMAP_BK);
            brBk.CreatePatternBrush(&bmp);
            bmp.DeleteObject();
            …
    }

     

    HBRUSH CETA108_TESTDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
    {
            HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
            // TODO: Change any attributes of the DC here
            if (pWnd == this)
            {
                    return brBk;
            }
            …
    }

     

            (3)自定義按鈕的實(shí)現(xiàn)

            靜態(tài)控件可以都放在背景圖片中,按鈕需要另外制作。

            1、同樣在Photoshop中設(shè)計(jì)好按鈕各個(gè)狀態(tài)的圖片。這里有兩個(gè)按鈕,一個(gè)是“開(kāi)始采樣”按鈕,一個(gè)是“退出”按鈕。
    其中“開(kāi)始采樣”按鈕設(shè)計(jì)3個(gè)狀態(tài)。

     

    普通狀態(tài)                高亮狀態(tài)                按下?tīng)顟B(tài)

     

            “退出”按鈕設(shè)計(jì)2個(gè)狀態(tài)。

     

     
    普通狀態(tài)                高亮狀態(tài)

     

            將這些圖片添加到資源中。

     

            2、添加一個(gè)基于MFC普通按鈕CButton的新類CMyButton。

            在對(duì)話框界面中右鍵->添加類,選擇基類為CButton,添加一個(gè)新類CMyButton。

     

    // 給這個(gè)類添加儲(chǔ)存各個(gè)狀態(tài)位圖的CBitmap成員
    CBitmap m_bmpBtnnormal; // 普通
    CBitmap m_bmpBtnon; // 高亮
    CBitmap m_bmpBtndown; // 按下
    // 添加一個(gè)成員記錄按鍵是否處于鼠標(biāo)位置(高亮狀態(tài))
    BOOL m_bTracking;

     

            3、在對(duì)話框中添加自定義按鈕,設(shè)置他們?yōu)镃MyButton。

    CMyButton m_BtnBegin;
    CMyButton m_BtnExit;

     

            4、給自定義按鈕添加消息響應(yīng)函數(shù)。

            如果按鈕要實(shí)現(xiàn)鼠標(biāo)移動(dòng)上去顯示高亮的效果,需要給CMyButton類添加消息響應(yīng)。如果鼠標(biāo)移動(dòng)到按鍵上,則設(shè)置m_bTracking = TRUE;當(dāng)鼠標(biāo)離開(kāi),則設(shè)置m_bTracking = FALSE;

     

            Wince不同于Windows,CButton不能添加WM_MOUSEHOVER和WM_MOUSELEAVE消息,只能設(shè)置鼠標(biāo)移動(dòng)消息響應(yīng)函數(shù)。

     

            頭文件添加
    DECLARE_MESSAGE_MAP()
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);

     

            cpp文件添加
    BEGIN_MESSAGE_MAP(CMyButton, CButton)
    ON_WM_MOUSEMOVE() // 必須在按鈕上移動(dòng)才有消息
    // ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover) // wince不行
    // ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
    END_MESSAGE_MAP()

     

    void CMyButton::OnMouseMove(UINT nFlags, CPoint point)
    {
            // TODO: 在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值
            if (!m_bTracking)
            {
                    m_bTracking = TRUE;
                    Invalidate();
            }
            // CButton::OnMouseMove(nFlags, point);
    }

     

            按鈕的鼠標(biāo)移動(dòng)消息是當(dāng)鼠標(biāo)在按鈕上移動(dòng)時(shí)才響應(yīng),所以在響應(yīng)函數(shù)里直接設(shè)置m_bTracking = TRUE;而鼠標(biāo)移開(kāi)的消息只能在對(duì)話框的鼠標(biāo)移動(dòng)消息函數(shù)中來(lái)通知。

     

            給CMyButton添加一個(gè)方法:
    public:
    void MouseLeave();

    void CMyButton::MouseLeave() // WINCE控件響應(yīng)不到MOUSE事件,只好DIALOG來(lái)通知了
    {
            if (m_bTracking)
            {
                    m_bTracking = FALSE;
                    Invalidate();
            }
    }

     

            對(duì)話框的鼠標(biāo)移動(dòng)消息里面調(diào)用自定義按鈕的MouseLeave方法:
    void CETA108_TESTDlg::OnMouseMove(UINT nFlags, CPoint point)
    {
            // TODO: Add your message handler code here and/or call default
            //加按鈕處理

            m_BtnBegin.MouseLeave();
            m_BtnExit.MouseLeave();
            …
    }

     

            5、添加CMyButton類的初始化函數(shù),在初始化函數(shù)中重新加載控件,并加載按鈕圖片。

     

    BOOL CMyButton::InitButton(CDialog* pParent, UINT nCtlID, UINT nID1, UINT nID2, UINT nID3) // 在OnInitDialog()中初始化按鈕上使用
    {
            CWnd *pWnd = pParent->GetDlgItem(nCtlID); // 取得控件的指針
            if (pWnd)
            {
                    pWnd->GetWindowRect(&m_rect); // 返回指定窗口的邊框矩形的尺寸(屏幕坐標(biāo))
                    pParent->ScreenToClient(&m_rect); // 以用戶坐標(biāo)替代屏幕坐標(biāo)

                    CString szCaption;
                    pWnd->GetWindowText(szCaption); // 獲取控件上已賦的文本
                    DWORD dwStyle= pWnd->GetStyle(); // 獲取控件原有的風(fēng)格

                    pWnd->DestroyWindow(); // 銷毀控件
                    Create(szCaption, dwStyle|BS_OWNERDRAW,m_rect, pParent, nCtlID); // 在控件的基礎(chǔ)上創(chuàng)建一個(gè)新控件

                   // 加載圖片
                   m_bmpBtnnormal.LoadBitmap(nID1);
                   m_bmpBtnon.LoadBitmap(nID2);
                   m_bmpBtndown.LoadBitmap(nID3);

                   return TRUE;
            }
            else
            {
                   return FALSE;
            }
    }

     

            在對(duì)話框的初始化函數(shù)中調(diào)用自定義按鈕初始函數(shù),傳入對(duì)話框指針和按鈕圖片資源ID。

     

    BOOL CETA108_TESTDlg::OnInitDialog()
    {
            CDialog::OnInitDialog();
            // 設(shè)置此對(duì)話框的圖標(biāo)。當(dāng)應(yīng)用程序主窗口不是對(duì)話框時(shí),框架將自動(dòng)
            // 執(zhí)行此操作
            SetIcon(m_hIcon, TRUE); // 設(shè)置大圖標(biāo)
            SetIcon(m_hIcon, FALSE); // 設(shè)置小圖標(biāo)

            …
            // 自定義Button
            m_BtnBegin.InitButton(this, IDC_BUTTON1, IDB_BITMAP_BTNNORMAL, IDB_BITMAP_BTNON, IDB_BITMAP_BTNDOWN);
            m_BtnExit.InitButton(this, IDC_BUTTON2, IDB_BITMAP_BTN_EXIT_NORMAL, IDB_BITMAP_BTN_EXIT_ON, IDB_BITMAP_BTN_EXIT_NORMAL);
            …
            return TRUE; // 除非將焦點(diǎn)設(shè)置到控件,否則返回TRUE
    }

     

            6、在CMyButton的析構(gòu)函數(shù)中釋放圖片資源。

     

    CMyButton::~CMyButton()
    {
            // 釋放個(gè)圖片資源
            if(m_bmpBtnnormal.GetSafeHandle() != NULL)
            {
                    m_bmpBtnnormal.DeleteObject();
            }
            if(m_bmpBtnon.GetSafeHandle() != NULL)
            {
                    m_bmpBtnon.DeleteObject();
            }
            if(m_bmpBtndown.GetSafeHandle() != NULL)
            {
                    m_bmpBtndown.DeleteObject();
            }
    }

     

            7、重寫(xiě)CMyButton的DrawItem方法,實(shí)現(xiàn)自定義按鈕的畫(huà)圖。

     

    void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
            // TODO: 在此添加消息處理程序代碼和/或調(diào)用默認(rèn)值
            BOOL bSelected = FALSE;

            if (lpDrawItemStruct->itemState & ODS_SELECTED)
            {
                    bSelected = TRUE;
            }
            else
            {
                    bSelected = FALSE;
            }

            CDC DC;
            DC.Attach(lpDrawItemStruct->hDC);
            CDC dcMem;
            dcMem.CreateCompatibleDC(&DC);

            CBitmap* pOldBmp = NULL;
            CRect rcItem(lpDrawItemStruct->rcItem);
            BITMAP bp;

            if (bSelected) // 按下鼠標(biāo)時(shí)的狀態(tài)
            {
                    pOldBmp = dcMem.SelectObject(&m_bmpBtndown);
                    m_bmpBtndown.GetBitmap(&bp);
                    DC.BitBlt(0,0,bp.bmWidth, bp.bmHeight,&dcMem,0,0,SRCCOPY);
            }
            else if (m_bTracking) // 鼠標(biāo)置于按鈕上,但未按下
            {
                    pOldBmp = dcMem.SelectObject(&m_bmpBtnon);
                    m_bmpBtnon.GetBitmap(&bp);
                    DC.BitBlt(0,0,bp.bmWidth, bp.bmHeight,&dcMem,0,0,SRCCOPY);
            } 
            else // 鼠標(biāo)未置于按鈕上時(shí)的常態(tài)
            { 
                    pOldBmp = dcMem.SelectObject(&m_bmpBtnnormal);
                    m_bmpBtnnormal.GetBitmap(&bp);
                    DC.BitBlt(0,0,bp.bmWidth,bp.bmHeight,&dcMem,0,0,SRCCOPY);
            }
            dcMem.SelectObject(pOldBmp);
            DC.Detach();
    }

     

            8、修改對(duì)話框的OnCtlColor函數(shù)。

            對(duì)話框重畫(huà)控件前會(huì)先用畫(huà)刷重刷繪圖區(qū)域。默認(rèn)的畫(huà)刷顏色是MFC底色灰色,如不修改,會(huì)有比較明顯的閃爍情況,這里稍作處理,在自定義按鈕重刷時(shí)使用空畫(huà)刷。


    HBRUSH CETA108_TESTDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
    {
            HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
            // TODO: Change any attributes of the DC here
            if (pWnd == this)
            {
                    return brBk;
            }
            else
            {
                    int ID = pWnd->GetDlgCtrlID();
                    if (( ID == IDC_BUTTON1)||(ID == IDC_BUTTON2)) 
                    {
                            return (HBRUSH)GetStockObject(NULL_BRUSH);
                    }
            }
            // TODO: Return a different brush if the default is not desired
            return hbr;
    }

     

            其他自定義控件的實(shí)現(xiàn)方法與按鈕類似,根據(jù)需要,可以實(shí)現(xiàn)自己的ComboBox,ScrollBar,Edit等。

     

            (4)使用GDI畫(huà)波形曲線圖

            實(shí)際應(yīng)用可以根據(jù)程序需求,使用GDI函數(shù)進(jìn)行曲線界面繪制,為了防止界面閃爍,可以先把去曲線圖繪制在內(nèi)存DC中,最后在調(diào)用BitBlt繪制到屏幕上。

            1、.對(duì)話框初始化函數(shù)中建立內(nèi)存位圖。

     

    // 圖片位置,大小
    #define CURVE_BMP_X 42
    #define CURVE_BMP_Y 72
    #define CURVE_BMP_W 520
    #define CURVE_BMP_H 320 // 340減去scrollbar高度

    CDC m_dcMem;
    CBitmap m_bitmap

    BOOL CETA108_TESTDlg::OnInitDialog()
    {
            …
            CDC* pDC = GetDC();
            m_dcMem.CreateCompatibleDC(pDC);
            m_bitmap.CreateCompatibleBitmap(pDC,CURVE_BMP_W,CURVE_BMP_H);
            m_dcMem.SelectObject(&m_bitmap);
            …
            ReleaseDC(pDC);
            …
    }

     

            2、在畫(huà)波形圖函數(shù)DrawCurve中在內(nèi)存DC即 m_dcMem中畫(huà)圖,最后BitBlt到屏幕。

    void CETA108_TESTDlg::DrawCurve()
    {
            int i, ii;
            …
            CBrush brush;
            …
            brush.CreateSolidBrush(COLOR_BK);
            m_dcMem.FillRect(m_rect,&brush);
            brush.DeleteObject();
            …
            // m_dcMem中繪制坐標(biāo)軸,坐標(biāo)線,坐標(biāo)值
            …
            // 從pBuf內(nèi)讀出AD數(shù)據(jù),在m_dcMem中繪制成曲線
            …
            // m_dcMem中繪制一個(gè)圖例框
            …
            CDC *pDC=GetDC();
            pDC->BitBlt(CURVE_BMP_X, CURVE_BMP_Y, CURVE_BMP_W, CURVE_BMP_H, &m_dcMem, 0, 0, SRCCOPY);
            ReleaseDC(pDC);
            return;
    }

     

            3、重寫(xiě)對(duì)話框OnPaint函數(shù)。

    void CETA108_TESTDlg::OnPaint()
    {
            CPaintDC dc(this); // device context for painting
            // TODO: Add your message handler code here

            dc.BitBlt(CURVE_BMP_X, CURVE_BMP_Y, CURVE_BMP_W, CURVE_BMP_H, &m_dcMem, 0, 0, SRCCOPY);
            // Do not call CDialog::OnPaint() for painting messages
    }

     

            4、注意事項(xiàng)

            GDI對(duì)象應(yīng)當(dāng)做到Create和Delete一一對(duì)應(yīng),Get和Release一一對(duì)應(yīng),避免內(nèi)存泄漏。

            當(dāng)SelectObject時(shí)最好記錄函數(shù)返回的原對(duì)象值,然后在繪圖完畢后還原。

            在DrawText繪制文字前應(yīng)當(dāng)先設(shè)置文字背景為透明,即SetBkMode(TRANSPARENT) 。

     

            (5)浮動(dòng)信息框?qū)崿F(xiàn)

            當(dāng)鼠標(biāo)在曲線圖上移動(dòng)到坐標(biāo)點(diǎn)附件時(shí),顯示一個(gè)浮動(dòng)的信息框。

            可以再建一個(gè)內(nèi)存DC,設(shè)置它的位圖大小為浮動(dòng)信息框所占大小。當(dāng)需要畫(huà)信息框時(shí),先將屏幕DC的位圖BitBlt到信息框DC內(nèi),并記錄相應(yīng)的坐標(biāo)點(diǎn)。

            當(dāng)信息框移動(dòng)或改變后,先將信息框DC的備份內(nèi)容還原到屏幕DC中,備份新的位置的位圖,然后記錄新坐標(biāo)點(diǎn),再在新的位置繪制信息框。

            為了避免快速度移動(dòng)的重畫(huà)導(dǎo)致屏幕閃爍,可以先在一個(gè)另外的內(nèi)存DC中畫(huà)好,再BitBlt到屏幕上。

     

            詳細(xì)完整的代碼請(qǐng)參考英創(chuàng)產(chǎn)品光盤(pán)中的ETA108波形采集顯示例程。

    99热这里只有精品免费播放| 日韩精品无码成人专区| 好湿好大硬得深一点动态图91精品福利一区二区| 久久久久久影院久久久久免费精品国产小说 | 国产精品兄妹在线观看麻豆| 亚洲精品国产首次亮相| 久9热免费精品视频在线观看| 精品人妻人人做人人爽夜夜爽| 亚洲国产精品yw在线观看| 日韩制服国产精品一区| 国产亚洲美女精品久久久久| 精品人妻系列无码一区二区三区| 91精品视频网站| 国产精品日本亚洲777| 999久久久免费精品国产| 柠檬福利精品视频导航| 国产av无码专区亚洲国产精品| 九九热在线视频精品| 精品无码久久久久久尤物| 国产在线精品一区二区夜色| 国产四虎精品8848hh| 久热爱精品视频在线 | 最新国产精品剧情在线SS| 一本大道久久a久久精品综合| 99re这里只有精品6| 亚洲精品久久久www | 久久99国产精品| 亚洲午夜国产精品无码老牛影视| 亚洲А∨精品天堂在线| 国产精品成人自拍| 国产乱码精品一区二区三区香蕉 | 亚洲精品中文字幕无乱码麻豆| 老司机69精品成免费视频| 精品国产91久久久久久久a| 精品无码av无码专区| 国产精品爆乳在线播放第一人称| 精品麻豆国产色欲色欲色欲www| 色播精品免费小视频| 亚洲国产福利精品一区二区| 999精品久久久中文字幕蜜桃| 久久99九九99九九精品|