<span style="font-size:18px;">
</span>
<span style="font-size:18px;">
</span>
<span style="font-size:18px;">知识点补充:
1、指向常量的指针:char ch[5] = "list"; const char* pStr = ch;
pStr指向的内容不可改变,pStr的指针值可以改变:
*pStr = 'w';//error pStr = "vector";//ok
2、指针常量:char ch[5] = "list"; char* const pStr = ch;
指针本身是常量,指向的内容可以修改,指针值不可修改:
pStr = "love";//error *pStr = 'w';//ok
/***********************************************************************************************/
当按照文本方式向文件中写入数据时,若遇到换行字符(ASCII为10),会转换为回车换行(ASCII为13,10)。在读取文件时,若遇到
回车换行的组合(即连续的ASCII 13、10),则会转换为换行字符(ASCII为10)。//以文本方式写入和以二进制方式读会差一个字符:
当以二进制方式向文件中写入数据时,将数据在内存中的存储形式原样输出到文件中.所以读取写入数据的方式应该一致.
//C、C++、MFC读写文件及MFC打开保存文件对话框:
void CFileView::OnFileWrite()
{
/* FILE *pFile=fopen("1.txt","w");//c语言使用了缓冲文件系统
fwrite("file",1,strlen("file"),pFile);//写入了缓冲区中,缓冲区满后才写/读入磁盘文件
//fseek(pFile,0,SEEK_SET); //将文件内部指针移到文件开始位置
//fwrite("ftp:",1,strlen("ftp:"),pFile);
//fwrite("file",1,strlen("file"),pFile);
fclose(pFile);*/ //将缓冲区中的数据写入磁盘文件
//fflush(pFile); //刷新缓冲区,把数据写入文件,而不必关闭文件
/* FILE *pFile=fopen("2.txt","wb");//以二进制方式打开
char ch[3];
ch[0]='a';
ch[1]=10; //换行(存放的是ASCII)
ch[2]='b';
fwrite(ch,1,3,pFile);
fclose(pFile);*/
/*FILE *pFile=fopen("3.txt","w");
int i=98341;//将98341以整数方式写入?打开时显示98341
char ch[5];*/
/*ch[0]=9+48;//法一:以ASCII形式写入,和内存一致
ch[1]=8+48;
ch[2]=3+48;
ch[3]=4+48;
ch[4]=1+48;*/
/*itoa(i,ch,10);//法二:将数字转换为字符串写入
//fwrite(&i,4,1,pFile);
fwrite(ch,1,5,pFile);
fclose(pFile);*/
/* ofstream ofs("4.txt"); //C++语法,需包含头文件
ofs.write("file",strlen("file"));
ofs.close(); */
/* HANDLE hFile;
hFile=CreateFile("5.txt",GENERIC_WRITE,0,NULL,CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,NULL); //win32 AIP函数
DWORD dwWrites;
WriteFile(hFile,"file",strlen("file"),
&dwWrites,NULL); //写文件
CloseHandle(hFile); */
/* CFile file("6.txt",CFile::modeCreate | CFile::modeWrite); //MFC提供
file.Write("file",strlen("file"));
file.Close();*/
CFileDialog fileDlg(FALSE);
fileDlg.m_ofn.lpstrTitle="我的文件保存对话框";
fileDlg.m_ofn.lpstrFilter="Text Files(*.txt)\0*.txt\0All Files(*.*)\0*.*\0\0";
fileDlg.m_ofn.lpstrDefExt="txt";
if(IDOK==fileDlg.DoModal())
{
CFile file(fileDlg.GetFileName(),CFile::modeCreate | CFile::modeWrite);
file.Write("file",strlen("file"));
file.Close();
}
}
void CFileView::OnFileRead()
{
/* FILE *pFile=fopen("1.txt","r");//以文本方式打开
// char ch[100];
// memset(ch,0,100);
// fread(ch,1,100,pFile);
// MessageBox(ch);
char *pBuf;
fseek(pFile,0,SEEK_END); //文件内部指针移到文件结尾
int len=ftell(pFile); //得到文件内部指针的当前位置
pBuf=new char[len+1];
rewind(pFile); //重新放置文件内部指针到文件开始处
fread(pBuf,1,len,pFile);
pBuf[len]=0;
MessageBox(pBuf);
fclose(pFile); */
/* FILE *pFile=fopen("2.txt","rb");//以二进制方式打开
char ch[100];
fread(ch,1,3,pFile);
ch[3]=0;
MessageBox(ch);
fclose(pFile); */
/* ifstream ifs("4.txt"); //C++语法,需包含头文件
char ch[100];
memset(ch,0,100);
ifs.read(ch,100);
ifs.close();
MessageBox(ch); */
/* HANDLE hFile;
hFile=CreateFile("5.txt",GENERIC_READ,0,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL); //win32 API函数
char ch[100];
DWORD dwReads;
ReadFile(hFile,ch,100,&dwReads,NULL); //读文件
ch[dwReads]=0;
CloseHandle(hFile); //关闭文件句柄
MessageBox(ch); */
/* CFile file("6.txt",CFile::modeRead); //MFC提供
char *pBuf;
DWORD dwFileLen;
dwFileLen=file.GetLength();
pBuf=new char[dwFileLen+1];
pBuf[dwFileLen]=0;
file.Read(pBuf,dwFileLen);
file.Close();
MessageBox(pBuf); */
CFileDialog fileDlg(TRUE);
fileDlg.m_ofn.lpstrTitle="我的文件打开对话框";
fileDlg.m_ofn.lpstrFilter="Text Files(*.txt)\0*.txt\0All Files(*.*)\0*.*\0\0";
if(IDOK==fileDlg.DoModal())
{
CFile file(fileDlg.GetFileName(),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);
}
}
/***********************************************************************************************/
//兼容16位版本,存储信息在WIN.INI文件中(InitInstance中添加):
/* ::WriteProfileString("love","admin","zhangsan");//表项,键名,值
CString str;
::GetProfileString("love","admin","lisi",
str.GetBuffer(100),100); //若修改字符串,之后需调用ReleaseBuffer
AfxMessageBox(str); */
/* WriteProfileString("love","admin","zhangsan"); //写入的是注册表中(App继承的)
CString str;
str=GetProfileString("love","admin");
AfxMessageBox(str); */
//读写注册表:
void CFileView::OnRegWrite() //写注册表
{
HKEY hKey;
DWORD dwAge=20;
RegCreateKey(HKEY_LOCAL_MACHINE,"Software\\http://www.kai.org\\admin",&hKey); //创建注册表项,若存在,打开
RegSetValue(hKey,NULL,REG_SZ,"zhangsan",strlen("zhangsan"));//存储字符串类型
RegSetValueEx(hKey,"age",0,REG_DWORD,(CONST BYTE*)&dwAge,4);//存储其他类型
RegCloseKey(hKey);
}
void CFileView::OnRegRead() //读注册表
{
/* LONG lValue;
RegQueryValue(HKEY_LOCAL_MACHINE,"Software\\http://www.kai.org\\admin",
NULL,&lValue); //LPTSTR置为NULL,得到数据长度存在lValue(包含终止的空字符)中
char *pBuf=new char[lValue];
RegQueryValue(HKEY_LOCAL_MACHINE,"Software\\http://www.kai.org\\admin",
pBuf,&lValue);
MessageBox(pBuf);*/
HKEY hKey;
RegOpenKey(HKEY_LOCAL_MACHINE,"Software\\http://www.kai.org\\admin",&hKey);//打开注册表项
DWORD dwType;
DWORD dwValue;
DWORD dwAge;
RegQueryValueEx(hKey,"age",0,&dwType,(LPBYTE)&dwAge,&dwValue);//dwType:返回的数据类型
CString str;
str.Format("age=%d",dwAge);
MessageBox(str);
}
/***********************************************************************************************/
文档串行化(CArchive,之前必须创建一个CFile对象):
//CArchive不仅可以处理基本类型,还可以处理CObject派生类
void CGraphic1View::OnArchive()
{
CFile file("1.txt",CFile::modeCreate | CFile::modeWrite);
CArchive ar(&file,CArchive::store);
int i = 4;
char ch = 'a';
float f = 1.3f;
CString str("zhangyue");
ar << i << ch << f << str;
}
void CGraphic1View::OnRead()
{
CFile file("1.txt",CFile::modeRead);
CArchive ar(&file,CArchive::load);
int i;
char ch;
float f = 0.0;
CString str;
CString strResult;
ar >> i >> ch >> f >> str; //保存时是什么顺序,提取时也要是这个顺序
strResult.Format("%d,%c,%f,%s",i,ch,f,str);
MessageBox(strResult);
}
///
给文档添加标题:
法一:BOOL CGraphic1Doc::OnNewDocument(){ //文件-新建 会调用此函数.
if (!CDocument::OnNewDocument())
return FALSE;
SetTitle("love");//在此设置文档标题
return TRUE;
}//( CWinApp::OnFileNew(); CDocManager::OnFileNew()...)文档框架视图对象三位一体,都会创建
法二:在资源视图的String Table中的IDR_MAINFRAME的Caption中的第二个项输入标题名.
//那么,资源视图中的字符创、菜单、图标等资源何时加入程序中了呢?
//在App类的InitInstance()函数中,有下面所示代码,将文档框架视图关联在一起:
CSingleDocTemplate* pDocTemplate; //构造了一个单文档模板对象
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME, //资源ID(包含多种资源)
RUNTIME_CLASS(CGraphic1Doc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CGraphic1View));
AddDocTemplate(pDocTemplate);
//对于IDR_MAINFRAME资源中的各个子串,可以利用CDocTemplate::GetDocString来获取:
virtual BOOL GetDocString(
CString& rString,
enum DocStringIndex index
) const;
CDocTemplate::windowTitle //主窗口标题栏上的字符串;MDI不需指定,将一IDR_MAINFRAME串为默认值
CDocTemplate::docName //缺省文档名,若没有指定,将为无标题
CDocTemplate::fileNewName //文档类型的名称,若应用程序支持多种类型文档(增加另一个模板对象在InitInstance中),
//此串将显示在File/New对话框中
CDocTemplate::filterName //出现在File/Open对话框中,要和filterExt一起使用
CDocTemplate::filterExt //文档缺省扩展名,若没有指定,就不能出现在打开对话框中,和filterName一起使用
CDocTemplate::regFileTypeId
CDocTemplate::regFileTypeName
///
在Doc类中有个函数:Serialize(CArchive &ar);
void CGraphic1Doc::Serialize(CArchive& ar) //文件-打开/保存对话框关闭后会调用此函数
{
if (ar.IsStoring()){ // TODO: add storing code here
int i = 4;
char ch = 'a';
float f = 1.3f;
CString str("zhangyue");
ar << i << ch << f << str;
}
else{ // TODO: add loading code here
int i;
char ch;
float f = 0.0;
CString str;
CString strResult;
ar >> i >> ch >> f >> str; //保存时是什么顺序,提取时也要是这个顺序
strResult.Format("%d,%c,%f,%s",i,ch,f,str);
AfxMessageBox(strResult);//不是从CWnd派生的,用应用程序框架的函数
}
}
///
创建一个串行化的类(支持串行化)需要5个步骤:
1、让你的类从CObject(或其派生类)中派生
2、重载Serialize成员函数
3、在类声明中使用DECLARE_SERIAL(类名)宏
4、添加一个不带参数的构造函数
5、INPLEMENT_SERIAL(类名,基类名,1)//1:版本号
//CDocument::GetFirstViewPosition(),GetNextView();
有关文件读写的操作在CDocument的Serialize函数中进行,有关数据和图形的显示在CView的OnDraw函数中进行;
在其派生类中,只需要去关注Serialize和OnDraw函数就可以了,其他细节不需要理会。
当按下File/Open,应用程序框架会激活文件打开对话框,让你指定文件名,然后自动调用CGraphicDoc::Serialize
读取文件;应用程序框架还会调用CGraphicView::OnDraw,传递一个DC,让你重新绘制窗口内容。
一个文档对象可以和多个视类对象相关联,而一个视类对象只能和一个文档对象相关联。
eg:
class CGraph:public CObject{.....}
void CGraph::Serialize(CArchive& ar) //支持串行化的5个步骤
{
if(ar.IsStoring())
{
ar<<m_nDrawType<<m_ptOrigin<<m_ptEnd;
}
else
{
ar>>m_nDrawType>>m_ptOrigin>>m_ptEnd;
}
}
CGraph::CGraph(UINT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd) //绘图类的构造函数存储绘图的必要东西
{
this->m_nDrawType=m_nDrawType;
this->m_ptOrigin=m_ptOrigin;
this->m_ptEnd=m_ptEnd;
}
void CGraph::Draw(CDC *pDC) //绘图类的窗口重绘函数
{
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CBrush *pOldBrush=pDC->SelectObject(pBrush);
switch(m_nDrawType)
{
case 1:
pDC->SetPixel(m_ptEnd,RGB(0,0,0));
break;
case 2:
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(m_ptEnd);
break;
case 3:
pDC->Rectangle(CRect(m_ptOrigin,m_ptEnd));
break;
case 4:
pDC->Ellipse(CRect(m_ptOrigin,m_ptEnd));
break;
}
pDC->SelectObject(pOldBrush);
}
void CGraphicDoc::Serialize(CArchive& ar) // 文档类的Serialize函数
{
POSITION pos=GetFirstViewPosition();
CGraphicView *pView=(CGraphicView*)GetNextView(pos);
if (ar.IsStoring()){ // TODO: add storing code here
/* int nCount=pView->m_obArray.GetSize();
ar<<nCount; //要存储在CObArray中的绘图种类
for(int i=0;i<nCount;i++)
{
ar<<pView->m_obArray.GetAt(i);
} */
}
else{ // TODO: add loading code here
/* int nCount;
ar>>nCount;
CGraph *pGraph;
for(int i=0;i<nCount;i++)
{
ar>>pGraph;
pView->m_obArray.Add(pGraph);
}
} */
m_obArray.Serialize(ar); //CObArray(其实是内部成员)也支持串行化
}
CGraphicDoc* CGraphicView::GetDocument(){...} //MFC提供
void CGraphicView::OnDraw(CDC* pDC) //View类的重绘函数
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
int nCount;
nCount=pDoc->m_obArray.GetSize();
for(int i=0;i<nCount;i++)
{
((CGraph*)m_obArray.GetAt(i))->Draw(pDC);
}
}
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point) //绘制完毕,把图形保存在CObArray中
{
CClientDC dc(this);
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
dc.SelectObject(pBrush);
switch(m_nDrawType)
{
case 1:
dc.SetPixel(point,RGB(0,0,0));
break;
case 2:
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
break;
case 3:
dc.Rectangle(CRect(m_ptOrigin,point));
break;
case 4:
dc.Ellipse(CRect(m_ptOrigin,point));
break;
}
CGraph *pGraph=new CGraph(m_nDrawType,m_ptOrigin,point); //把绘制图形的必备变量传给CGraph类
CGraphicDoc *pDoc=GetDocument(); //利用MFC框架得到文档类
pDoc->m_obArray.Add(pGraph);
CView::OnLButtonUp(nFlags, point);
} //pGraph指针没有释放!看后面的CGraphicDoc::DeleteContents函数
void CGraphicView::OnDraw(CDC* pDC) //View类的窗口重绘函数
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
int nCount;
nCount=pDoc->m_obArray.GetSize();
for(int i=0;i<nCount;i++)
{
((CGraph*)pDoc->m_obArray.GetAt(i))->Draw(pDC);
}
}
//文件打开和新建都会调用此函数,所以在此释放在堆上申请的内存
void CGraphicDoc::DeleteContents() //虚函数,不会消除CDocument自身
{
int nCount;
nCount=m_obArray.GetSize();
/*for(int i=0;i<nCount;i++)
{
delete m_obArray.GetAt(i);
//m_obArray.RemoveAt(i);
}//RemoveAt下移所有被移除元素上面的元素,并递减上界,但不释放内存
m_obArray.RemoveAll();*/
while(nCount--) //!!!!!!
{
delete m_obArray.GetAt(nCount);//只删了内存,没有删除指针自身
m_obArray.RemoveAt(nCount);
}
CDocument::DeleteContents();
}
</span>