《VC++深入详解–学习笔记》(13)文档与串行化

Filed Under (VC++ 学习笔记) by panmaoru on 17-12-2009

本章首先介绍了一种新的读写文件方式,使用MFC提供的CArchive类来实现。可以利用CArchive类将对象数据保存到永久设备上。这样即使应用程序关闭,再次启动后仍然可以从磁盘上读取对象数据,然后在内存中重构相应的对象。让数据持久性的过程成为串行化或序列化。

CArchive对象不仅可以处理基本类型的数据,还可以处理CObject类的派生对象。CArchive类重载了提取(>>)和插入(<<)操作符。通过这些重载的函数,可以利用CArchive对象完成对文件的读写操作。

CArchive构造函数的声明如下:

CArchive( CFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf = NULL );

pFile:指向文件对象的指针,该文件对象是持久数据的来源或目的地;

nMode:文件对象的标示符(load,store)读取还是存储;

CArchive类写入数据的实例:

void CFileView::OnFileWrite()
{
       CFile file(\"7.txt\",CFile::modeCreate|CFile::modeWrite);
       CArchive ar(&file,CArchive::store);
       int i=1;
       char ch='1';
       float f=1.3f;
       CString str=\"www.colsir.com\";
       ar<<i<<ch<<f<<str;
}

完成写入操作之后,用记事本打开7.txt,发现基本上都是乱码。这是因为CArchive对象是一种二进制流。

CArchive类读取数据的实例:

void CFileView::OnFileRead()
{
       CFile file(\"7.txt\",CFile::modeRead);
       CArchive ar(&file,CArchive::load);
       int i;
       char ch;
       float f;
       CString str;
       CString strResult;
       ar>>i>>ch>>f>>str;
       strResult.Format(\"%d,%c,%f,%s\",i,ch,f,str);
       MessageBox(strResult);
}

对象读取的顺序必须和保存的顺序一致,有些搞不懂,那CArchive类还有什么优势?暂时理解不了。

MFC新建,保存文件时的格式过滤

在字符串表中一个ID为IDR_MAINFRAME的行,用来实现一些初始值的设置。该项的值的优先级低于OnNewDocument函数中的设置。通过查看OnNewDocument函数的申明,可以看到OnNewDocument函数是一个虚函数。

文档串行化

Serialize?看了半天没看懂什么意思。这两天心情有点浮躁,先平静下再补充。

《VC++深入详解–学习笔记》(12)文件和注册表操作

Filed Under (VC++ 学习笔记) by panmaoru on 16-12-2009

很多与文件操作相关的函数其参数类型都是const char*,本章首先介绍指向常量的指针const char*和指针常量char *const这两种类型的区别。

12.1char const * 和char * const

char const * p;
const char * p;
char * const p;

这三个有什么不同?const char * p;和char const * p;在实现上都是一样的,定义一个指向常量的指针,由于指针指向的是一个常量,常量的值不能改变,但是可以改变指针的指向。char * const p;这是一个指针常量,也就是指针的指向不能改变,但是可以改变指针指向的值。区别指针常量和常量指针的关键看const 和* 的位置。

12.2C语言对文件操作的支持

C语言中,对文件的操作是利用FILE结构体实现的。

12.2.1文件的打开

MSDN中有一个fopen函数:

FILE *fopen( const char *filename, const char *mode );

其中的第一个参数是要打开的文件名称,第二个参数是打开的模式。MSDN中对打开文件的模式进行了如下的定义:

r 为读取而打开,如果文件不存在或者不能找到,函数调用失败
w 为写入文件而打开一个空文件,如果文件已经存在,怎清空内容
a 为写入打开一个文件,如果文件存在,则在尾部添加新数据,在写入之前,不会清除文件中已经有的EOF标记,如果文件不存在,新建一个文件
r+ 打开文档用户写入操作和读取操作,文件必须存在
w+ 为写入操作和读取操作打开一个空的文件,如果给定的文件已经存在,则清空内容
a+ 打开文件用于读取和添加操作,在写入之前移除文件已有的EOF标记,写入之后再恢复EOF标记,如果指定文件不存在,那么先创建这个文件

打开一个文件的实例代码如下:

FILE *pFile=fopen(“1.txt”,”w”);//该操作返回一个FILE类型的指针

12.2.2文件的写入

size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

文件写入有四个参数,分别表示:要写入的数据,以字节为单位的项的大小,写入项的最大数目,指向FILE类型的指针,该参数可以由fopen函数获取到,也就是fopen函数的返回值。写入文件的实例代码如下:

fwrite(\"new buffer\",1,strlen(\"new buffer\"),pFile);

由于C语言对文件操作采用缓存文件系统,从内存从磁盘写入的文件首先会被放到内存缓冲区中,只有当内存缓冲区满了或者当写入操作的文件关闭之后,才把要写入的数据存的磁盘文件上。如果要在执行写操作之后立即将数据存放到磁盘文件上,可以先调用fflush函数刷新缓冲区或者调用fclose函数将打开的文件关闭。

12.2.3文件指针的定位

int fseek( FILE *stream, long offset, int origin );

该函数的第三个参数有三种默认的值,SEEK_CUR,SEEK_END,SEEK_SET,实际上是三个宏定义值,在STDIO.h文件中可以看到它们的值分别是1,2,0。分别表示定位到文件的当前位置,结束位置和开始位置。

fseek(pFile,0,SEEK_SET);
fwrite(\"haha\",1,strlen(\"haha\"),pFile);

将指针定位到已经打开的文件的其实位置,并写入新的数据。完成此操作时候会发现文件中起始位置的四个字符已经被替换掉了。尝试了下改变文件的打开模式,但是都不能实现a+b的效果。

12.2.3文件的读取

size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

由于C语言中字符串是以”\0”符号结束的。在显示字符串的时候,系统会寻找”\0”字符,因此在写入数据的时候需要在结尾添加一个”\0”,在读取数据的时候,可以动态创建一个数据长度+1的字符数组,然后将最后一个元素设置为”\0”。

写入文件时:

void CFileView::OnFileRead()
{
       // TODO: Add your command handler code here
       FILE *pFile=fopen(\"1.txt\",\"w\");
       //fwrite(\"new buffer\",1,strlen(\"new buffer\"),pFile);
       char buf[22]=\"www.colsir.com\";
       buf[21]='\0';
       fwrite(buf,1,22,pFile);
       fclose(pFile);
}

读取文件时:

void CFileView::OnFileWrite()
{
       // TODO: Add your command handler code here
       FILE *pFile=fopen(\"1.txt\",\"r\");
       char *pbuf;
       fseek(pFile,0,SEEK_END); //为了获取数据的长度,将指针指向文件的末尾
       int len=ftell(pFile);
       pbuf =new char[len+1];
       //rewind(pFile); //下同fseek(pFile,0,SEEK_SET);
       fseek(pFile,0,SEEK_SET); //读取数据前,需要将指针再指回起始位置
       fread(pbuf,1,len,pFile);
       pbuf [len]='\0';
       fclose(pFile);
       MessageBox(pbuf);
}

12.2.3二进制文件和文本文件

字太多,有点啰嗦,不写了,慢慢体会。

12.3C++对文件操作的支持

void CFileView::OnFileWrite()//写入
{
       ofstream ofs(\"3.txt\");
       ofs.write(\"www.colsir.com\",strlen(\"www.colsir.com\"));
       ofs.close();
}
void CFileView::OnFileRead() //读取
{
       // TODO: Add your command handler code here
       ifstream ifs(\"3.txt\");
       char buf[100];
       memset(buf,0,100);
       ifs.read(buf,100);
       ifs.close();
       MessageBox(buf);
}

12.4Win32 API对文件操作的支持

void CFileView::OnFileWrite()//写入
{
       HANDLE hFile;
       hFile=CreateFile(\"4.txt\",GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
       DWORD dwWrites;
       WriteFile(hFile,\"www.colsir.com\",strlen(\"www.colsir.com\"),&dwWrites,NULL);
       CloseHandle(hFile);
}
void CFileView::OnFileRead()//读取
{
       // TODO: Add your command handler code here
       HANDLE hFile;
       hFile=CreateFile(\"4.txt\",GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
       char buf[100];
       DWORD dwWrites;
       ReadFile(hFile,buf,100,&dwWrites,NULL);
       buf[dwWrites]=0;
       CloseHandle(hFile);
       MessageBox(buf);
}

12.5MFC对文件操作的支持

MFC中提供的支持文件操作的基类是:CFile,该类提供了没有缓存的二进制格式的磁盘文件输入输出功能,通过其派生类能够间接的支持文本文件和内存文件。

利用MFC的CFile类实现文件写入操作:

void CFileView::OnFileWrite()
{
       CFile file(\"5.txt\",CFile::modeCreate|CFile::modeWrite);
       file.Write(\"www.colsir.com\",strlen(\"www.colsir.com\"));
       file.Close();
}

利用MFC的CFile类实现文件读取操作:

void CFileView::OnFileRead()
{
       CFile file(\"5.txt\",CFile::modeRead);
       char *pBuf;
       DWORD dwFileLen;
       dwFileLen=file.GetLength();
       pBuf=new char[dwFileLen+1];
       pBuf[dwFileLen]=0;
       file.Read(pBuf,dwFileLen);
       file.Close();
       MessageBox(pBuf);
}

12.5注册表操作

注册表存储在二进制文件中,Win32 API提供了大量的函数以便应用程序访问注册表。

1、  创建键:RegCreateKey

2、  打开键:RegOpenKey

3、  写入注册表:RegSetValue(默认REG_SZ类型),RegSetValueEx(其他类型)

4、  由注册表中读数据:RegQueryValue(默认REG_SZ类型),RegQueryValue Ex(其他类型)

void CFileView::OnRegWrite()
{
       HKEY hKey;
       RegCreateKey(HKEY_LOCAL_MACHINE,\"SoftWare\\www.colsir.com\\admin\",&hKey);
       RegSetValue(hKey,NULL,REG_SZ,\"pan\",strlen(\"pan\"));
       RegCloseKey(hKey);
}
void CFileView::OnRegRead()
{
       LONG lValue;
       RegQueryValue(HKEY_LOCAL_MACHINE,\"SoftWare\\www.colsir.com\\admin\",NULL,&lValue);
       char *pBuf=new char[lValue];
       RegQueryValue(HKEY_LOCAL_MACHINE,\"SoftWare\\www.colsir.com\\admin\",pBuf,&lValue);
       MessageBox(pBuf);
}

《VC++深入详解–学习笔记》(11)绘图的保存与重绘

Filed Under (VC++ 学习笔记) by panmaoru on 16-12-2009

看了书本上的内容,太多啰嗦,没耐心看,先放过,等兴趣来了再整理吧。

《VC++深入详解–学习笔记》(10)绘图控制

Filed Under (VC++ 学习笔记) by panmaoru on 15-12-2009

在软件的运行过程中,用户可以根据软件提供的设置对话框,颜色对话框和字体对话框等用户接口来对软件进行制定。本章主要介绍对图形绘制的制定,此外,也介绍了如何获取对话框的返回值。

10.1获取一个对话框的返回值

创建一个Setting对话框,在View类中添加Commad消息响应函数。然后再Setting对话框类中添加一个public变量m_nWidth。
在View中添加一个变量m_nWidth1,然后就可以设置和获取对话框的变量值了。

//#include \"SettingDlg.h\"
void CGraphicView::OnSetting()
{
	// TODO: Add your command handler code here
	CSettingDlg dlg;
	dlg.m_nWidth=m_nWidth1;
	if(IDOK==dlg.DoModal())
	{
		m_nWidth1=dlg.m_nWidth;
	}
}

10.2获取颜色对话框的值

MFC为我们提供了一个颜色对话框类CColorDialog,可以在View类中直接创建该类对象。为了设置和获取颜色对话框的RGB默认值,需要在View类中建一个COLORREF类型变量。

void CGraphicView::OnColor()
{
	// TODO: Add your command handler code here
	CColorDialog dlg;
	dlg.m_cc.rgbResult=m_ccr;// m_cc为一个COLORREF变量
	dlg.m_cc.Flags|=CC_RGBINIT;
	if(IDOK==dlg.DoModal())
	{
		m_ccr=dlg.m_cc.rgbResult;
	}
}

10.3获取字体对话框的值

MFC同样为我们提供了一个字体对话框类CFontDialog,可以在View类中直接创建该类对象。为了获取字体对话框的值,需要在View类中建一个CFont类型变量。

void CGraphicView::OnFont()
{
	// TODO: Add your command handler code here
	CFontDialog dlg;
	if(IDOK==dlg.DoModal())
	{
		// m_font为一个CFont变量
		if(m_font.m_hObject)// 判断m_font是否已经和某个字体资源相关联了
			m_font.DeleteObject();//如果已经关联,删除关联资源
		m_font.CreateFontIndirect(dlg.m_cf.lpLogFont);
		m_strFontName=dlg.m_cf.lpLogFont->lfFaceName;
	}
}

10.4绘图

设置绘图的一些参数之后,便可以开始实现绘图。将设置的一些参数选择到画笔,并完成相应的图像绘制。

void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
   CClientDC dc(this);
   CPen pen(m_nLineStyle,m_nWidth,m_ccr);
   dc.SelectObject(&pen);
   CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//透明画刷
   dc.SelectObject(pBrush);
   //画点
   dc.SetPixel(point,m_ccr);
   //画线
   dc.MoveTo(m_pOrigin);
   dc.LineTo(point);
   //画矩形
   dc.Rectangle(CRect(m_pOrigin,point));
    //画椭圆
   dc.Ellipse(CRect(m_pOrigin,point));
}

《VC++深入详解–学习笔记》(9)定制应用程序外观

Filed Under (VC++ 学习笔记) by panmaoru on 14-12-2009

本章主要讲解如何修改MFC AppWizard自动生成的应用程序的外观,包括工具栏和状态栏的变成。

9.1在窗口创建之前修改

第三章介绍了一些MFC AppWizard应用程序的执行流程,如果要在窗口创建之前修改应用程序的外观,可以再MainFrame类的PreCreateWindow()函数中修改窗口的外观属性。

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
//  the CREATESTRUCT cs
cs.cx=800;
cs.cy=500;
cs.style&=~FWS_ADDTOTITLE;
cs.lpszName=\"www\";
return TRUE;
}

由于MFC应用程序的View类是覆盖在Frame类之上的,在此处对外观做的修改将只显示在Frame类部分。如窗口的大小,标题。

一个MFC单文档应用程序窗口的默认窗口样式是WS_OVERLAPPEDWINDOW和WS_ADDTOTITLE,要去掉其中的一种样式,可以对其做取反操作。

cs.style=cs.style&~WS_ADDTOTITLE;

或者直接设置窗口的样式

cs.style=WS_OVERLAPPEDWINDOW;

9.2在窗口创建之后修改

在窗口创建之后修改窗口的样式,在Create函数中执行。在Create函数中调用SetWindowLong函数。

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//。。。
SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW);
SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR));
}

9.3动态加载Icon

如果要设置窗口的Icon为系统提供的格式,可以通过SetClassLong来实现,如果要动态的加载一个自定义的Icon,首先需要在Frame类的头文件中创建一个HICON类型的变量。

HICON m_icon;可以同时加载多个文件,则需要创建的HICON数组HICON m_iconl[],

然后调用LoadIcon函数。

hicon[0]=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));
hicon[1]=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON2));

书中给出了三种加载icon文件的方法,选择一个自己看着顺眼的方式。加载Icon文件之后,设置窗口的icon:

SetClassLong(m_hWnd,GCL_HICON,(LONG)hicon[0]);

9.4设置定时器

SetTimer函数属于标准消息,在Frame类上右键,可以看到所有的标准消息。

void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
static int index=0;
index=++index%4;
CFrameWnd::OnTimer(nIDEvent);
}

这里有2个概念,一是创建一个静态变量的时候,在内存区域的全局对象与静态变量区域分派内存,只会创建一次。二是如果要在一个循环中将值限定在一个范围之内,可以将循环值和这个值取模。

创建一个定时器之后,需要在OnCreate函数中添加定时器的响应。在MSDN中可以看到SetTimer函数的说明:

UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );

SetTimer函数的返回值也即是函数的编号(第一个参数),第二个参数为定时器的响应时间,以毫秒为单位,第三个参数通常设置为NULL,具体为什么,没看懂。

SetTimer(1,1000,NULL);

9.5创建进度条

MFC中,有一个CProgressCtrl的类,如果要创建一个进度条,首先需要创建一个CProgressCtrl类的对象,然后调用Create成员函数来创建。MSDN中给出了一个相关的实例程序:

CProgressCtrl myCtrl;
// Create a smooth child progress control.
myCtrl.Create(WS_CHILD|WS_VISIBLE|PBS_SMOOTH, CRect(10,10,200,30),
pParentWnd, 1);

如何要在状态栏中创建一个进度条?

状态栏属于框架类,在状态栏中创建进度条,首先同样需要获取创建的区域。这之前需要String表中添加进度条的字串。然后将字串ID添加到

static UINT indicators[] =
{
ID_SEPARATOR,           // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
IDS_PROGRESS,//用来显示进度条区域
};

为了获取进度条所处于的区域,可以调用GetItemRect函数。

void GetItemRect(index,LPRECT lprect) const;其中第一个参数为状态栏中网格的在indicators[]中的索引号。由于OnCreate函数实际上是响应的WM_ OnCreate函数,只有在这个函数完成之后才能获取到状态栏的矩形区域。因此需要在此处添加一个消息响应函数,等窗口创建完成之后,发送生成进度条消息。

MFC的每个标准消息都有一个消息编号,要创新一个新的消息,首先要创建消息编号。

1、 在Frame的头文件中添加一个消息标识宏#define UM_PROGRESS WM_USER+1;

2、 按照标准消息的格式和流程,分别在头文件和源文件中添加消息映射

头文件:

//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnPaint();
afx_msg void OnProgress();//消息
//}}AFX_MSG

源文件:

//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_TIMER()
ON_WM_PAINT()
ON_MESSAGE(UM_PROGRESS,OnProgress) //消息
//}}AFX_MSG_MAP

3、 在源文件中添加消息响应函数

void CMainFrame::OnProgress()
{
CRect rect;
m_wndStatusBar.GetItemRect(5,&rect);
m_cpc.Create(WS_CHILD|WS_VISIBLE|PBS_SMOOTH,rect,&m_wndStatusBar,123);
m_cpc.SetPos(50);
}

4、 在源文件的OnCreate函数中添加PostMessage(UM_PROGRESS);

这样便可以在状态栏动态创建一个进度条。这里有个一SendMessage函数和PostMessage函数的区别说明:

1、 SendMessage:直接把消息发送给消息响应函数,等消息响应函数处理完之后再返回。

2、 PostMessage:把消息发送到消息队列,然后立即返回。

由于OnProgress函数需要在OnCreate执行完之后再响应,因此此处采用PostMessage函数来发送该消息。

创建进度条完成之后,显示正常,但是如果此时拉动窗口,改变大小,会发现进度条的位置不正确了,为了保证进度条的位置正确,需要添加OnPaint函数。

void CMainFrame::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CRect rect;
m_wndStatusBar.GetItemRect(5,&rect);
if(!m_cpc.m_hWnd)
{
m_cpc.Create(WS_CHILD|WS_VISIBLE|PBS_SMOOTH,rect,&m_wndStatusBar,123);
}
else
{
m_cpc.MoveWindow(rect);
}
m_cpc.SetPos(50);
// Do not call CFrameWnd::OnPaint() for painting messages
}

因此WM_PAINT消息是自动执行的,这样就不需要在OnCreate函数中再添加PostMessage函数来发送消息了。

完成进度条的创建之后,可以再OnTimer函数中添加代码,实现进度条的动态效果,代码就不贴上来了,都是调用相关函数来实现。

9.5在状态栏上显示鼠标

在View类上添加WM_MOUEOVER函数:

void CStyleView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CString str;
str.Format(\"x=%d y=%d\",point.x,point.y);
((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);
CView::OnMouseMove(nFlags, point);
}

这之前需要在View类中引入Frame类的头文件,并将Frame类的m_wndStatusBar设置为public.

《VC++深入详解–学习笔记》(8)对话框2

Filed Under (VC++ 学习笔记) by panmaoru on 13-12-2009

本章节继续讲解对话框的有关知识,以及属性表单和向导的创建。

8.1属性表单和向导的创建

一个属性表单是由一个或者多个属性页组成的。要创建一个属性表单,首先要创建一个CPropertySheet属性页和几个IDD_PROPPAGE_类型的选项页,创建页面完成之后。在PropertySheet类页面添加需要引入选项页的头文件,同时创建该类的对象,并调用AddPage函数,将选项页添加到属性表单中。

1、  添加头文件 #include “head.h”;

2、  创建该类的对象 head head1;

3、  将对象添加到属性列表中 AddPage(&head1)。

当添加多个选项页的时候,最后显示的顺序和添加的顺序一致。

如果要显示一个属性表单,可以通过调用模态对话框的形式显示。比如说一个按钮事件:

void CMenuListDlg::OnButton1()
{
       // TODO: Add your control notification handler code here
       CPropSheet cps(\"list\");
       //cps.SetWizardMode();//设置表单显示方式
       cps.DoModal()
}

在创建一个属性表单对象的时候,必须初始化对象的一个名称参数。

8.2属性向导的按钮属性

当把一个属性表单的导航设置为上一步,下一步的浏览方式的时候,需要对当前选项卡下的导航做一些设置,如第一个页面不需要上一步,最后一个页面不需要下一步。要设置这些按钮的显示属性,可以通过SetWizardButtons函数来设置这些按钮的显示属性。

SetWizardButtons( DWORD dwFlags );

在属性表单的选择过程中,当一个页面变成活动页的时候,应用程序就会调用该选项卡的OnSetActive()函数,也就是可以在这个时候设置按钮属性。要在一个选项卡的中访问父框架,可以使用GetParent()来获取父框架指针,可以需要对返回的指针做一个强制转化为CPropertySheeet类型的。设置顶一个活动页的按钮属性为。

BOOL CProp1::OnSetActive()
{
       // TODO: Add your specialized code here and/or call the base class
       ((CPropertySheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);
       return CPropertyPage::OnSetActive();
}

由于在第一个页面设置了父框架的按钮属性,在之后的每一个页面都要做对应本页面的属性设置。

在设置了按钮的显示属性之后,可以同时添加按钮的响应事件。

LRESULT CProp1::OnWizardNext()
{
       // TODO: Add your specialized code here and/or call the base class
       UpdateData();//需要更新一下数据
       if(判断事件)
       {
              //响应结果
              return -1;
       }
       return CPropertyPage::OnWizardNext();
}

在执行判断事件之前,需要先更新下页面上的一些操作而引发的一些初始数据的变化(如选择框的选择等等)。

8.3属性表单数据的动态添加和获取

对于一些输入框,文本框,可以通过SetDlgItemText等函数来动态设置值,这里需要主要在获取这些对象的时候,有些可能需要做指针的类型转换。对于一些列表控件(CListBox,CComboBox,CToolBarBox),可以通过AddString函数来动态添加列表的值。

       ((CListBox*)GetDlgItem(IDC_LIST2))->AddString(\"1\");
       ((CListBox*)GetDlgItem(IDC_LIST2))->AddString(\"2\");
       ((CListBox*)GetDlgItem(IDC_LIST2))->AddString(\"3\");
       ((CListBox*)GetDlgItem(IDC_LIST2))->AddString(\"4\");

这些动态数据的创建在下面2个函数中都可以完成,在2个函数中都做了下测试,显示方面都是正常的,OnSetActive和OnInitDialog,从2个函数的定义上来看,还是OnInitDialog更合适些。

要获取属性表单的数据,需要记清楚一个概念:当一个DoModal函数返回之后,对话框窗口就被销毁了,但是窗口类的对象并没有消失,因此任然何以用这个窗口类的对象去访问它的数据成员。

访问方式如下

CPropSheet cps(\"list\");
cps.SetWizardMode();
if(ID_WIZFINISH==cps.DoModal())
{
       m_iin=cps.m_prop1.m_iint;
       Invalidate();//让类视图无效,引发重绘操作
}

好了,数据已经获取到了,可以执行相应的操作了。