首页 > 代码库 > 精通 VC++ 实效编程280例 - 01 窗口[转]
精通 VC++ 实效编程280例 - 01 窗口[转]
窗口是屏幕上的一个矩形区域。窗口分为3种:重叠窗口、弹出窗口和子窗口。每个窗口都有由系统绘制的“非客户区”和应用程序绘制的“客户区”。在 MFC 中,CWnd 类为各种窗口提供了基类。
1 通过 HWND 获得 CWnd 指针
通过 HWND 获得 Cwnd 指针可以调用 Cwnd::FromHandle 函数。
1 2 3 4 5 6 7 8 | void CDemoDlg::OnButton1() { HWND hWnd = GetSafeHwnd(); //获得当前窗口的句柄 CWnd* pWnd = CWnd::FromHandle(hWnd); //通过HWND获得CWnd指针 CString strText = _T( "" ); strText.Format( "pWnd=0x%X\nthis=0x%X\n" ,pWnd, this ); AfxMessageBox(strText); } |
2 获得应用程序主窗口的指针
主窗口指针保存在 CWinThread::m_pMainWnd 中。可以首先调用 AfxGetApp 函数获得应用程序的指针,然后通过应用程序指针获得主窗口的指针。
1 2 3 4 5 6 7 8 | void CDemoDlg::OnButton2() { CDemoApp* pApp = (CDemoApp*)AfxGetApp(); //获得应用程序指针 CWnd* pMainWnd = pApp->m_pMainWnd; //获得主窗口指针 CString strText = _T( "" ); strText.Format( "pMainWnd=0x%X\nthis=0x%X\n" ,pMainWnd, this ); AfxMessageBox(strText); } |
3 获得指定点的窗口
获得指定点的窗口可以调用 CWnd::WindowFromPoint 函数。
a 在 CDemoDlg 类中重载 CWnd::PreTranslateMessage 函数。
1 2 3 4 5 6 7 8 9 10 | BOOL CDemoDlg::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_MOUSEMOVE) { CPoint point(LOWORD(pMsg->lParam),HIWORD(pMsg->lParam)); ::ClientToScreen(pMsg->hwnd, &point); //客户区坐标转换为屏幕坐标 OnMouseMove(0,point); } return CDialog::PreTranslateMessage(pMsg); } |
b 在 CDemoDlg 类中添加 WM_MOUSEMOVE 消息处理函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void CDemoDlg::OnMouseMove( UINT nFlags, CPoint point) { CWnd* pWnd = WindowFromPoint(point); //获得指定点的窗口 if (pWnd != NULL) { TRACE( "%d\n" ,pWnd); if (IsChild(pWnd)) { CString strText = _T( "" ); pWnd->GetWindowText(strText); SetWindowText(strText); } } CDialog::OnMouseMove(nFlags, point); } |
4 最大化和最小化窗口
最大化和最小化窗口可以调用 CWnd::SendMessage 函数发送最大化或最小化窗口消息。
LRESULT SendMessage(
UINT message, //发送的消息,值为 WM_SYSCOMMAND 时表示系统命令消息。
WPARAM wParam = 0, //当 message 值为 WM_SYSCMMAND,参数 wParam 值为 SC_MAXIMIZE、SC_MINIMIZE、
LPARAM lParam = 0 ); //SC_RESTORE 时分别表示最大化窗口、最小化窗口、恢复窗口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | void CDemoDlg::OnButton3() { //最大化窗口 SendMessage(WM_SYSCOMMAND,SC_MAXIMIZE,0); } void CDemoDlg::OnButton4() { //最小化窗口 SendMessage(WM_SYSCOMMAND,SC_MINIMIZE,0); } void CDemoDlg::OnButton5() { //恢复窗口 SendMessage(WM_SYSCOMMAND,SC_RESTORE,0); } |
5 关闭窗口
关闭窗口可以调用 CWnd::SendMessage 函数发送 WM_CLOSE 消息。框架将调用 CWnd::OnClose 函数处理 WM_CLOSE 消息。默认情况下,OnClose 函数将调用 CWnd::DestroyWindow 函数关闭窗口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | void CDemoDlg::OnButton6() { //关闭窗口 SendMessage(WM_CLOSE,0,0); } void CDemoDlg::OnClose() //添加 WM_CLOSE 消息处理函数 { //判断是否关闭 if (IDYES == MessageBox(_T( "是否关闭窗口?" ),NULL,MB_YESNO)) { CDialog::OnClose(); } } |
6 设置窗口的大小和位置
设置窗口大小和位置可通过两种方法:1.调用 CWnd::SetWindowPos 函数;2.调用 CWnd::MoveWindow 函数。
1 2 3 4 5 6 7 8 9 10 11 | void CDemoDlg::OnButton7() { //设置窗口的大小和位置 SetWindowPos(NULL,0,0,320,200,SWP_NOZORDER); } void CDemoDlg::OnButton8() { //设置窗口的大小和位置 MoveWindow(0,200,200,320); } |
7 居中显示窗口
使窗口居中显示可以调用 CWnd::CenterWindow 函数。
1 2 3 4 5 | void CDemoDlg::OnButton9() { //居中显示窗口 CenterWindow(); } |
8 顶层显示窗口
使窗口顶层显示,可以调用 CWnd::SetWindowPos 函数,设置对话框窗口的层次为最顶层。
1 2 3 4 5 | void CDemoDlg::OnButton10() { //设置窗口层次 SetWindowPos(&wndTopMost,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE); //SWP_NOSIZE:表示窗口保持当前的大小,SWP_NOMOVE:表示窗口保持当前的位置 } |
9 设置窗口图标
首先调用 CWinApp::LoadIcon 函数加载图标资源,然后调用 CWnd::SetIcon 函数设置图标。
1 2 3 4 5 6 7 | void CDemoDlg::OnButton11() { //加载图标 HICON hIcon = AfxGetApp()->LoadIcon(IDI_ICON); //设置图标 SetIcon(hIcon,FALSE); //FALSE:设置程序小图标,TRUE:设置任务栏大图标 } |
10 获得和设置窗口的标题
获得和设置窗口标题可以分别调用 CWnd::GetWindowText 和 CWnd::SetWindowText 函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 | void CDemoDlg::OnButton12() { CString strText = _T( "" ); GetWindowText(strText); //获得窗口标题 SetDlgItemText(IDC_TEXT,strText); //设置编辑框文本 } void CDemoDlg::OnButton13() { CString strText = _T( "" ); GetDlgItemText(IDC_TEXT,strText); //获得编辑框文本 SetWindowText(strText); //设置窗口标题 } |
11 显示或隐藏窗口的标题栏
显示或隐藏窗口的标题栏可以调用 CWnd::ModifyStyle 函数。
1 2 3 4 5 6 7 8 9 10 11 | void CDemoDlg::OnButton14() { //删除标题栏风格 ModifyStyle(WS_CAPTION,0,SWP_FRAMECHANGED); } void CDemoDlg::OnButton15() { //添加标题栏风格 ModifyStyle(0,WS_CAPTION,SWP_FRAMECHANGED); } |
12 改变窗口形状
标准窗口的形状是矩形的。改变窗口的形状首先调用 CRgn 类的成员函数创建相应形状的区域,然后调用 CWnd::SetWindowRgn 函数将其设置为窗口区域。
CRgn 类的 CreateRectRgn、CreateEllipticRgn、CreatePolygonRgn 和 CreateRoundRectRgn 函数可以分别用来创建矩形、椭圆形、多边形和圆矩形区域。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | void CDemoDlg::OnButton16() { CRect rect; GetClientRect(rect); //创建矩形区域 CRgn rgn; rgn.CreateRectRgn(rect.left,rect.top,rect.right,rect.bottom); //设置窗口的区域 SetWindowRgn(( HRGN )rgn,TRUE); } void CDemoDlg::OnButton17() { CRect rect; GetClientRect(rect); //创建椭圆形区域 CRgn rgn; rgn.CreateEllipticRgn(0,0,rect.Width(),rect.Height()); //设置窗口的区域 SetWindowRgn(( HRGN )rgn,TRUE); } void CDemoDlg::OnButton18() { CRect rect; GetClientRect(rect); CPoint point[6]; point[0].x = 0; point[0].y = rect.Height() / 2; point[1].x = rect.Width() / 3; point[1].y = 0; point[2].x = 2 * rect.Width() / 3; point[2].y = 0; point[3].x = rect.Width(); point[3].y = rect.Height() / 2; point[4].x = 2 * rect.Width() / 3; point[4].y = rect.Height(); point[5].x = rect.Width() / 3; point[5].y = rect.Height(); //创建多边形区域 CRgn rgn; rgn.CreatePolygonRgn(point,6,ALTERNATE); //设置窗口的区域 SetWindowRgn(( HRGN )rgn,TRUE); } void CDemoDlg::OnButton19() { CRect rect; GetClientRect(rect); //创建圆矩形区域 CRgn rgn; rgn.CreateRoundRectRgn(0,0,rect.Width(),rect.Height(),rect.Width() / 2,rect.Height() / 2); //设置窗口的区域 SetWindowRgn(( HRGN )rgn,TRUE); } |
13 设置窗口的透明区域
设置窗口的透明区域,首先调用 CRgn::CreateRectRgn 创建一个区域,然后调用 CRgn::CombineRgn 函数将需要透明的区域去掉,最后调用 CWnd::SetWindowRgn 函数将其设置为窗口区域。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | void CDemoDlg::OnButton20() { CRect rect1; GetWindowRect(rect1); CRect rect2; GetClientRect(rect2); ClientToScreen(rect2); CRgn rgn1; rgn1.CreateRectRgn(rect1.left,rect1.top,rect1.right,rect1.bottom); CRgn rgn2; rgn2.CreateRectRgn(rect2.left,rect2.top,rect2.right,rect2.bottom); CRgn rgn; rgn.CreateRectRgn(0,0,1,1); rgn.CombineRgn(&rgn1,&rgn2,RGN_DIFF); //设置窗口区域 SetWindowRgn(( HRGN )rgn,TRUE); } |
14 透明窗口
实现透明窗口,首先调用 CWnd::ModifyStyleEx 函数,添加窗口的 WS_EX_LAYERED(0x00080000) 扩展风格,然后调用 SDK 的 SetLayeredWindowAttributes 函数设置窗口的透明度和透明色。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | void CDemoDlg::OnButton21() { //添加 WS_EX_LAYERED(0x80000) 扩展风格 ModifyStyleEx(0,0x80000); //加载 User32.DLL 动态链接库 HMODULE hModule = LoadLibrary( "User32.DLL" ); if (hModule != NULL) { typedef BOOL (WINAPI *FUNC)( HWND , COLORREF , BYTE , DWORD ); //获得 SetLayeredWindowAttributes 函数指针 FUNC func = (FUNC)GetProcAddress(hModule, "SetLayeredWindowAttributes" ); if (func != NULL) { func(GetSafeHwnd(),0,128,2); } FreeLibrary(hModule); } } |
15 窗口闪烁
使窗口闪烁可以调用 CWnd::FlashWindow 函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | void CDemoDlg::OnButton22() { //设置定时器 SetTimer(1,1000,NULL); } void CDemoDlg::OnButton23() { //关闭定时器 KillTimer(1); //窗口返回原始状态 FlashWindow(FALSE); } void CDemoDlg::OnTimer( UINT nIDEvent) { if (nIDEvent == 1) { //窗口从一种状态闪烁到另一种状态 FlashWindow(TRUE); } CDialog::OnTimer(nIDEvent); } |
16 图片窗口
实现图片窗口,首先调用 CRgn::CreateRectRgn 和 CRgn::CombineRgn 函数创建并合并多个区域,然后调用 CWnd::SetWindowRgn 函数将其设置为窗口区域。
VC对话框如何添加WM_ERASEBKGND消息(OnEraseBkgnd函数):
http://guohaiyang.blog.163.com/blog/static/3213403720081027104147/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | void CDemoDlg::OnButton24() { CRect rect; GetWindowRect(&rect); //加载位图 CBitmap bmp; bmp.LoadBitmap(IDB_BITMAP); //将位图选入设备环境 CDC dc; CDC *pDC = GetDC(); dc.CreateCompatibleDC(pDC); dc.SelectObject(&bmp); //将位图中黑色区域变成透明区域 CRgn rgn1; rgn1.CreateRectRgn(0,0,rect.Width(),rect.Height()); for ( int x = 0;x < rect.Width();x++) { for ( int y = 0;y < rect.Height();y++) { COLORREF cr = dc.GetPixel(x,y); if (cr == RGB(0,0,0)) { CRgn rgn2; rgn2.CreateRectRgn(x,y,x+1,y+1); rgn1.CombineRgn(&rgn1,&rgn2,RGN_XOR); } } } //设置窗口区域 SetWindowRgn(( HRGN )rgn1,TRUE); ReleaseDC(pDC); } //添加 WM_ERASEBKGND 消息处理函数 BOOL CDemoDlg::OnEraseBkgnd(CDC* pDC) { CRect rect; GetWindowRect(&rect); CBitmap bmp; bmp.LoadBitmap(IDB_BITMAP); CDC dc; dc.CreateCompatibleDC(pDC); dc.SelectObject(&bmp); pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dc,0,0,SRCCOPY); return TRUE; } |
17 动画窗口
实现动画窗口,可以调用 SDK 的 AnimateWindow 函数。
1 2 3 4 5 6 7 8 9 10 | BOOL CDemoDlg::OnInitDialog() { CDialog::OnInitDialog(); // ... //窗口居中 CenterWindow(); //显示动画窗口 AnimateWindow(GetSafeHwnd(), 3000, AW_BLEND); return TRUE; } |
18 桌面窗口
获得桌面窗口,可以调用 CWnd::GetDesktopWindow 函数。
1 2 3 4 5 6 7 8 9 10 11 | void CDemoDlg::OnButton25() { //获得桌面窗口 CWnd* pWnd = CWnd::GetDesktopWindow(); //获得窗口大小 CRect rect; pWnd->GetClientRect(rect); CString strText = _T( "" ); strText.Format(_T( "桌面窗口大小:%dX%d" ),rect.Width(),rect.Height()); AfxMessageBox(strText); } |
19 最小化桌面所有窗口
Window 中可以利用快捷键 Win+M 最小化所有窗口。因此,可以通过向任务栏窗口发送 ID 为 0x1F5(Win+M) 的 WM_HOTKEY 消息,使桌面所有窗口最小化。首先调用 CWnd::FindWindow 函数获得窗口,然后调用 CWnd::SendMessage 函数向窗口发送消息。
1 2 3 4 5 6 7 | void CDemoDlg::OnButton26() { //获得任务栏窗口 CWnd* pWnd = CWnd::FindWindow(_T( "Shell_TrayWnd" ),NULL); //发送ID为0x1F5(Win+M)的WM_HOTKEY消息 pWnd->SendMessage(WM_HOTKEY,0x1F5); } |
20 获取任务栏窗口
获得任务栏窗口,可以调用 CWnd::FindWinow 函数。
1 2 3 4 5 6 7 8 9 10 11 | void CDemoDlg::OnButton27() { //获得任务栏窗口 CWnd* pWnd = CWnd::FindWindow(_T( "Shell_TrayWnd" ),NULL); //获得窗口大小 CRect rect; pWnd->GetClientRect(rect); CString strText = _T( "" ); strText.Format(_T( "任务栏窗口大小:%dX%d" ),rect.Width(),rect.Height()); AfxMessageBox(strText); } |
21 显示或隐藏任务栏
显示或隐藏任务栏,首先调用 CWnd::FindWindow 函数获得窗口,然后调用 CWnd::ShowWindow 函数隐藏或显示窗口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | void CDemoDlg::OnButton28() { //获得任务栏窗口 CWnd* pWnd = CWnd::FindWindow(_T( "Shell_TrayWnd" ),NULL); //隐藏窗口 if (pWnd->IsWindowVisible()) { pWnd->ShowWindow(SW_HIDE); } } void CDemoDlg::OnButton29() { //获得任务栏窗口 CWnd* pWnd = CWnd::FindWindow(_T( "Shell_TrayWnd" ),NULL); //显示窗口 if (!pWnd->IsWindowVisible()) { pWnd->ShowWindow(SW_SHOW); } } |
22 枚举桌面所有顶层窗口
BOOL CDemoDlg::OnInitDialog() { CDialog::OnInitDialog(); // ... //初始化列表框控件 CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST); pList->ModifyStyle(LVS_ICON | LVS_SMALLICON | LVS_LIST,LVS_REPORT); pList->SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT); pList->InsertColumn(0,_T( "窗口类名" ),LVCFMT_LEFT,115); pList->InsertColumn(1,_T( "窗口标题" ),LVCFMT_LEFT,150); return TRUE; } |
枚举桌面所有顶层窗口有以下两种方法:
a 调用 CWnd::GetDesktopWindow 和 CWnd::GetWindow 函数:首先调用 CWnd::GetDesktopWindow 函数,获得桌面窗口,然后调用 CWnd::GetWindow 函数,枚举所有子窗口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | void CDemoDlg::OnButton30() { CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST); pList->DeleteAllItems(); pList->SetRedraw(FALSE); //获得桌面窗口 CWnd* pDesktopWnd = CWnd::GetDesktopWindow(); //获得第一个子窗口 CWnd* pWnd = pDesktopWnd->GetWindow(GW_CHILD); while (pWnd != NULL) { int nItem = pList->GetItemCount(); //获得窗口类名 CString strClassName = _T( "" ); ::GetClassName(pWnd->GetSafeHwnd(),strClassName.GetBuffer(256),256); strClassName.ReleaseBuffer(); pList->InsertItem(nItem,strClassName); //获得窗口标题 CString strWindowText = _T( "" ); ::GetWindowText(pWnd->GetSafeHwnd(),strWindowText.GetBuffer(256),256); strWindowText.ReleaseBuffer(); pList->SetItemText(nItem,1,strWindowText); //继续获得下一个子窗口 pWnd = pWnd->GetWindow(GW_HWNDNEXT); } pList->SetRedraw(TRUE); } |
b 调用 SDK 的 EnumWindows 函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | //添加全局函数 BOOL CALLBACK EnumWndPorc( HWND hWnd, LPARAM lParam) { if (hWnd == NULL) { return FALSE; } CListCtrl* pList = (CListCtrl*)lParam; int nItem = pList->GetItemCount(); //获得窗口类名 CString strClassName = _T( "" ); ::GetClassName(hWnd,strClassName.GetBuffer(256),256); strClassName.ReleaseBuffer(); pList->InsertItem(nItem,strClassName); //获得窗口标题 CString strWindowText = _T( "" ); ::GetWindowText(hWnd,strWindowText.GetBuffer(256),256); strWindowText.ReleaseBuffer(); pList->SetItemText(nItem,1,strWindowText); return TRUE; } void CDemoDlg::OnButton31() { CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST); pList->DeleteAllItems(); pList->SetRedraw(FALSE); //枚举窗口 ::EnumWindows(EnumWndPorc,( LPARAM )pList); pList->SetRedraw(TRUE); } |
精通 VC++ 实效编程280例 - 01 窗口[转]