分割窗口有两种类型,一种是动态分割,一种是静态分割。此处仅记录静态分割的方法。
一、初始化
//插入页面项
m_Tab.InsertItem(0,"选项1");
m_Tab.InsertItem(0,"选项2");
m_Tab.InsertItem(0,"选项3");
//新建页面(非模态对话框),将其与对话框资源关联起来
page1.Create(IDD_PAGE1,GetDlgItem(IDC_TAB));
page2.Create(IDD_PAGE2,GetDlgItem(IDC_TAB));
page3.Create(IDD_PAGE3,GetDlgItem(IDC_TAB));
//调整页面位置
CRect rect;
m_Tab.GetClientRect(&rect);
rect.top+=19;
rect.left+=1;
rect.bottom-=1;
rect.right-=1;
//将页面移动到调整好的位置上
page1.MoveWindow(&rect);
page2.MoveWindow(&rect);
page3.MoveWindow(&rect);
//显示页面,当前显示页面一
page1.ShowWindow(TRUE);
page2.ShowWindow(FALSE);
page3.ShowWindow(FALSE);
//设置默认显示页面为页面一
m_Tab.SetCurSel(0);
二、选项切换
int CurSel = m_Tab.GetCurSel();//得到当前的选项ID
switch(CurSel)//通过窗口的隐藏与显示切换选项面板
{
case 0:
page1.ShowWindow(TRUE);
page2.ShowWindow(FALSE);
page3.ShowWindow(FALSE);
break;
case 1:
page1.ShowWindow(FALSE);
page2.ShowWindow(TRUE);
page3.ShowWindow(FALSE);
break;
case 2:
page1.ShowWindow(FALSE);
page2.ShowWindow(TRUE);
page3.ShowWindow(TRUE);
break;
default: ;
}
一、概述
1、Encapsulates the functionality of a "list view control," which displays a collection of items each consisting of an icon (from an image list) and a label.封装了列表控件,列表控件显示了一系列列表项,每个列表项包含一个图标和一个标签。
2、In addition to an icon and label, each item can have information displayed in columns to the right of the icon and label.
除了一个图标和标签,每个列表项可以包含一个信息,显示在图标和标签右边的列内。
3、List view controls can display their contents in four different ways, called "views."
列表控件可以以四种视图显示其内容:图标、小图标、列表、报表。
4、The style of the control's current list view determines the current view.
该控件的当前视图风格取决于当前的视图。
二、ListCtrl基本使用(该项内容转自http://www.cnblogs.com/cy163/archive/2006/10/15/529790.html)
以下未经说明,listctrl默认view 风格为report
LVS_ICON: 为每个item显示大图标
LVS_SMALLICON: 为每个item显示小图标
LVS_LIST: 显示一列带有小图标的item
LVS_REPORT: 显示item详细资料
直观的理解:windows资源管理器,“查看”标签下的“大图标,小图标,列表,详细资料”
LONG lStyle;
lStyle = GetWindowLong(m_list.m_hWnd, GWL_STYLE);//获取当前窗口style
lStyle &= ~LVS_TYPEMASK; //清除显示方式位
lStyle |= LVS_REPORT; //设置style
SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle);//设置style
DWORD dwStyle = m_list.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl)
dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl)
dwStyle |= LVS_EX_CHECKBOXES;//item前生成checkbox控件
m_list.SetExtendedStyle(dwStyle); //设置扩展风格
注:listview的style请查阅msdn
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wceshellui5/html/wce50lrflistviewstyles.asp
m_list.InsertColumn( 0, "ID", LVCFMT_LEFT, 40 );//插入列
m_list.InsertColumn( 1, "NAME", LVCFMT_LEFT, 50 );
int nRow = m_list.InsertItem(0, “11”);//插入行
m_list.SetItemText(nRow, 1, “jacky”);//设置数据
int nIndex = 0;
//选中
m_list.SetItemState(nIndex, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
//取消选中
m_list.SetItemState(nIndex, 0, LVIS_SELECTED|LVIS_FOCUSED);
m_list.SetExtendedStyle(LVS_EX_CHECKBOXES);
CString str;
for(int i=0; i<m_list.GetItemCount(); i++)
{
if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED || m_list.GetCheck(i))
{
str.Format(_T("第%d行的checkbox为选中状态"), i);
AfxMessageBox(str);
}
}
方法一:
CString str;
for(int i=0; i<m_list.GetItemCount(); i++)
{
if( m_list.GetItemState(i, LVIS_SELECTED) == LVIS_SELECTED )
{
str.Format(_T("选中了第%d行"), i);
AfxMessageBox(str);
}
}
方法二:
POSITION pos = m_list.GetFirstSelectedItemPosition();
if (pos == NULL)
TRACE0("No items were selected!\n");
else
{
while (pos)
{
int nItem = m_list.GetNextSelectedItem(pos);
TRACE1("Item %d was selected!\n", nItem);
// you could do your own processing on nItem here
}
}
TCHAR szBuf[1024];
LVITEM lvi;
lvi.iItem = nItemIndex;
lvi.iSubItem = 0;
lvi.mask = LVIF_TEXT;
lvi.pszText = szBuf;
lvi.cchTextMax = 1024;
m_list.GetItem(&lvi);
关于得到设置item的状态,还可以参考msdn文章
Q173242: Use Masks to Set/Get Item States in CListCtrl
http://support.microsoft.com/kb/173242/en-us
LVCOLUMN lvcol;
char str[256];
int nColNum;
CString strColumnName[4];//假如有4列
nColNum = 0;
lvcol.mask = LVCF_TEXT;
lvcol.pszText = str;
lvcol.cchTextMax = 256;
while(m_list.GetColumn(nColNum, &lvcol))
{
strColumnName[nColNum] = lvcol.pszText;
nColNum++;
}
方法一:
while ( m_list.DeleteColumn (0))
因为你删除了第一列后,后面的列会依次向上移动。
方法二:
int nColumns = 4;
for (int i=nColumns-1; i>=0; i--)
m_list.DeleteColumn (i);
添加listctrl控件的NM_CLICK消息相应函数
void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
// 方法一:
/*
DWORD dwPos = GetMessagePos();
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
m_list.ScreenToClient(&point);
LVHITTESTINFO lvinfo;
lvinfo.pt = point;
lvinfo.flags = LVHT_ABOVE;
int nItem = m_list.SubItemHitTest(&lvinfo);
if(nItem != -1)
{
CString strtemp;
strtemp.Format("单击的是第%d行第%d列", lvinfo.iItem, lvinfo.iSubItem);
AfxMessageBox(strtemp);
}
*/
// 方法二:
/*
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
if(pNMListView->iItem != -1)
{
CString strtemp;
strtemp.Format("单击的是第%d行第%d列",
pNMListView->iItem, pNMListView->iSubItem);
AfxMessageBox(strtemp);
}
*/
*pResult = 0;
}
添加listctrl控件的NM_CLICK消息相应函数
void CTest6Dlg::OnClickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
DWORD dwPos = GetMessagePos();
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
m_list.ScreenToClient(&point);
LVHITTESTINFO lvinfo;
lvinfo.pt = point;
lvinfo.flags = LVHT_ABOVE;
UINT nFlag;
int nItem = m_list.HitTest(point, &nFlag);
//判断是否点在checkbox上
if(nFlag == LVHT_ONITEMSTATEICON)
{
AfxMessageBox("点在listctrl的checkbox上");
}
*pResult = 0;
}
添加listctrl控件的NM_RCLICK消息相应函数
void CTest6Dlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
if(pNMListView->iItem != -1)
{
DWORD dwPos = GetMessagePos();
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
CMenu menu;
VERIFY( menu.LoadMenu( IDR_MENU1 ) );
CMenu* popup = menu.GetSubMenu(0);
ASSERT( popup != NULL );
popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this );
}
*pResult = 0;
}
添加listctrl控件的LVN_ITEMCHANGED消息相应函数
void CTest6Dlg::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
// TODO: Add your control notification handler code here
CString sTemp;
if((pNMListView->uOldState & LVIS_FOCUSED) == LVIS_FOCUSED &&
(pNMListView->uNewState & LVIS_FOCUSED) == 0)
{
sTemp.Format("%d losted focus",pNMListView->iItem);
}
else if((pNMListView->uOldState & LVIS_FOCUSED) == 0 &&
(pNMListView->uNewState & LVIS_FOCUSED) == LVIS_FOCUSED)
{
sTemp.Format("%d got focus",pNMListView->iItem);
}
if((pNMListView->uOldState & LVIS_SELECTED) == LVIS_SELECTED &&
(pNMListView->uNewState & LVIS_SELECTED) == 0)
{
sTemp.Format("%d losted selected",pNMListView->iItem);
}
else if((pNMListView->uOldState & LVIS_SELECTED) == 0 &&
(pNMListView->uNewState & LVIS_SELECTED) == LVIS_SELECTED)
{
sTemp.Format("%d got selected",pNMListView->iItem);
}
*pResult = 0;
}
http://www.codeguru.com/cpp/controls/listview/introduction/article.php/c919/
m_list.SetExtendedStyle(LVS_EX_SUBITEMIMAGES);
m_list.SetItem(..); //具体参数请参考msdn
网上找到的代码,share
BOOL CTest6Dlg::OnInitDialog()
{
CDialog::OnInitDialog();
HIMAGELIST himlSmall;
HIMAGELIST himlLarge;
SHFILEINFO sfi;
char cSysDir[MAX_PATH];
CString strBuf;
memset(cSysDir, 0, MAX_PATH);
GetWindowsDirectory(cSysDir, MAX_PATH);
strBuf = cSysDir;
sprintf(cSysDir, "%s", strBuf.Left(strBuf.Find("\\")+1));
himlSmall = (HIMAGELIST)SHGetFileInfo ((LPCSTR)cSysDir,
0,
&sfi,
sizeof(SHFILEINFO),
SHGFI_SYSICONINDEX | SHGFI_SMALLICON );
himlLarge = (HIMAGELIST)SHGetFileInfo((LPCSTR)cSysDir,
0,
&sfi,
sizeof(SHFILEINFO),
SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
if (himlSmall && himlLarge)
{
::SendMessage(m_list.m_hWnd, LVM_SETIMAGELIST,
(WPARAM)LVSIL_SMALL, (LPARAM)himlSmall);
::SendMessage(m_list.m_hWnd, LVM_SETIMAGELIST,
(WPARAM)LVSIL_NORMAL, (LPARAM)himlLarge);
}
return TRUE; // return TRUE unless you set the focus to a control
}
void CTest6Dlg::AddFiles(LPCTSTR lpszFileName, BOOL bAddToDocument)
{
int nIcon = GetIconIndex(lpszFileName, FALSE, FALSE);
CString strSize;
CFileFind filefind;
// get file size
if (filefind.FindFile(lpszFileName))
{
filefind.FindNextFile();
strSize.Format("%d", filefind.GetLength());
}
else
strSize = "0";
// split path and filename
CString strFileName = lpszFileName;
CString strPath;
int nPos = strFileName.ReverseFind('\\');
if (nPos != -1)
{
strPath = strFileName.Left(nPos);
strFileName = strFileName.Mid(nPos + 1);
}
// insert to list
int nItem = m_list.GetItemCount();
m_list.InsertItem(nItem, strFileName, nIcon);
m_list.SetItemText(nItem, 1, strSize);
m_list.SetItemText(nItem, 2, strFileName.Right(3));
m_list.SetItemText(nItem, 3, strPath);
}
int CTest6Dlg::GetIconIndex(LPCTSTR lpszPath, BOOL bIsDir, BOOL bSelected)
{
SHFILEINFO sfi;
memset(&sfi, 0, sizeof(sfi));
if (bIsDir)
{
SHGetFileInfo(lpszPath,
FILE_ATTRIBUTE_DIRECTORY,
&sfi,
sizeof(sfi),
SHGFI_SMALLICON | SHGFI_SYSICONINDEX |
SHGFI_USEFILEATTRIBUTES |(bSelected ? SHGFI_OPENICON : 0));
return sfi.iIcon;
}
else
{
SHGetFileInfo (lpszPath,
FILE_ATTRIBUTE_NORMAL,
&sfi,
sizeof(sfi),
SHGFI_SMALLICON | SHGFI_SYSICONINDEX |
SHGFI_USEFILEATTRIBUTES | (bSelected ? SHGFI_OPENICON : 0));
return sfi.iIcon;
}
return -1;
}
m_list.SetRedraw(FALSE);
//更新内容
m_list.SetRedraw(TRUE);
m_list.Invalidate();
m_list.UpdateWindow();
或者参考
Q250614:How To Sort Items in a CListCtrl in Report View
http://support.microsoft.com/kb/250614/en-us
Q151897: CListCtrl::InsertColumn() Causes Column Data to Shift
http://support.microsoft.com/kb/151897/en-us
解决办法:把第一列当一个虚列,从第二列开始插入列及数据,最后删除第一列。
具体解释参阅 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/listview/structures/lvcolumn.asp
http://msdn.microsoft.com/msdnmag/issues/03/06/CQA/
把需隐藏的列的宽度设为0,然后检测当该列为隐藏列时,用上面第27点的锁定column 的拖动来实现
http://www.codeguru.com/cpp/controls/listview/advanced/article.php/c4151/
http://www.codeproject.com/listctrl/virtuallist.asp
解决办法:需要在item上放一个edit。
Q125694: How To Find Out Which Listview Column Was Right-Clicked
http://support.microsoft.com/kb/125694/en-us
Q234310: How to implement a ListView control that is similar to Windows Explorer by using DirLV.exe
http://support.microsoft.com/kb/234310/en-us
Q200054:
PRB: OnTimer() Is Not Called Repeatedly for a List Control
http://support.microsoft.com/kb/200054/en-us
(1) 拖放
http://www.codeproject.com/listctrl/dragtest.asp
在CListCtrl和CTreeCtrl间拖放
http://support.microsoft.com/kb/148738/en-us
(2) 多功能listctrl
支持subitem可编辑,图标,radiobutton,checkbox,字符串改变颜色的类
http://www.codeproject.com/listctrl/quicklist.asp
支持排序,subitem可编辑,subitem图标,subitem改变颜色的类
http://www.codeproject.com/listctrl/ReportControl.asp
(3) subitem中显示超链接
http://www.codeproject.com/listctrl/CListCtrlLink.asp
(4) subitem的tooltip提示
http://www.codeproject.com/listctrl/ctooltiplistctrl.asp
(5) subitem中显示进度条
http://www.codeproject.com/listctrl/ProgressListControl.asp
http://www.codeproject.com/listctrl/napster.asp
http://www.codeguru.com/Cpp/controls/listview/article.php/c4187/
(6) 动态改变subitem的颜色和背景色
http://www.codeproject.com/listctrl/highlightlistctrl.asp
http://www.codeguru.com/Cpp/controls/listbox/colorlistboxes/article.php/c4757/
(7) 类vb属性对话框
http://www.codeproject.com/listctrl/propertylistctrl.asp
http://www.codeguru.com/Cpp/controls/listview/propertylists/article.php/c995/
http://www.codeguru.com/Cpp/controls/listview/propertylists/article.php/c1041/
(8) 选中subitem(只高亮选中的item)
http://www.codeproject.com/listctrl/SubItemSel.asp
http://www.codeproject.com/listctrl/ListSubItSel.asp
(9) 改变行高
http://www.codeproject.com/listctrl/changerowheight.asp
(10) 改变行颜色
http://www.codeproject.com/listctrl/coloredlistctrl.asp
(11) 可编辑subitem的listctrl
http://www.codeproject.com/listctrl/nirs2000.asp
http://www.codeproject.com/listctrl/editing_subitems_in_listcontrol.asp
(12) subitem可编辑,插入combobox,改变行颜色,subitem的tooltip提示
http://www.codeproject.com/listctrl/reusablelistcontrol.asp
(13) header 中允许多行字符串
http://www.codeproject.com/listctrl/headerctrlex.asp
(14) 插入combobox
http://www.codeguru.com/Cpp/controls/listview/editingitemsandsubitem/article.php/c979/
(15) 添加背景图片
http://www.codeguru.com/Cpp/controls/listview/backgroundcolorandimage/article.php/c4173/
http://www.codeguru.com/Cpp/controls/listview/backgroundcolorandimage/article.php/c983/
http://www.vchelp.net/vchelp/archive.asp?type_id=9&class_id=1&cata_id=1&article_id=1088&search_term=
(16) 自适应宽度的listctrl
http://www.codeproject.com/useritems/AutosizeListCtrl.asp
NM_CUSTOMDRAW
http://www.codeproject.com/listctrl/lvcustomdraw.asp
一、文件打开与保存对话框
1、OPENFILENAME Structure
The OPENFILENAME structure contains information that the GetOpenFileName and GetSaveFileName functions use to initialize an Open or Save As dialog box. After the user closes the dialog box, the system returns information about the user's selection in this structure.
OPENFILENAME结构体包含了GetOpenFileName 和GetSaveFileName 函数的信息,这两个函数用于初始化一个打开或另存为对话框。当用户关闭了该对话框,系统返回包含在该结构体中用户的选择信息。(更详细信息参见MSDN)
1、API实现
OPENFILENAMEA ofn; //定义结构体变量
char szFile[260];
ZeroMemory(&ofn, sizeof(ofn));//初始化结构体
ofn.lStructSize = sizeof(ofn); //Specifies the length, in bytes, of the structure.
ofn.hwndOwner = NULL; //Handle to the window that owns the dialog box.
ofn.lpstrFile = szFile; //Pointer to a buffer that contains a file name used to initialize the File Name edit control.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile); //Specifies the size, in TCHARs, of the buffer pointed to by lpstrFile.
ofn.lpstrFilter = "PDF File(*.pdf)\0*.pdf\0音频文件(*.wma)\0*.wma\0All Files(*.*)\0\0"; //文件过滤
ofn.nFilterIndex = 1; //Specifies the index of the currently selected filter in the File Types control.
ofn.lpstrFileTitle = NULL; //Pointer to a buffer that receives the file name and extension (without path information) //of the selected file
ofn.nMaxFileTitle = 0; //Specifies the size, in TCHARs, of the buffer pointed to by lpstrFileTitle.
ofn.lpstrInitialDir = NULL; //Pointer to a NULL terminated string that can specify the initial directory.
ofn.Flags = 0; //A set of bit flags you can use to initialize the dialog box.
if (GetOpenFileNameA(&ofn)==FALSE) {
return S_FALSE;
}
3、CFileDialog类实现
CFileDialog fileDlg(TRUE);//初始为TRUE,生成打开对话框,初始为FALSE,生成保存对话框
fileDlg.m_ofn.lpstrTitle=_T("打开");//对话框标题
fileDlg.m_ofn.lpstrFilter=_T("PDF File(*.pdf)\0*.pdf \0All Files(*.*)\0*.*\0\0");//文件类型过滤
filter =_T("pdf File(*.pdf)|*.pdf|All Files(*.*)|*.*||");//文件过滤
fileDlg.DoModal();//显示模态对话框
//打开对话框
CString filter;
filter =_T("pdf File(*.pdf)|*.pdf|All Files(*.*)|*.*||");//文件过滤
CFileDialog dlg(TRUE,NULL,NULL,OFN_ALLOWMULTISELECT,filter,NULL);//OFN_ALLOWMULTISELECT:多选
dlg.DoModal();//显示模态对话框
二、浏览文件夹对话框
CString CTestDlg::FolderBrowse(void)
{
TCHAR chPath[255]; //用来存储路径的字符串
CString strPath = _T("");
BROWSEINFO bInfo;
GetModuleFileName(NULL,chPath,MAX_PATH);
strPath =chPath;
ZeroMemory(&bInfo, sizeof(bInfo));
bInfo.hwndOwner = m_hWnd;
bInfo.lpszTitle = _T("请选择路径: ");
bInfo.ulFlags = BIF_RETURNONLYFSDIRS|BIF_EDITBOX;
//bInfo.lpfn = BrowseCallbackProc;
bInfo.lParam = (LPARAM)strPath.GetBuffer(strPath.GetLength());
LPITEMIDLIST lpDlist; //用来保存返回信息的IDList
lpDlist = SHBrowseForFolder(&bInfo) ; //显示选择对话框
if(lpDlist != NULL) //用户按了确定按钮
{
SHGetPathFromIDList(lpDlist, chPath);//把项目标识列表转化成字符串
strPath = chPath; //将TCHAR类型的字符串转换为CString类型的字符串
}
return strPath;
}
一、 按键讯息
1、系统按键与非系统按键
当您按下一个键时,Windows 把WM_KEYDOWN 或者WM_SYSKEYDOWN 讯息放入有输入焦点的视窗的讯息伫列;当您释放一个键时,Windows 把WM_KEYUP 或者WM_SYSKEYUP 讯息放入讯息伫列中。
WM_SYSKEYDOWN 和WM_SYSKEYUP 讯息经常由与Alt 相组合的按键产生。
WM_KEYDOWN和WM_KEYUP讯息通常是在按下或者释放不带Alt键的键时产生的。
对所有四类按键讯息,wParam 是虚拟键代码,表示按下或释放的键,而lParam 则包含属於按键的其他资料。
2、虚拟键码
虚拟键码保存在WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN 和WM_SYSKEYUP
讯息的wParam 参数中。此代码标识按下或释放的键。
您使用的大多数虚拟键码的名称在WINUSER.H 表头档案中都定义为以VK_开头。
3、lParam资讯
lParam 的32 位分为6 个栏位:

重复计数
OEM扫描码
扩充键旗标
内容代码
键的先前状态
转换状态
1、 位移状态
在处理按键讯息时,您可能需要知道是否按下了位移键(Shift、Ctrl 和Alt)或开关键(Caps Lock、Num Lock和Scroll Lock)。通过呼叫GetKeyState函式,您就能获得此资讯。
请注意GetKeyState 的使用,它并非即时检查键盘状态,而只是检查直到目前为止正在处理的讯息的键盘状态。多数情况下,这正符合您的要求。如果您需要确定使用者是否按下了Shift-Tab,请在处理Tab 键的WM_KEYDOWN 讯息时呼叫GetKeyState,带有参数VK_SHIFT。
如果您确实需要知道目前某键的状态,那么您可以使用GetAsyncKeyState。
一、 键盘基础
键盘输入以讯息的形式传递给程式的视窗讯息处理程式。Windows用八种不同的讯息来传递不同的键盘事件。
1、 忽略键盘
l 您可以忽略那些属於系统功能的按键,它们通常用到Alt 键;
l 有些Windows 程式使用「键盘加速键」来启动通用功能表项。加速键通常是功能键或字母同Ctrl 键的组合(例如,Ctrl-S 用於保存档案)。这些键盘加速键与程式功能表一起在程式的资源描述档案中定义(我们可以在第十章看到)。Windows 将这些键盘加速键转换为功能表命令讯息,您不必自己去进行转换。
l 当对话方块处於活动状态时,应用程式通常不必监视键盘。
2、 谁获得了焦点
接收特定键盘事件的视窗具有输入焦点;
有时输入焦点不在任何视窗中;
视窗讯息处理程式通过拦截WM_SETFOCUS和WM_KILLFOCUS讯息来判定它的视窗何时拥有输入焦点。WM_SETFOCUS 指示视窗正在得到输入焦点,WM_KILLFOCUS 表示视窗正在失去输入焦点。
3、 伫列和同步
系统讯息伫列:
系统讯息伫列是独立的讯息伫列,它由Windows 维护,用於初步保存使用者从键盘和滑鼠输入的资讯。
只有当Windows应用程式处理完前一个使用者输入讯息时,Windows 才会从系统讯息伫列中取出下一个讯息,并将其放入应用程式的讯息伫列中。此过程分为两步:首先在系统讯息伫列中保存讯息,然後将它们放入应用程式的讯息伫列,其原因是需要同步。
4、 按键和字元
应用程式从Windows接收的关於键盘事件的讯息可以分为按键和字元两类。
对产生可显示字元的按键组合,Windows 不仅给程式发送按键讯息,而且还发送字元讯息。
对于控制字元和不可显示字元的按键组合,Windows 只产生按键讯息。
六、矩形、区域和剪裁
1、矩形函式
下面三个绘图函式需要一个指向矩形结构的指标:
FillRect (hdc, &rect, hBrush) ;
FrameRect (hdc, &rect, hBrush) ;
InvertRect (hdc, &rect) ;
rect参数是一个RECT型态的结构,它包含有4个栏位:left、top、right 和bottom。这个结构中的座标被当作逻辑座标。
FrameRect 使用画刷画矩形框,但是不填入矩形。
InvertRect 将矩形中所有图素翻转,1 转换成0,0 转换为1。
rect.left = xLeft ;
rect.top = xTop ;
rect.right = xRight ;
rect.bottom = xBottom ;
SetRect (&rect, xLeft, yTop, xRight, yBottom) ;
将矩形沿x 轴和y 轴移动几个单元 OffsetRect (&rect, x, y) ;
增减矩形的尺寸 InflateRect (&rect, x, y) ;
矩形各栏位设定为0 SetRectEmpty (&rect) ;
将矩形复制给另一个矩形 CopyRect (&DestRect, &SrcRect) ;
取得两个矩形的交集 IntersectRect (&DestRect, &SrcRect1, &SrcRect2) ;
取得两个矩形的联集 UnionRect (&DestRect, &SrcRect1, &SrcRect2) ;
确定矩形是否为空 bEmpty = IsRectEmpty (&rect) ;
确定点是否在矩形内 bInRect = PtInRect (&rect, point) ;
2、随机矩形
在Windows 中一定有很多「闲置时间」,在这个时间内,所有讯息伫列为空,Windows 只停在一个小回圈中等待键盘或者滑鼠输入。我们能否在闲置时间内获得控制,绘制矩形,并且只在有讯息加入程式的讯息伫列之後才释放控制呢?这就是PeekMessage 函式的目的之一。
PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) ;
前面的四个参数(一个指向MSG 结构的指标、一个视窗代号、两个值指示讯息范围)与GetMessage 的参数相同。将第二、三、四个参数设定为NULL 或0时,表明我们想让PeekMessage 传回程式中所有视窗的所有讯息。如果要将讯息从讯息伫列中删除,则将PeekMessage 的最後一个参数设定为PM_REMOVE。如果您不希望删除讯息,那么您可以将这个参数设定为PM_NOREMOVE。这就是为什么Peek_Message 是「偷看」而不是「取得」的原因,它使得程式可以检查程式的伫列中的下一个讯息,而不实际删除它。
GetMessage 不将控制传回给程式,直到从程式的讯息伫列中取得讯息,但是PeekMessage 总是立刻传回,而不论一个讯息是否出现。当讯息伫列中有一个讯息时,PeekMessage 的传回值为TRUE(非0),并且将按通常方式处理讯息。当伫列中没有讯息时,PeekMessage 传回FALSE(0)。
3、建立和绘制剪裁区域
剪裁区域是对显示器上一个范围的描述,这个范围是矩形、多边形和椭圆的组合。剪裁区域可以用於绘制和剪裁,通过将剪裁区域选进装置内容,就可以用剪裁区域来进行剪裁(就是说,将可以绘图的范围限制为显示区域的一部分)。与画笔、画刷和点阵图一样,剪裁区域是GDI物件,您应该呼叫DeleteObject来删除您所建立的剪裁区域。
4、矩形与区域的剪裁
Windows 有两个作用於剪裁区域而不是矩形的函式:
InvalidateRgn (hwnd, hRgn, bErase);
ValidateRgn (hwnd, hRgn) ;
五、映射模式
到目前为止,所有的程序都是相对与显示区域的左上角,以像素为单位绘图的。这是内定情况,但不是唯一选择。事实上,「映射方式」是一种几乎影响任何显示区域绘图的设备上下文属性。另外有四种设备上下文属性——视窗原点、视埠原点、视窗范围和视埠范围——与映射方式密切相关。
Windows 定义了8 种映射方式:

您可以使用下面的函数调用来设定映射方式:
SetMapMode (hdc, iMapMode) ; //其中,iMapMode 是8 个映射方式关键字之一。
您可以通过以下调用取得目前的映射方式:
iMapMode = GetMapMode (hdc) ;
内定映射方式为MM_TEXT。在这种映射方式下,逻辑单位与实际单位相同,这样我们可以直接以像素为单位进行操作。
1、设备坐标和逻辑坐标
Windows 对所有消息(如WM_MOVE、WM_SIZE 和WM_MOUSEMOVE),对所有非GDI 函数,甚至对一些GDI 函数,永远使用设备座标。
由于映射方式是一种设备上下文属性,所以,只有对需要设备上下文代号作参数的GDI 函数,映射方式才会起作用。
1)、GetSystemMetrics 不是GDI函数,所以它总是以设备单位(即像素)为量度来传回大小的。
2)、GetDeviceCaps 尽管是GDI 函数,需要一个设备上下文代号作为参数,但是Windows 仍然对HORZRES 和VERTRES 以设备单位作为传回值,因为该
函数的目的之一就是给程序提供以像素为单位的设备大小。
3)、GetTextMetrics 传回的TEXTMETRIC 结构的值是使用逻辑单位的 。
四、绘制填充区域
Rectangle 直角矩形
Ellipse 椭圆
RoundRect 圆角矩形
Chord 椭圆周上的弧,两端以弦连接
Pie 椭圆上的圆形图
Polygon 多边形
PolyPolygon 多个多边形
Windows用设备上下文中选择的当前画笔来画图形的边界框,边界框还使用当前背景模式、背景色彩和绘图模式,这跟Windows 画线时一样。关与直线的一切也适用与这些图形的边界框。
图形以当前设备上下文中选择的画刷来填充。内定情况下,使用现有对象,这意味著图形内部将画为白色。Windows 定义六种现有画刷:WHITE_BRUSH、LTGRAY_BRUSH、GRAY_BRUSH、DKGRAY_BRUSH、BLACK_BRUSH 和NULL_BRUSH (也叫HOLLOW_BRUSH)。
示例代码:
HBRUSH hBrush ;
hBrush = GetStockObject (GRAY_BRUSH) ;
SelectObject (hdc, hBrush) ;
现在,如果您要画任一个图形,则其内部将为灰色。
如果您想画一个没有边界框的图形,可以将NULL_PEN 选进设备上下文:
SelectObject (hdc, GetStockObject (NULL_PEN)) ;
如果您想画出图形的边界框,但不填充内部,则将NULL_BRUSH 选进设备上下文:
SelectObject (hdc, GetStockobject (NULL_BRUSH) ;
您也可以自定义画刷,就如同您自定义画笔一样。
1、Polygon函数和多边形填充方式
1)、Polygon (hdc, apt, iCount) ;
apt为POINT结构数组,iCount是点的个数。。如果该数组中的最后一个点与第一个点不同,则Windows 将会再加一条线,将最后一个点与第一个点连起来。
2)、PolyPolygon (hdc, apt, aiCounts, iPolyCount) ;
该函数绘制多个多边形。最后一个参数给出了所画的多边形的个数。aiCounts 数组给出了多边形的端点数。apt 数组具有全部多边形的所有点。
3)、SetPolyFillMode (hdc, iMode) ;
该函数设置多边形的填充方式。内定情况下,多边形填充方式是ALTERNATE,但是您可以将它设定为WINDING。
程序5-5:
2、用画刷填入内部
画刷是一个8 x8 的点阵图,它水平和垂直地重复使用来填入内部区域。
windows 还有五个函数,可以让您建立逻辑画刷:
hBrush = CreateSolidBrush (crColor) ; //纯色画刷
hBrush = CreateHatchBrush (iHatchStyle, crColor) ; //阴影画刷
CreatePatternBrush和CreateDIBPatternBrushPt //建立自己的点阵图画刷。
hBrush = CreateBrushIndirect (&logbrush) ; //logbrush 是一个类型为LOGBRUSH 的结构。