用VC5開發監控介面的方法 (轉)

worldblog發表於2007-12-06
用VC5開發監控介面的方法 (轉)[@more@]  用VC5開發介面的方法

南京師範大學物理系 (伶俐 黃斌 顧敏芬)

VC5開發工具提供了現成的視窗、控制與工具條的製作手段,大大簡化了介面的開發
過程,並且使得開發出的介面具有組態風格,使用起來方便、靈活、簡單易學。

本文以一例項介紹如何實現三個獨立的分離視窗:監視視窗,控制視窗和動畫視窗,
並以圖1中的進水和溫度值傳遞為例,介紹如何實現控制功能和不同視窗間的資料共享,
並介紹實現無閃爍動畫的方法。
  (圖略)

如圖1,將工作臺分離成為三個視窗,動畫視窗用於模擬鍋爐的進、出水、升溫的畫
面顯示,其中的畫面與採集的資料相對應。控制視窗用於實現預設溫度值,調節水位、
控制加熱、暫停等功能。監視視窗用來實時跟蹤取樣的溫度值,作出溫度--時間曲線。

  一、創立分離視窗

要實現多視窗顯示,必須使用CSplitterWnd類,將視窗分成三個子視窗,然後將各個
功能類與視窗聯絡起來。在建立應用時,在第一步中選擇Single Document Interface, 並
選用中文字型檔,在第4步中按下Advanced,選擇Use Split Window選項。設定應用程式名
為Animation。目前我們只有一個視類CAnimationView,它將與動畫視窗對應,此外我們
還要生成具有對話功能的監視視窗(對應CShowView類)和控制視窗(對應 CControlView
類)。在Re View中調出上下文選單並選擇Insert,選擇屬性為IDD_FORMVIEW,創
建監視對話方塊IDD_SHOWVIEW和控制對話方塊IDD_CONTROLVIEW,並單擊滑鼠右鍵在
Properties選擇項中選擇中文字型檔。然後編輯IDD_CONTROLVIEW:利用VC5提供的
生成器生成ID名為IDC_SETTEMPERATURE的文字編輯域,並生成Caption為“設定溫
度初始值”。再利用button生成器,生成控制元件IDC_WATERIN,IDC_CONFIRM,Caption
分別為“進水”和“確認”。再利用ClassWizard,建立基於CFormView類的新類,分別為
CShowView和CControlView類,並將它們與剛建立的兩個對話方塊聯絡。

  在CMainFrame類中,過載OnCreateClient()建立三個靜態分離視窗,先在
MainFrame.h中宣告所需變數:

protected:
  CSplitterWnd   m_wndSplitter2;
轉入MainFrame.cpp程式,在開頭處包含頭“ShowView.h”,向下找到函式
OnCreateClient(),新增如下程式碼,生成兩個視窗,三個檢視:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT/*lpcs*/,CCreateContext* pContext)
{
  //先分裂成兩個視窗,一行兩列
  if(!m_wndSplitter.CreateStatic(this,1,2))
  {
  TRACE0("Failed to CreateStaticSplittern");
  return FALSE;
  }
 
  // 加上動畫視窗,將其放在左邊
  if(!m_wndSplitter.CreateView(0,0,pContext->m_pNewViewClass,CSize(425,50),pContext))
  {
  TRACE0("Failed to create first panen");
  return FALSE;
  }

  //將第二個視窗再一分為二
  if(!m_wndSplitter2.CreateStatic(
  &m_wndSplitter, //原來的m_wndSplitter是父指標,m_wndSplitter2是子指標
  2,1, //視窗分為兩行,一列
  WS_CHILD|WS_VISIBLE|WS_BORDER,m_wndSplitter.IdFromRowCol(0,1)))
  {
  TRACE0("Failed to create nested splittern");
  return FALSE;
  }
 
  //增加兩個檢視,並調整檢視大小
  if(!m_wndSplitter2.CreateView(0,0,
  RUNTIME_CLASS(CShowView),CSize(0,175),pContext))
  {
  TRACE0("Failed to create second panen");
  return FALSE;
  }
 
  if(!m_wndSplitter2.CreateView(1,0,RUNTIME_CLASS(CControlView),
CSize(0,0),pContext))
  {
  TRACE0("Failed to create third panen");
  return FALSE;
  }
  return TRUE;
}

