分享
 
 
 

用VC5开发监控界面的方法

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

用VC5开发监控界面的方法

南京师范大学物理系 (伶俐 黄斌 顾敏芬)

VC5开发工具提供了现成的窗口、控制与工具条的制作手段,大大简化了界面的开发

过程,并且使得开发出的界面具有组态软件风格,使用起来方便、灵活、简单易学。

本文以一实例介绍如何实现三个独立的分离窗口:监视窗口,控制窗口和动画窗口,

并以图1中的进水和温度值传递为例,介绍如何实现控制功能和不同窗口间的数据共享,

并介绍实现无闪烁动画的方法。

(图略)

如图1,将工作台分离成为三个窗口,动画窗口用于模拟锅炉的进、出水、升温的画

面显示,其中的画面与系统采集的数据相对应。控制窗口用于实现预设温度值,调节水位、

控制加热、暂停等功能。监视窗口用来实时跟踪采样的温度值,作出温度--时间曲线。

一、创立分离窗口

要实现多窗口显示,必须使用CSplitterWnd类,将窗口分成三个子窗口,然后将各个

功能类与窗口联系起来。在创建应用程序时,在第一步中选择Single Document Interface, 并

选用中文字库,在第4步中按下Advanced,选择Use Split Window选项。设定应用程序名

为Animation。目前我们只有一个视类CAnimationView,它将与动画窗口对应,此外我们

还要生成具有对话功能的监视窗口(对应CShowView类)和控制窗口(对应 CControlView

类)。在Resource 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 CreateStaticSplitter\n");

return FALSE;

}

// 加上动画窗口,将其放在左边

if(!m_wndSplitter.CreateView(0,0,pContext->m_pNewViewClass,CSize(425,50),pContext))

{

TRACE0("Failed to create first pane\n");

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 splitter\n");

return FALSE;

}

//增加两个视图,并调整视图大小

if(!m_wndSplitter2.CreateView(0,0,

RUNTIME_CLASS(CShowView),CSize(0,175),pContext))

{

TRACE0("Failed to create second pane\n");

return FALSE;

}

if(!m_wndSplitter2.CreateView(1,0,RUNTIME_CLASS(CControlView),

CSize(0,0),pContext))

{

TRACE0("Failed to create third pane\n");

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 nIDEvent)

{

CClientDC ClientDC(this);

ServicedAnimation(&ClientDC); //调用动画服务函数

CView::OnTimer(nIDEvent);

}

ServicedAnimation()用于检查系统的时钟,并能计算从发生最后一个动画事件开始计算

起所经过的时间,然后这个函数检查本帧动画的延迟时间,并决定是否到达了另一次更新

的时间,若到了另一次更新的时间,那么m_nCurrentFrame变量就增加,此时若进水标志

成功,则调用DrawWaterinAnimation(),开始新一帧动画画面。如果由于其它原因造成了

到达ServicedAnimation()函数的延迟也计算在内。

先在CAnimationView中,定义变量:

public:

DWORD 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[]= {IDB_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].GetObject(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 *pOldBitmapIn=dcMemWI[m_nCurrentFrame].SelectObject

(&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.LineTo(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开发人员指南》Scott Stanfield机械工业出版社

3、《MFC开发人员参考手册》 Robert D. Thompson机械工业出版社

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有