vc++深入详解学习笔记_第1页
vc++深入详解学习笔记_第2页
vc++深入详解学习笔记_第3页
vc++深入详解学习笔记_第4页
vc++深入详解学习笔记_第5页
已阅读5页,还剩63页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

学习笔记 在程序运行时,当对话框及其子控件创建完成将要显示之前发送一个 WM_INITDIALOG 因此在此消息响应函数中修改编辑框的串口过程。 比如设置焦点 WM_CTLCOLOR 消息:在一个子控件绘制时,会向父窗口发送此消息,来准备设备上下 文,以便使用正确的的颜色来绘制该控件 响应函数:OnCtlColor 包含 pDC 指针:绘制控件上下文 当前指针 pWnd 和一个要绘制的控件类型。 其值返回到画刷 10.7 位图的显示 1. 创建位图 2. 创建兼容 DC 3. 将位图选入兼容 DC 4. 将兼容 DC 中的位图贴到当前 DC 中 当擦除窗口时消息:WM_ERASRBKGND OnEraseBkgnd(CDC* pDC) BOOL CMoniView:OnEraseBkgnd(CDC* pDC) / TODO: Add your message handler code here and/or call default CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); CDC dcCompatible; dcCompatible.CreateCompatibleDC(pDC); /创建一个和 pDC 指向 DC 兼容 DC, dcCompatible.SelectObject( CRect rect; GetClientRect( pDC-BitBlt(0,0,rect.Width(),rect.Height(), return CView:OnEraseBkgnd(pDC); 然而,BitBlt 是 1:1 复制的 此时就需要另外一个复制函数 StretchBIt BITMAP bmp; bitmap. GetBitmap ( 在构建好 bitmap 后用 GetBitmap 函数来获取其结构体 BITMAP 对象 bmp 的值。 并使用到 StretchBIt 来表明对象的宽和高 实现代码: pDC- StretchBlt(0,0,rect.Width(),rect.Height(), 本例子在擦除窗口的时候来完成的 也可以用视类提供的类似 WM_PAINT 消 息响应函数的 OnDraw 函数在窗口重绘的时候来完成。 11 图形的保存和重绘 WIN32 应用程序编程接口 (API) 四种坐标系: 1 世界坐标空间 2 页面空间 以上是逻辑空间,用世界坐标来完成旋转,斜切或者反射 3 设备空间 4 物理设备空间 物理设备随(:打印机,显示器)设置尺寸而变化 当应用程序调用 SetWorldTransform 1 -2-3-4(多为屏幕) 在实际编程中主要是从页面空间开始 页面空间到设备空间的转换,所用的是两个矩形的宽高比例 从窗口原点到视口原点的转换 设备空间到物理空间转换只用于平移,而这是由 Windows 控制的 只需要考虑从页面空间到设备空间的转换 Windows 对所有消息,所有非 GDI 函数和一些 GDI 函数 永远使用设备坐标 映射模式 默认为像素模式 MM_TEXT 可以用 SetMapMode 来改变模式 逻辑坐标和设备坐标 而在事件 如 鼠标单击中是以设备坐标为单位 即为像素为单位的值 CDC 中提供 2 个成员函数:SetViewportOrg 和 SetWindowOrg 对于重绘 图形 只需要在 OnDraw 函数中 利用结构体来保存 起点 终点 和绘制类型就可以重绘了 创建结构体后 我们可以用数组来保存这些创建的对象了 但是数组对象有个缺点就是只能存储一定的容量的元素 而每次绘制的图形个数是不定的 因此要采用动态的存储结构来保存这些对象 如链表 集合类: CString 的集合类 CStringArray 容量是可以动态增加的 CPtrArray 支持 void 类型的指针数组,void *,任何类型的指针都能够直接赋值给他,无 需进行强制类型转换: 为什么设置开关后会要先点一下才能使用铅笔工具 因为事件是在 mouse down 的时候开始的 当 mouse up 中 case 5 运行时 才调用 mousemove 函数。 因此要循环中的 case5 要在 mouse down 判断。 关于连续线的重绘 分析:画直线 设置一个点变量,当发生 mouse down 的时候 记录变量值 = 当前鼠标所点的坐标值 当发生 mouse up 的时候 首先移动到这个变量的点 然后画线 到 当前鼠标的点 画不规则线 设置一个点变量,当发生 mouse down 的时候 记录变量值 = 当前鼠标所点的坐标值 在 mouse move 的事件中 dc.MoveTo(m_ptOrigin); dc.LineTo(point) 不停地画直线并 m_ptOrigin=point; 将远不停变化 这和画多个矩形一样,点一样 还需要一个结构体类来保存改变量。 结构体参数完成以后考虑如何调用这个保存结构体 因为是在 mousemove 事件中完成的 所以我们在此函数中完成 保存结构体 以下是编写的可以进行矩形,点,直线,以及任意线的重绘的代码 for(int i=0;im_nDrawType) case 1: pDC-SetPixel(CGraph*)m_ptrArray.GetAt(i)-m_ptEnd,RGB(0,0,0); break; case 2: pDC-MoveTo(CGraph*)m_ptrArray.GetAt(i)-m_ptOrigin); pDC-LineTo(CGraph*)m_ptrArray.GetAt(i)-m_ptEnd); break; case 3: pDC-Rectangle(CRect(CGraph*)m_ptrArray.GetAt(i)- m_ptOrigin,(CGraph*)m_ptrArray.GetAt(i)-m_ptEnd); break; case 4: pDC-Ellipse(CRect(CGraph*)m_ptrArray.GetAt(i)- m_ptOrigin,(CGraph*)m_ptrArray.GetAt(i)-m_ptEnd); break; / TODO: add draw code for native data here for(int y=0;ym_nDrawType = 5) /此处要判断一下函数,否则将会造成死循环,另只要注意在结构体中保存了点的坐标就 可以完成任意线的绘制了 pDC-MoveTo(CLineh*)m_ptrArray1.GetAt(y)-m_ptOrigin); pDC-LineTo(CLineh*)m_ptrArray1.GetAt(y)-m_ptEnd); 总结: 先尝试用开关来完成鼠标按下时绘制连续线 这个有个关键点在此函数中设置判断语句来用 bool 型变量 开关 来控制 mousemove 函数中绘线语句 if(m_Ben = TRUE) /m_nDrawType = 5;因为这个变量的值只能唯一,当按下铅 笔按钮时 就已经赋值给 m_nDrawType 了 dc.MoveTo(m_ptOrigin); dc.LineTo(point); CLineh *plineh=new CLineh(m_nDrawType,m_ptOrigin,point); m_ptrArray1.Add(plineh); m_ptOrigin=point; 另在 CGraph 中我们只保存了一维数组 我们也可以将 CLINE 结构体写入 CGrpah 中来用一个语句完成操作 但是结构体必须要保存 2 个 使用兼容设备描述表 利用兼容 DC 来实现图形的保存和重绘 首先 创建一个兼容 DC 对象 void CDCclientView:OnLButtonUp(UINT nFlags, CPoint point) / TODO: Add your message handler code here and/or call default CClientDC dc(this); CPen pen(0,1,RGB(0,0,255); dc.SelectObject( CBrush *pBrush =CBrush:FromHandle(HBRUSH)GetStockObject(NULL_BRUSH); dc.SelectObject(pBrush); if(!m_dcCompatible.m_hDC) m_dcCompatible.CreateCompatibleDC( CRect rect; GetClientRect( CBitmap bitmap; bitmap.CreateCompatibleBitmap( m_dcCompatible.SelectObject( m_dcCompatible.SelectObject(pBrush); m_dcCompatible.SelectObject( m_dcCompatible.BitBlt(0,0,rect.Width(),rect.Height(), switch(m_type) case 1: dc.SetPixel(point,RGB(0,255,255); m_dcCompatible.SetPixel(point,RGB(0,255,255); break; case 2: dc.MoveTo(Startpoint); dc.LineTo(point); m_dcCompatible.MoveTo(Startpoint); m_dcCompatible.LineTo(point); break; case 3: dc.Rectangle(CRect(Startpoint,point); m_dcCompatible.Rectangle(CRect(Startpoint,point); break; case 4: dc.Ellipse(CRect(Startpoint,point); m_dcCompatible.Ellipse(CRect(Startpoint,point); break; CView:OnLButtonUp(nFlags, point); 注意 首先创建一个兼容 DC,用 IF 语句使之不能重复创建。将 DC 的地址指向此兼容 DC 2因为不是调用现有的的位图 必然要创建一个兼容位图,获取当前窗口的大小创建该位 图 将位图地址笔刷写入 兼容设备描述表 ,但此时只包含位图的信息头而没有保存颜色表和 像素块。 所以在调用 BitBlt 复制像素块到兼容设备描述表中 并且将所用绘制的方法也写入兼容设备描述表中 然后调用重绘 CRect rect; GetClientRect( pDC-BitBlt(0,0,rect.Width(),rect.Height(), 将位图重新绘制到当前 DC 中。 文件和注册表操作 常量指针: Const char* 常量指针不能修改其内存内容,但是可以修改其指向的内存地址。 指针常量: Char * const 指针常量不能修改其指向的地址,但是可以修改其指向内容 两个指针都要在定义的时候赋值。 在 C 语言中文件的操作是利用 file 结构体完成的。 利用 fopen 函数返回一个指向 FILE 的指针 FILE *fopen( const char *filename, const char *mode ); 指向文件名的常量指针,指向文件打开的模式的常量指针 FILE *pFile = fopen(“1.txt“,“w“); fwrite(““,1,strlen(““),pFile); w 为写操作打开一个文件 ,如果给定文件以存在 则清空 具体使用表见 P438 如果写入后想立即看到数据 可以用 fclose 关闭文件表示写操作以完成。这是会把缓冲区 的内容写入磁盘。 fclose(pFile); 但一旦调用 FCLOSE 函数 再次访问就必须重新打开文件 可以使用 FFLUSH 函数 fflush(pFile); fflush 函数来刷新缓冲区数据。这样就可以不必要不停的先关闭文件再写入磁盘文件 、 文件定位指针 对于 C 语言来说 它有一个文件指针,会占据写入数据占用的下一个位置。 如果需要文件指针移动到指定的位置 需要使用 fseek 函数来实现 SEEK_CUR/ 当前位置 SEEK_END/ 结尾位置 SEEK_SET/ 开始位置 FILE *pFile = fopen(“2.txt“,“w“); char ch3; ch0 = a; ch1 = 10; ch2 =b; fwrite(ch,1,3,pFile); fclose(pFile); FILE *pFile = fopen(“2.txt“,“r“); char ch100; fread(ch,1,3,pFile); ch3=0; fclose(pFile); MessageBox(ch); 文件分为 二进制文件和文本文件 给你一个整数 98341 写入文本文件中,打开文件显示 98341 FILE *pFile = fopen(“3.txt“,“w“); char buf6 = “98314“; buf5=0; fwrite(buf,1,6,pFile); fclose(pFile); 这么写是不对的 因为给的是整数 而不是字符; FILE *pFile = fopen(“3.txt“,“w“); int i = 98314; fwrite( fclose(pFile); 打开后乱码 因为显示的时候是 5 个字符 使用 ITOA 函数对此整型转化为字符型 FILE *pFile = fopen(“3.txt“,“w“); int i = 98314; char ch5; itoa(i,ch,10); fwrite(ch,1,5,pFile); fclose(pFile); 12.3 c+对文件操作的支持 Ofstream 读操作 ifstream ifs(“4.txt“); char ch100; memset(ch,0,100); ifs.read(ch,100); ifs.close(); MessageBox(ch); 写操作 ofstream ofs(“4.txt“); ofs.write(“http:/www.sunxin,org“,strlen(“http:/www.sunxin,org“); ofs.close(); 12.4 win32 api 对文件操作的支持 文件的创建或者打开 1 文件 2 管道 3 邮槽 4 通信资源 5 磁盘设备 6 控制台 7 目录(只适用打开操作) HANDLE CreateFile( LPCTSTR lpFileName, / file name DWORD dwDesiredAccess, / access mode DWORD dwShareMode, / share mode LPSECURITY_ATTRIBUTES lpSecurityAttributes, / SD DWORD dwCreationDisposition, / how to create DWORD dwFlagsAndAttributes, / file attributes HANDLE hTemplateFile / handle to template file ); 文件的写入 HANDLE hFile; hFile = CreateFile(“5.txt“,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL, NULL); DWORD dwWrites; WriteFile(hFile,““,strlen(““), CloseHandle(hFile); 文件的读取 HANDLE hFile; hFile = CreateFile(“5.txt“,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMA L,NULL); char ch100; DWORD dwReads; ReadFile(hFile,ch,100, chdwReads=0; CloseHandle(hFile); MessageBox(ch); 在这个可以看到 WriteFile 和 ReadFile 最后一个 lpOverlapped 指针都为空 如果要这个指针 有效地话必须在文件的创建方式 FLAG 中设置为 FILE_FLAG_OVERLAPPED 否则将同步运行 不会中断 不会返回错误标示。 12.4 MFC 对文件操作的支持 MFC 的特点就是 CFile 基类 该类不使用二进制格式的文件输入输入功能,间接的支持文本文件和内存文件 读: char *pBuf; DWORD dwFileLen; dwFileLen=file.GetLength(); pBuf=new chardwFileLen+1; pBufdwFileLen=0; file.Read(pBuf,dwFileLen); file.Close(); MessageBox(pBuf); 在读操作时分配一个堆内存。 写:CFile file(“6.txt“,CFile:modeCreate | CFile:modeWrite); file.Write(““,strlen(““); file.Close(); 现在总结 C : 建立一个指向 fopen 的指针,使用 fwrite ,fread, fclose 来操作 C+:使用 fstream.h 头文件 使用 ofstream ifstream 来建立对象,使用 write read close 方 法来进行操作 API: 使用 CreateFile 建立文件句柄使用 WriteFile ReadFile CloseHandle(hFile) ,相对来说使用到多个参数值。更加复 杂和强大。 MFC 使用 CFile 类,建立类对象 write read close 方法来进 行操作,但因为不使用缓冲区所以要分配堆内存。可以看 到 MFC 的方法是最方便的。因此利用 MFC 编程,最好使 用 CFile 类来完成 CFileDialog CFileDialog fileDlg(FALSE); fileDlg.DoModal(); fileDlg.m_ofn.lpstrTitle=“测试“; fileDlg.m_ofn.lpstrFilter=“Text Files(0*.txt)0All Files(*.*)0*.*00“; 仔细分析此代码发现 fileDlg 为 FALSE 是另存为 这个不是不能更改标题的原因 仔细分析发现在建立对话框以后再进行设置,所以导致不 能正常运行的原因。故更改代码 CFileDialog CFileDialog fileDlg(FALSE); fileDlg.m_ofn.lpstrTitle=“测试“; fileDlg.m_ofn.lpstrFilter=“Text Files(0*.txt)0All Files(*.*)0*.*00“; fileDlg.DoModal(); 发现可以了但是选择里看不到 TXT 文件。 修改代码: fileDlg.m_ofn.lpstrFilter=“Text Files(*.txt)0*.txt0All Files(*.*)0*.*00“; 再字符串前+0/ 在设置好选择地字符串后再填上红字内容连续两个00 字符结尾。 fileDlg.m_ofn.lpstrDefExt=“txt“;/设置默认格式 设置另存为 写入文本 if(IDOK=fileDlg.DoModal() CFile file(fileDlg.GetFileName(),CFile:modeCreate | CFile:modeWrite); file.Write(““,strlen(““); file.Close(); 设置读取操作 CFileDialog fileDlg(TRUE); fileDlg.m_ofn.lpstrTitle=“测试“; fileDlg.m_ofn.lpstrFilter=“Text Files(*.txt)0*.txt0All Files(*.*)0*.*00“; fileDlg.m_ofn.lpstrDefExt=“txt“;/设置默认格式 if(IDOK=fileDlg.DoModal() CFile file(fileDlg.GetFileName(),CFile:modeRead); char *pBuf; DWORD dwFileLen; dwFileLen=file.GetLength(); pBuf=new chardwFileLen+1; pBufdwFileLen=0; file.Read(pBuf,dwFileLen); file.Close(); MessageBox(pBuf); Win.ini The WriteProfileString function copies a string into the specified section of the Win.ini file. BOOL WriteProfileString( LPCTSTR lpAppName, / section name 段名 LPCTSTR lpKeyName, / key name 键名 LPCTSTR lpString / string to write 写的值 ); 下面在 InitInstance 中重载 CWinApp:InitInstance virtual BOOL InitInstance( ); 返 回 值 如 果 初 始 化 成 功 , 则 返 回 非 零 值 ; 否 则 返 回 0。 注 释 Windows 允 许 在 同 一 时 刻 运 行 程 序 的 几 份 拷 贝 。 在 概 念 上 , 应 用 程 序 的 初 始 化 可 以 被 分 为 两 个 部 分 : 一 次 性 的 应 用 程 序 初 始 化 工 作 , 这 些 在 应 用 程 序 第 一 次 运 行 时 完 成 , 以 及 实 例 的 初 始 化 工 作 , 每 次 运 行 程 序 的 一 个 拷 贝 时 都 会 执 行 这 些 操 作 , 包 括 第 一 次 运 行 时 。 框 架 中 WinMain 实 现 调 用 这 个 函 数 。 重 载 InitInstance 以 初 始 化 在 Windows 下 运 行 的 应 用 程 序 的 每 个 新 实 例 。 通 常 , 你 重 载 InitInstance 以 构 造 主 窗 口 对 象 并 设 置 CWinThread:m_pMainWnd 数 据 成 员 , 使 其 指 向 这 个 窗 口 。 有 关 重 载 这 个 成 员 函 数 的 更 多 信 息 参 见 “Visual C+ 程 序 员 指 南 ”中 的 “ CWinApp: 应 用 程 序 类 ”。 示 例 / AppWizard 根 据 你 选 择 的 选 项 实 现 重 载 的 InitInstance 函 数 。 / 例 如 , 对 于 下 面 由 AppWizard 创 建 的 代 码 , 选 择 了 单 文 档 界 面 ( SDI) 选 项 。 / 你 可 以 在 AppWizard 创 建 的 代 码 中 加 入 其 它 的 每 个 实 例 都 执 行 的 初 始 化 代 码 。 BOOL CMyApp:InitInstance() / 标 准 的 初 始 化 工 作 / 如 果 你 没 有 使 用 这 些 特 性 , 并 且 希 望 减 小 最 终 可 执 行 程 序 的 大 小 , / 你 应 当 从 下 面 的 初 始 化 例 程 中 移 去 不 必 要 的 代 码 。 SetDialogBkColor(); / 将 对 话 框 的 背 景 色 设 为 灰 色 。 LoadStdProfileSettings(); / 载 入 标 准 的 INI 文 件 选 项 ( 包 括 MRU) / 注 册 应 用 程 序 的 文 档 模 板 。 文 档 模 板 / 被 用 作 文 档 、 框 架 窗 口 和 视 图 之 间 的 联 系 。 CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CMyDoc), RUNTIME_CLASS(CMainFrame), / SDI 的 主 框 架 窗 口 RUNTIME_CLASS(CMyView); AddDocTemplate(pDocTemplate); / create a new (empty) document OnFileNew(); if (m_lpCmdLine0 != 0) / 创 建 一 个 新 ( 空 的 ) 文 档 return TRUE; 、:WriteProfileString(““,“admin“,“zhangshan“); 写入 win.ini 读取 CString str; :GetProfileString(““,“admin“,“lisi“,str.GetBuffer(100),100); AfxMessageBox(str); 写入注册表 WriteProfileString(““,“admin“,“zhangshan“); 注意在这里并没有使用全局对象:符,这个对象是 CWinApp 的函数 而不是全局函数 SetRegistryKey(_T(“httP:“);这个函数是用来设置键值的。 附:注册表修改 REG 将要修改的写入一个.reg 文件中,然后导入注册表中。.reg 文件的基本格式为: REGEDIT4HKEY_LOCAL_MACHINESoftwareSuper RabbitMagicSet “=“Super Rabbit Magic Set For Windows XP V2.92“ “a“=dword:00000001 “b“=hex:02,05,00,00 HKEY_LOCAL_MACHINESoftwareSCCQuickViewer 第一行为“REGEDIT4”,必须大写。 第二行为空行。 第三行使用括起子键分支,其中 HKEY_LOCAL_MACHINESoftwareSuper RabbitMagicSet 就是一个子键分支。 第四、五、六行是该子键下的设置数据。其中表示注册表编辑器右窗格中的“ 默认“键。 以下类似。 这样做的好处是可以避免错误的写入或删除等操作,但是要求用户了解注册表 的内部结构和.reg 文件的格式。 注册表六大主键 HKEY-CLASSES-ROOT 文件扩展名与应用的关联及 OLE 信息 HKEY-CURRENT-USER 当前登录用户控制面板选项和桌面等的设置,以及映射的网络驱 动器 HKEY-LOCAL-MACHINE 计算机硬件与应用程序信息 HKEY-USERS 所有登录用户的信息 HKEY-CURRENT-CONFIG 计算机硬件配置信息 HKEY-DYN-DATA 即插即用和系统性能的动态信息 写入注册表 HKEY hKey; RegCreateKey(HKEY_LOCAL_MACHINE,“SoftWareadmin“, RegSetValue(hKey,NULL,REG_SZ,“zhazhiwei“,strlen(“zhazhiwei“); RegCloseKey(hKey); 定义一个 HKEY 变量 然后创建这个主键 位置 和变量地址 设置变量值 如果是已经存在或者主键有值的请使用 RegSetValueEX 关闭主键 读取操作 void CFileView:OnRegRead() / TODO: Add your command handler code here LONG lValue; RegQueryValue(HKEY_LOCAL_MACHINE,“SoftWareadmin“,N ULL, char *pBuf = new charlValue; RegQueryValue(HKEY_LOCAL_MACHINE,“SoftWareadmin“,pBuf, MessageBox(pBuf); 在上段函数中 使用了两次 RegQueryValue 第一次当 lpValue 的值是 NULL 最后 lpcbValue 非空 为一个 LONG 型变量指针地址。 第一次将返回带有结束符的数据大小 然后分配一个堆内存做为缓冲区 第 2 次使用后 讲字符串输入缓冲区 然后读取该指针。 但 RegQueryValue 和刚才的 RegSetValue 都是针对字符串类型数据进行读写操作的, 如果要读取如整形 写入 DWORD dwAge =30; RegSetValueEx(hKey,“age“,0,REG_DWORD,(CONST BYTE*) 定义键值名 要类型转换 dwAge 读操作: HKEY hKey; RegOpenKey(HKEY_LOCAL_MACHINE,“SoftWareadmin“, DWORD dwType; DWORD dwValue; DWORD dwAge; RegQueryValueEx(hKey,“age“,0, CString str; str.Format(“age=%d“,dwAge); MessageBox(str); 定义键 下面打开主键 和直接读取不一样 把主键内容 存在三个 DWORD 变量里 因为是 DWORD 类型所以将其格式成字符串表示。 文档 与 串行化 让对象数据持久性的过程就称之为串行化 在 MFC 中,我们利用 CArchive 类来实现将对象数据保存到永久设备中。 注意: 在创建 CArchive 对象之前必须先创建一个 CFile 类或者子类的对象,并且因为存档对象可 以用来加载也可以用来保存数据。 必须保证 CFile 类对象和存档对象的一致性,但一个文件只能与一个活动存档关联。 void CMoniView:OnFileRead() / TODO: Add your command handler code here CFile file(“1.txt“,CFile:modeRead); CArchive ar( int i; char ch ; float f; CString str; CString strResult; arichfstr; strResult.Format(“%d,%c,%f,%s“,i,ch,f,str); MessageBox(strResult); void CMoniView:OnFileWrite() / TODO: Add your command handler code here CFile file(“1.txt“,CFile:modeCreate | CFile:modeWrite); CArchive ar( int i=4; char ch =a; float f=1.3f; CString str(““); arichfstr; strResult.Format(“%d,%c,%f,%s“,i,ch,f,str); AfxMessageBox(strResult); 我们单击保存发现文件已经保存,但点击打开时并不调用此函数 我们可以知道在此结构中: 文档类负责管理数据 视类负责显示数据 框架类负责为用户提供编辑数据和修改数据的功 能。 下面看下 void CFileDoc:Serialize(CArchive 在声明 CGraph 类,在头文件中 class CGraph :public CObject public: DECLARE_SERIAL(CGraph) void Serialize(CArchive CPoint m_ptEnd; CPoint m_ptOrigin; UINT m_nDrawType; CGraph(UINT m_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd); virtual CGraph(); ; 定义一个不带参数的构造函数 在这里我们遇到一个问题 为什么不能将头文件的构造函数参数值去掉 因为在函数中传递了参数 在 C+中 我们可以知道实例构造函数可以有多个,但是必须构 成重载才可以,就是方法的参数个数或类型不一样 两个定义就是在实例化类的时候可以带参数,也可以不带。但是只有第二个的话就必须带 参数,不然报错。 再完成 绘制函数 Draw 然后利用可串行化的类的 Serialize 的函数保存和加载对象。 绘制图形以后,使用 CObArray 类来实现,该类的用法与 CPtrList 类似,只是在添加元素 时时 CObject 指针 m_ptrArray.Add(pgraph) 接下来使用文档类的 Serialize 的函数中,将成员变量传递出去 为了获得与文档对象相关的视类对象,则使用 POSITION pos = GetFirstViewPosition();/创建一个 GetNextView 参数的变量来存储链表 首地址 CFileView *pView=(CFileView*)GetNextView(pos);/通过迭代运行将链表复制 存储: if (ar.IsStoring() int nCount = pView-m_obArray.GetSize();/建立一个变量链表长度的值 arm_obArray.GetAt(i); 读取: int nCount; arnCount; CGraph *pGraph; for(int i =0;ipGraph;/再这里并没有构造一个 CGraph 对象再读其数据因为使 时会自 动调用不带参数的构造函数构造对象 /然后将这个对象的地址赋给*pGraph 指针变量,所以不需要分配内存空间 /pView-m_obArray.GetAt(i); pView-m_obArray.Add(pGraph);/这里是给 CGraph 对象增加值而不是刚才写错了 的取值,打开时是无值,然后再 OnDraw 函数中 /调用强制转换对象的地址调用 m_obArray 对象的 Draw 方法来达到重绘的目的 另在编译这个文件时 加入头文件 #include “FileView.h“ 始终报错 说文档 VIEW 头文件出错 经过半天调试发现 #include “Graph.h“ #include “FileDoc.h“ #include “FileView.h“必须在后面 是按照那个顺序来加载的啊 假如一个头文件需要另一个头文件 那么这个头文件就得放那个下面了 所以“FileView.h“必须在后面 另做一个思考 每次打开后应该做个擦除的工作 而不是新 增加的数组上又做增加怎么办。 可以考虑 设计串行化类的时,在其内部确定需要成串行化的数据,这就是可串行化类的内部机制。 我们把前面的代码注释 在 IF/ELSE 语句外 pView-m_obArray.Serialize(ar); 发现可以保存 而这就是可串行化的类实现的过程 在上述文件中 还有个问题 堆内存的释放问题 我们新建一个文档时 程序文档对象所保存的数据要被销毁,然后再与一个新文档相关 而堆上的内存 必须被程序员手工释放. void CFileDoc:DeleteContents() 具体操作看 518 页数据的销毁 网络编程: TCP/IP 模型 应用层 传输层 网络层 网络接口层 端口 065535 16 位 其中 1024 以下端口保留给预定的服务 套接字 socket 的引入 它存在于通信区域 也就是地址族中 通常只与同一区域的套索字 交换字数 Windows Sockets 只支持一个通信区域 AF_INET,这个域使用网际协议簇通信的进程使用 PC 机采用的是地位先存,为确保数据的正确性,在网络协议中需要指定网络字节的顺序 TCP/IP 协议使用 16 位整数和 32 位整数的高位先存格式。 在网络中不通主机间进行通信的时候,要统一采用网络字节顺序。 客户机/服务器模式 在 TCP/IP 中 通信的两个进程间相互的主要模式是客户机/服务器模式 网络进程间通信时异步的,相互通信的进程间即不存在父子关系,也不共享内存缓冲区, 因此需要建立一种机制为互相通信的进程建立联系 这就是基于 cs 的 TCP/IP TCP 是传输层协议 主要是握手 IP 是网络层协议 主要是寻址和路由 Socket 类型 1. 流式套接字(SOCK_STREAM )提供面向连接的 可靠地数据传输服务,数据无差错, 无重复的发送,且按发送顺序接收。 TCP 2. 数据报式套接字(SOCK_DGRAM )提供无连接服务。数据包以独立包形式发送,不 提供无错保证,数据可能会丢失和重复,并且接受顺序混乱, UDP 3. 原始套接字(SOCK_RAW) 基于 TCP 面向连接的 SOCKET 编程 服务器端 1 创建套接字 2 将套接字绑定到一个本地地址和端口上 bind 3 将套接字设置为监听模式,准备接收客户的请求 listen 4 等待客户请求,当接受连接请求后 返回一个新的对应于此连接的套接字 accept 5 用返回的套接字和客户端进行通信 SEND/RECV 6 返回,等待另一用户请求 7 关闭套接字 客户端 1 创建套接字 2 向服务器发送连接请求 3 和服务器进行通信 4 关闭套接字 UDP 1 创建套接字 2 将套接字绑定到一个本地地址和端口上 bind 3 等待数据 4 关闭套接字 客户端 1 创建套接字 2 向服务器发送数据 3 闭套接字 加载套接字库 int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData ); 创建套接字 SOCKET socket( int af, Address family specification. 对于 TCP 只能写成 AF_INET int type, Type specification for the new socket SOCK_STREAM SOCK_DGRAM int protocol 指定地址家族的协议 0 的话自动选择 ); 2 将套接字绑定到一个本地地址和端口上 bind int bind( SOCKET s, const struct sockaddr FAR *name, int namelen ); MAKEWORD 宏 平 台 : SDK 这 个 宏 创 建 一 个 被 指 定 变 量 连 接 而 成 的 WORD 变 量 。 返 回 一 个 WORD 变 量 。 (注 : typedef unsigned short WORD;) WORD MAKEWORD( BYTE bLow, /指 定 新 变 量 的 低 字 节 序 ; BYTE bHigh /指 定 新 变 量 的 高 字 节 序 ; ); 服 务 器 端 程 序 编 写 #include #include void main() /加载套接字库 WORD wVersionRequested;/word 型套接字库版本号 WSADATA wsaData;/WSADATA 型 结构体 int err; /MAKEWORD 宏写入前面是高位副版本号 后面是地位高版本号 wVersionRequested = MAKEWORD(1,1); /创建加载套接字库 err = WSAStartup(wVersionRequested, if(err!=0) return; if(LOBYTE(wsaData.wVersion) !=1 | HIBYTE( wsaData.wVersion) !=1) WSACleanup(); return; /如果高位版本号或者地位版本号不为 1 则调用 WSACleanup()释放资源 /创建用于监听的套接字 SOCKET sockSrv = socket(AF_INET,SOCK_STREAM,0); SOCKADDR_IN addrSrv; /创建 SOCKADDR_IN 类型变量用来作为绑定的参数 addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);/对象结构体 sin_addr 中设置 允许任何套接字分配给本机的 IP addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(6000);/指定端口号 8000 并使用 htons 函数将一个 u_short =6000 的值从主机字节循序转换为 TCP/IP 顺序 bind(sockSrv,(SOCKADDR*)/绑定套接字 /设置为监听模式,准备请求 listen(sockSrv,5);/设置等待连接的最

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论