再轉入Animation.cpp中,修改InitInstance()函式,將其中的m_pMainWnd->ShowWindow
(SW_SHOW),改為m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);至此,我們
可以生成圖1的介面。

  二、動畫顯示視窗的實現

  動畫是透過一幅幅的圖片來實現的,因此先將所需的畫面載入資源BITMAP中,
並按順序編輯它們的ID號,然後在定時器中,每隔一定的時間呼叫一次動畫函式。第一
步先生成定時器,用ClassWizard給CAnimationView新增訊息處理程式:OnCreate()函式
對應於訊息WM_CREATE,OnTimer()函式對應於訊息WM_TIMER。編輯函式OnCreate(),
生成每隔0.1秒的時鐘。

int CAnimationView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  if(CView::OnCreate(lpCreateStruct)= = -1)
return -1;
  SetTimer(2,100,NULL); //產生每隔0.1秒的時鐘
  return 0;
}
  在函式OnTimer()中,呼叫動畫服務函式ServicedAnimation(),該函式根據系統情況作出
無閃爍動畫,並可以根據不同的功能,選擇畫面。
void CAnimationView::OnTimer(UINT nvent)
{
  CClientDC ClientDC(this);
  ServicedAnimation(&ClientDC); //呼叫動畫服務函式
  CView::OnTimer(nIDEvent);
}
  ServicedAnimation()用於檢查系統的時鐘,並能計算從發生最後一個動畫事件開始計算
起所經過的時間,然後這個函式檢查本幀動畫的延遲時間,並決定是否到達了另一次
的時間,若到了另一次更新的時間,那麼m_nCurrentFrame變數就增加,此時若進水標誌
成功,則呼叫DrawWaterinAnimation(),開始新一幀動畫畫面。如果由於其它原因造成了
到達ServicedAnimation()函式的延遲也計算在內。
  先在CAnimationView中,定義變數:
public:
  D   mLastEventServiced;
  BOOL  m_bPause, m_bDone; //暫停、動畫終點標誌
  int   m_nCurrentFrame, m_nFrame; //當前的動畫幀數,總動畫幀數
  建構函式中,新增:
CAnimationView::CAnimationView()
{
  mLastEventServiced=0;
  m_bPause=FALSE;
  m_bDone=FALSE;
  m_nCurrentFrame=0;
  m_nFrame=100; //圖畫的幀數設為100幅
}
  編輯ServicedAnimation()函式:
