《VC++深入详解》
——————2012/8
颜色对话框 CColorDialog
保存另存为对话框 CFileDialog
字体对话框 CFontDialog
1 (用API创建一个窗口)
2 (C++类的基本知识)
3 (MFC单文档执行流程)
4 (消息映射机制;
MoveTo 、Lineto
获取客户区DC,绘画CPen CBrush)
使窗口无效 Invalidate();
刷新视图时默认的调用过程:CDocument::UpdateAllViews() -> CView::OnUpdate() -> CWnd::Invalidate() -> OnPaint() -> OnDraw()
5 (txt文本制作,插入符、路径程?
GetTextExtent、GetTextMetrics区别
卡拉OK字幕变色(DrawText、TextOut),
定时器)
得到客户窗口矩形坐标 GetClientRect(&rect);
Class 6 .menu
若四个类(App、MainFrame、Doc、View)都有一个菜单按钮的响应函数,那么响应优先级是前面列出的反序,且只有一个函数会响应。
菜单命令的路由过程:首先MainFrame类接受到消息,它将把消息传递给view类,若view类无处理函数,则转交给doc类,若也无处理函数则交还 给view类,view类再交还给mainframe类处理,若MainFrame也没有处理函数,则交给app来处理了。
创建一个弹出式菜单CreatePopupMenu; 添加到菜单栏最后AppendMenu; 删除指定的菜单DeleteMenu; 插入到菜单栏指定位置InsertMenu
Class 7 .dialog
GetDlgItem (控件ID )获取该对话框指定ID的控件指针
GetWindowText 获取控件的文本
SetWindowText 设置控件的文本
GetDlgItemText / SetDlgItemText atoi itoa
GetDlgItemInt / SetDlgItemInt
GetDlgItem->SendMessage ( ,WM_GETTEXT / WM_SETTEXT , , )
SendDlgItemMessageEM_SETSEL : SetFoucs
Edit控件
在聊天的时候,除了要滚动到最后一行显示外,还要把光标定位到最后。
m_edit.SetFocus();
int n = m_edit.GetWindowTextLength();
m_edit.SetSel(n, n, FALSE);
在编辑框中输入文本立即做出反映,可利用消息响应EN_CHANGE
对话框上创建一个控件按钮,风格一般是WS_VISIBLE | WS_CHILDE
Class 8.propertysheet & propertyPage
CPropertySheet sheet(_T("Simple PropertySheet"));
CStylePage pageStyle;
CColorPage pageColor;
CShapePage pageShape;
sheet.AddPage(&pageStyle);
sheet.AddPage(&pageColor);
sheet.AddPage(&pageShape);
sheet.SetWizardMode();//若在此处添加该函数则属性页变为属性向导
sheet.DoModal();
设置属性向导的上一页下一页和完成按钮:
在CPropertyPage::OnSetActive函数中调用 CPropertySheet::SetWizardButtons
在CPropertyPage::OnWizardNext函数中处理点击下一步按钮时的消息。先刷新updatedata
Group Box + Radio Button
(第一个Radio的属性要选中group,并为它定义一个int变量,当updatedata刷新后,变量的值即为以0为开始的该组Radio的索引) OnWizardNext()
在组框中绘图:CRect rect ; GetDlgItem(组框ID)->GetWindowRect(&rect); ScreenToClient(&rect) ;
这样就可以利用该矩形的坐标绘图了。
List Box
在对话框即将显示之前调用虚函数OnInitDialog()为该控件添加显示内容:((CListBox*)GetDlgItem(ID_LISTBOX))->AddString()。
为该控件定义一个CString变量,updatedata之后该变量值被用户选中的值刷新。
Grouo Box + check box
为每一个check关联一个bool变量。
Combo Box
Setcursel设置初始化edit默认的显示为索引为0的string
列表会自动排序,在控件属性上去掉sort选项,那么就会和自己添加的顺序一样。
为该控件定义一个变量 int型的索引 和 string型均可以。
对用户的选择结果可以不用updatedata实现映射,用getcursel和getlbtext组合也可。
向导框结束后,用户点击完成,domodal返回WIZFINISH。向导页的关联变量定义为public方便完成后在view类中访问。CPropertySheet为局部变量,此时窗口销毁了,但是对象还在,依然可以访问其中的成员。 调用InValidate函数使窗口无效,然后在OnDraw函数中实现在窗口中输出。
Class 9 修改窗口外观
修改图标,标题栏在框架窗口中修改。 修改客户区背景在view类中修改。(因为view覆盖在MainFrame上面的)
函数CMainFrame(CView)::PreCreateWindow(CREATESTRUCT& cs)中修改窗口的外观(窗口创建前)
在OnCreate函数末尾修改窗口外观(窗口创建后)
1. (修改光标,背景等)自定义并注册一个窗口类,注册并赋给cs.lpszClass
(修改标题栏,图标)直接修改cs的各成员变量。
因为:窗口的背景,消息处理函数,光标等是在定义窗口类时确定的,而窗口风格,最大最小化按钮,窗口大小是在注册窗口类之后创建窗口时设置的,所以可以通过cs直接改。
(创建后)调用全局函数SetWindowLong
2. (比上面的方法更方便) cs.lpszClass = AfxRegisterWndClass (创建前)
(常用)全局函数SetClassLong (创建后(OnCreate函数))Cview中没有OnCreate函数,需自己添加WM_CREATEX的消息处理。
IsWindowVisible ShowWindow( SW_SHOW / SW_HIDE )
ShowControlBar SetCheck (复选标记,选上之后会在菜单栏前面加个勾)
设置状态栏创建进度栏。。。。。。。
Class 10
CClientDC dc(this);
画点: dc.SetPoxel
画线: dc.MoveTo LineTo
画矩形: dc.Rectangle(CRect( ,))
画椭圆: dc.Ellipse
dc.SelectObject
画笔CPen、
画刷CBrush[要使新画的图形不覆盖原来的线条,应该将画刷设置为透明的,CBrush *p = CBrush::FromHandle ((HBRUSH)GetStockObject(NULL_BRUSH))得到一个透明的画刷,选入dc即可]
颜色对话框,字体对话框
设置对话框背景色WM_CTLCOLOR 消息响应函数OnCtlColor(CDC *pDC,CWnd *pWnd,UINT nCtlColor),返回一个用于绘制的指定画刷句柄。 会多次调用,对话框创建时调用,然后子窗口控件绘画时也要调用,pDC,pWnd均指向要绘制的控件,如果只绘制指定控件的颜色,可以在该函数中判断if(pWnd->GetDlgCtrID()==指定控件ID) { return 你要用的画刷}
SetWindowText设置文字的颜色 SetBkMode(TRANSPARENT)设置文字背景透明
SetBkColor设置背景色
若要改变CButton的字体颜色和背景色需要 派生CButton类并重写DrawItem函数,然后把该派生类对象与对话框中的按钮控件相关联。且在按钮控件的属性中要选中OwnerDraw
GetClientRect
位图:BitBlt按位拷贝 StretchBlt压缩放大拷贝.GetBitmap获取位图的宽高。
使窗口无效,窗口重绘经过两步:1,擦除背景OnEraseBkgnd;2,绘图OnDraw
如果重绘时窗口闪动大,则把绘图的操作写到OnEraseBkgnd中会好一点,因为在这个函数中绘图则不调用基类的OnEraseBkgnd,即不擦除背景就直接绘制了。
Class 11 图形的绘制和保持
MFC 集合类 CPreArray
Win32相应WM_PAINT消息绘图时,获取DC只能使用BeginPaint,EndPaint,且只能在painting消息中使用。它们封装在CPaintDc中。 而CClientDC封装了GetDC和ReleaseDC。
CScrollView 带滚动条的窗口
视口与窗口, 页面坐标(逻辑) 设备坐标(物理)
虚函数OnInitialUpdate 窗口刚完全创建时第一个调用的函数,可用来完成一些完后创建窗口后的初始化工作。
OnPrepareDC调整例如带滚动条之类的窗口。(逻辑坐标到设备坐标的映射)
Class 12 文件读写
memset memcpy memmove
C文件操作:
FILE * pFile = fopen(filename, openmode);
fwrite 、 fread 、 fclose 、 fseek(移动文件指针到指定位置)、 ftell(从当前指针位置得到文件长度) rewind(重新放置文件指针到开始处)
对文本的写入和读取应该保持一样,文本方式、二进制方式。因为文本方式的读写会做一些转换。如果以文本方式写二进制方式读则可能出现错误。
C++文件操作:
类: ofstream ifstream fstream
常用成员函数:write read close
Win32 API文件操作:
创建或打开(不仅文件):CreateFile ,关闭(CloseHandle) ,可设置共享,安全性,异步同步读写等等
写入:WrireFile 读取:ReadFile
MFC文件操作:
类: CFile (使用很方便)无缓冲
打开、保存对话框 CFileDialog类
CFileDialog类中一个重要的结构类型:m_ofn
win.ini文件信息存储与删除
::WriteProfileString函数用于兼容16系统写win.ini文件(一般用在CApp类的InitInstance虚函数中对注册表操作函数(SetRegistryKey)之下。)
::GetProfileString 获取键相关的字符串
CWinApp也继承了这两个函数,但是有区别,win2000以上的系统是写在注册表之中。
在32位系统中应该直接对注册表进行操作。
可查看注册表目录:HKEY_CURRENT_USER\Software\应用程序向导生成的本地应用程序
注册表操作
RegCreateKey(HEY_LOCAL_MACHINE,”Software\\ www.sunxin.org\\admin”,&hKey)
RegSetValue(hKey,NULL,REG_SZ,”zhangsan”,strlen(“zhangsan”)) //使用该函数只能设置REG_SZ类型的值
若要设置其他值则应该用RegSetValueEx
RegCloseKey(hKey)
RegQueryValue(HKEY_LOCAL_MACHINE,” Software\\ www.sunxin.org\\admin”,pBuf,&value)
用RegSetValueEx设置的其他类型值查询用 RegOpenKey + RegQueryValueEx
文档串行化
类: CArchive 必须在创建之前先创建一个CFile对象与之关联,而且访问文件的模式要相同 输入输出串行化,重载了 >> <<
MFC文档类串行化
一个文档对象与一个文件关联,通过CArchive操作。 集合类CObArray
有关文件读写操作在CDoc::Serialise(CArchive &ar);函数中,点击窗口的打开和保存按钮触发函数的消息相应。由语句if(ar.IsStoring())判断是保存还是打开。
编写自己的可串行化的类时,要保存自己定义的这个类的对象要为该类定义自己的serialise函数,doc类的函数在执行保存打开时会自动调用你定义的serialise函数。支持串行化的mfc类都定义了serialise函数
CWinApp管理文档链表,而每个文档关联一个框架和视图类(一个文档可以和多个视类关联,一个视类只能和一个文档关联),文档负责保存和加载数据(serialize),视图负责显示数据(ondraw)。
在文档类获取视图类的指针:
POSITION pos = GetFirstViewPosition();
CGraghView *pView = (CGrangh*)GetNextView(pos);
示图类获取文档类的指针:视图类自己定义了一个函数能获取文档类的指针。
关闭文档、onopendocument 和 onnewdocument 都会调用 deletecontents,特别是单文档分配了堆内存记得使用该函数释放。
Class14 网络编程
16位端口,1024及以下保留。
TCP/IP采用16位或32位整数高位先存。
TCP
服务器端:
1、 创建套接字(socket)。
2、 将套接字绑定到一个本地地址和端口上(bind)。
3、 将套接字设为监听模式,准备接受客户请求(listen)。
4、 等待客户请求到来:当请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept)。
5、 用返回的套接字和客户端进行通信(send/recv)。
6、 返回,等待另一个客户请求。
7、 关闭套接字。(closesocket)
客户端:
1、 创建套接字(socket)。
2、 向服务器发出连接请求(connect)。
3、 和服务器端进行通信(send/recv)。
4、 关闭套接字
UDP
服务器(接收端):
1、 创建套接字(socket)。
2、 将套接字绑定到一个本地地址和端口上(bind)。
3、 等待接受数据(recvfrom)。
4、 关闭套接字。
客户端(发送端):
1、 创建套接字(socket)。
2、 向服务器发送数据(sendto)。
3、 关闭套接字。
开始时应该调用WSAStartup启动库,结束后调用WSACleanup
Class 15,16 多线程、同步、聊天室
创建线程: CreateThread //创建返回线程的句柄应立即用CloseHandle关闭。
线程函数形式DWORD WINAPI ThreadProc(LPVOID lpParameter)
互斥对象: HANDLE hMutex= CreateMutex //如果创建命名的对象先前已经存在,且调用GetLastError()返回ERROR_ALREADY_EXISTS,则返回之前创建的对象的句柄。(可用于一个程序只能有一个实例的实现。)
WaitForSingleObject(hMutex,INFINITE) (使用之前申请)无信号时等待
ReleaseMutex(hMutex) (不使用时释放)让互斥量有信号
互斥对象里有一个计数器和访问线程的ID。谁拥有互斥对象只能由谁释放(请求多少次就应该释放多少次)。 若请求得到之后,线程关闭,但未释放,则操作系统会自动释放。其他线程任然能申请到。
(lesson 16)事件对象(线程同步)
CreateEvent, SetEvent, ResetEvent 申请用WaitForSingleObject
注意:人工重置,有信号时,所有的等待线程都能运行,需要手动调用reset,但还是不能实现同步。所以最好使用自动重置,有信号时只能有一个线程变为可调度,同时os会设置该对象为非信号,不需手动调用reset。
(可用于一个程序只能有一个实例的实现。)
(lesson 16)关键代码段(线程同步)
InitializeCriticalSection EnterCriticalSection, LeaveCriticalSection DeleteCriticalSection
互斥对象、事件对象、关键代码段:
前两者属于内核对象,进行线程同步较慢,可以实现多个进程间的线程同步。关键代码段是工作在用户方式下,同步速度快,但是容易出现死锁,因为等在时无法设定超时值。
聊天室
MFC中加载套接字可用AfxSocketInit,1.1版本,结束时系统会自动调用WSACleanup。
//Call this function in your CWinApp::InitInstance override to initialize Windows Sockets
使用这个函数应该在预编译头文件(stdafx)中加入afxsock.h,这样也不需要手动连接库文件。
线程函数可以定义为类静态函数。或全局函数。
CEdit控件中要支持换行,则属性中应该选择multiline,然后在CString中有\r\n则换行。
CIPAddressCtrl IP控件类。
DWORD dwIP;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);//获取控件中的ip地址(主机字节序)。
消息传递:
#define WM_ (WM_USER+1)
::PostMessage(hWnd,WM_,wParam,lParam)
ON_MESSAGE(WM_ , proc)
非阻塞的套接字异步选择机制:
利用消息传递机制(性能更高)
WSAAsyncSelect设置抛出消息 WSAEnumProtocols WSASocket (socket函数的扩展) 带WSA的均为windows的扩展。
WSARecvFrom, WSASendTo, sunxi PPT中有详解
用主机名获得ip地址:gethostbyname <-> gethostbyaddr
HOSTENT * pHost;
pHost = gethostbyname(edit_name);
addrto.sin_addr.S_un.S_addr = *((DWORD*)pHost->h_addr_list[0]);
Class 17.进程间通信
剪贴板
OpenClipboard EmptyClipboard SetClipboardData
CloseClipboard
匿名管道
命名管道
邮槽
Class 18. ActiveX
属性、事件、方法。
增加activex控件到工程会自动添加一个该控件的类。Project -> Add To Project ->Comgeonents and Contrls
Class 19.动态链接库
_declspec(dllexport) 导出函数需要在前面增加该语句。声明时应该使用_declspec(dllimport)该语句而不使用extern,这样效率更高。
GetForegroundWindow()获取当前用户窗口
extern “C”采用c语言编译方式到处库函数。(而不采用c++名字改编),不能导出类的成员函数,只能导出全局函数
模块定义文件。。。。。。。。。即使是_stdcall也不会采用c++的名字改编
动态加载一个动态链接库:LoadLibrary GetProcAddress 只加载需要的函数,节省内存空间,提高性能 FreeLibrary
DllMain