void CAnimationView::ServicedAnimation(CDC* pDC)
{
  DWORD Elapsed=0L;
  DWORD FirstSample=::GetTickCount();
  DWORD WorkValue=mLastEventServiced;
  CAnimationDoc *pDoc=(CAnimationDoc*) GetDocument();
  ASSERT(pDoc->IsKindOf(TUNTIME_CLASS(CAnimationDoc)));

  if(m_bPause||m_bDone) return; //如果動畫被暫停或結束,就返回
  while(FirstSample!=WorkValue)
  {
  WorkValue++;
  Elapsed++;
  }
  //如果Elapsed達到其閾值點,並滿足或超過這幀動畫的延遲值,則可進入下一個程式碼
  //資訊塊,這樣,動畫順序將移動到下一幀:
  if(Elapsed>=1L) //設定每幀動畫的延遲值都為1
  {
  m_nCurrentFrame++;
  if(m_nCurrentFrame>=m_nFrame)
  {
  m_nCurrentFrame=0; //將要開始時,應把幀記數置於零
  if(!pDoc->m_bWaterInFlagDoc)
  {
  m_nCurrentFrame=m_nFrame-1;
  m_bDone=TRUE;
  }
  if(pDoc->m_bWaterInFlagDoc&&!m_bDone)
  {
  DrawAnimationWaterIn(pDC);
  m_bWaterInFlagDoc=FALSE;
  mLastEventServicced=::GetTickCount(); // 把系統當前的時鐘記錄下來
  }
  }
  }


DrawAnimationWaterIn()為顯示不同的進水水位的畫面的函式,要連續顯示畫面,應將
一幅幅點陣圖宣告成一個靜態陣列。

Static int bitmapswaterin[]= {I_WATERIN1,
IDB_WATERIN2 ...... IDB_WATERIN100};

  利用ClassWizard宣告CAnimationView的變數:
protected:
  CBitmap  bmpWI[100];
  CDC  dcMemWI[100];
  BITMAP  bmWI;
  在CAnimationView的建構函式里新增如下語句:
for(int i=0;i<100;i++)
{
  bmpWI[i].LoadBitmap(bitmapswaterin[i]);
  bmpWI[i].Get(sizeof(BITMAP),&bmWI[i]);
}

  編輯DrawAnimationWaterIn()函式,在此函式中,應重新宣告bmpWI[100],dcMemWI[100]
為區域性變數,這樣當重新呼叫同一幅點陣圖時,可以及時重新整理,不會引起衝突。
void CAnimationView: DrawAnimationWaterIn(CDC* pDC)
{
  CBITMAP bmpWI[100];
  CDC dcMemWI[100];
  CRect rect;
  GetClientRect(rect); //選擇當前使用的矩形視窗
  dcMemWI[m_nCurrentFrame].CreateCompatibleDC(pDC); //在記憶體中準備圖象
  bmpWI[m_nCurrentFrame].LoadBitmap(bitmapsWaterIn[m_nCurrentFrame]);// 裝載一個
  //由lpszResourcceName標識的點陣圖資源,並將它連線到CBitmap上
  CBitmap *pOldBitmn=dcMemWI[m_nCurrentFrame].Object
(&bmpWI[m_nCurrentFrame] ); //將GDI物件選入裝置描述表
  pDC->BitBlt((recct.right-bmWI[m_nCurrentFrame].bmWidth)/2,
  (rect.bottom-bmWI[m_nCurrentFrame].bmHeight)/2,//點陣圖放在視窗正中
  bmWI[m_nCurrentFrame].bmWidth,bmWI[m_nCurrentFrame].bmHeight,
  &dcMemWI[m_nCurrentFrame],0,0,SRCCOPY);//顯示點陣圖
  dcMemWI[m_nCurrentFrame].SelectObject(pOldBitmapIn);
}


  三、控制視窗功能的實現


  利用ClassWizard中的Member Variables標籤為CControlView增加成員變數。
  控制元件
  控制元件ID
  型別
  成員
  預設溫度值
  IDC_SETTEMPERATURE
  int
  m_nSetTemperature
  在CControlView中增加訊息處理函式:
  物件
  物件ID
  函式
  訊息
  進水按鍵
  IDC_WATERIN
  OnWaterIn()
  BN_CLICKED
  確認按鍵
  IDC_CONFIRM
  OnComfirm()
  BN_CLICKED

  下面以輸入預設溫度值和進水響應為例,來講述如何實現控制功能。當控制視窗
(CControlView類)中預置溫度設定之後,按下確認鍵即響應訊息OnConfirm(),在監視視窗
(CShowView類)中的狀態監測圖中畫一條預設溫度的橫線。當控制視窗(CControlView
類)中按下進水鍵,便在動畫檢視(CAnimationView類)有進水動畫產生。

  這時控制檢視要向監視檢視、動畫檢視傳送資料,但它們之間無法直接實現資料共享。
MFC類庫中CDocument類及其派生類用來管理工作資料,它能夠讀寫和檢視所要觀
察和處理的資料,並可以同時擁有多個檢視。所以,此處用CDocument的派生類
CAnimationDoc作為資料傳輸的中介,來實現不同視窗之間的資料傳遞。
  預置溫度(變數名為m_nSetTemperature)的資料傳送示意圖如圖2所示。


m_nSetTemperature m_nSetTemperatureDoc


 

圖2 省略

  在CAnimationDoc中,設定公共變數:
public:
  int  m_nSetTemperatureDoc; //用來傳遞m_nSetTemperature的Document派生類變數
  BOOL m_bSetTemperatureFlagDoc; //溫度設定成功標誌
  BOOL m_bWaterInFlagDoc; //進水標誌
 
  在CAnimationDoc的建構函式中初始化變數:
CAnimationDoc::CAnimationDoc()
{
  m_nSetTemperatureDoc=0;
  m_bSetTemperatureFlagDoc=FALSE;
  m_bWaterInFlagDoc=FALSE;
}
  編輯CControlView的OnConfirm()函式:
void CControlView::OnConfirm()
{
  CAnimationDoc* pDoc=(CAnimationDoc*) GetDocument();
  ASSERT(pDoc->IsKindOf(RUNTIME_CLASS(CAnimationDoc)));//找到當前的  
  //CDocument類
  UpdateData(); //更新檢視資料
  pDoc->m_nSetTemperatureDoc=m_nSetTemperature;
  pDoc->m_bSetTemperatureFlagDoc=TRUE; //預設溫度成功標誌
}
  編輯CControlView的OnWaterIn()函式:
void CControlView::OnWater()
{
  CAnimationDoc*pDoc=(CAnimationDoc*)GetDocument();
  ASSERT(pDoc->IsKindOf(RUNTIME_CLASS(CAnimationDoc)));
  pDoc->m_bWaterInFlagDoc=TRUE; //進水響應成功
}
  最後在ControlView.cpp的開頭包含“AnimationDoc.h"。
然後轉入CShowView中,為了要能達到實時監測的目的,資料的接收要做在定時器中,這
樣才可以不斷地檢測是否有新的資料輸入。檢測到溫度設定標誌後,畫一條橫線。
void CShowView::OnTimer(UINT nIDEvent)
{
  CClientDC dc(this);
  CAnimationDoc*pDoc=(CAnimationDoc*)GetDocument();
  ASSERT(pDoc->IsKindOf(RUNTIME_CLASS(CAnimationDoc)));
  UpdateData();
  If(pDoc->m_bSetTemperatureFlagDoc)
  {
  dc.MoveTo(0,145-pDoc->m_nSetTemperatureDoc);
  dc.Lo(400,145-pDoc->m_nSetTemperatureDoc); //畫一條橫線
  pDoc->m_bSetTemperatureFlagDoc=FALSE; //保證只做一次
  }
  CFormView::OnTimer(nIDEvent);
}
  同樣,在CAnimationView中,編輯OnTimer()函式呼叫的過程ServicedAnimation(),檢
測到進水鍵響應成功後,呼叫進水動畫例程DrawAnimationWaterIn()。
 

  四、監視視窗功能的實現

  溫度、水位跟蹤實現的原理類似於控制功能,它實現的是CAnimatinDoc與CShowView
類之間的資料傳遞,當系統取樣的溫度與水位變化時,CShowView中的m_nTemperature(溫
度變數)即隨之變化,在利用MoveTo()與LineTo()函式,便可將其畫在圖上。再把這些做
在定時器當中,就可以實時監測。

參考文獻:
1、《Visual C++5開發人員指南》David Bennett機械工業出版社
2、《Visual C++4開發人員指南》tt Stanfield機械工業出版社
3、《MFC開發人員參考手冊》 Robert D. Thompson機械工業出版社


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988833/,如需轉載,請註明出處,否則將追究法律責任。

相關文章