<!-- [if !mso]>
<style>
v/:* {behavior:url(#default#VML);}
o/:* {behavior:url(#default#VML);}
w/:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style>
<![endif]--><!-- [if gte mso 9]><xml>
<w:WordDocument>
<w:View>Normal</w:View>
<w:Zoom>0</w:Zoom>
<w:PunctuationKerning/>
<w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing>
<w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery>
<w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery>
<w:ValidateAgainstSchemas/>
<w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid>
<w:IgnoreMixedContent>false</w:IgnoreMixedContent>
<w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText>
<w:Compatibility>
<w:SpaceForUL/>
<w:BalanceSingleByteDoubleByteWidth/>
<w:DoNotLeaveBackslashAlone/>
<w:ULTrailSpace/>
<w:DoNotExpandShiftReturn/>
<w:AdjustLineHeightInTable/>
<w:BreakWrappedTables/>
<w:SnapToGridInCell/>
<w:WrapTextWithPunct/>
<w:UseAsianBreakRules/>
<w:DontGrowAutofit/>
<w:UseFELayout/>
</w:Compatibility>
<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
</w:WordDocument>
</xml><![endif]--><!-- [if gte mso 9]><xml>
<w:LatentStyles DefLockedState="false" LatentStyleCount="156">
</w:LatentStyles>
</xml><![endif]--><!-- [if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
</style>
<![endif]-->
// HitTestEx
- Determine the row index and column index for a point
// Returns
- the row index or -1 if point is not over a row
// point
- point to be tested.
// col
- to hold the column index
int
CMyListCtrl::HitTestEx(CPoint &point, int
*col) const
{
int
colnum = 0;
int
row = HitTest( point, NULL );
if
( col ) *col = 0;
// Make sure that the ListView is in LVS_REPORT
if
( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
return
row;
// Get the top and bottom row visible
row = GetTopIndex();
int
bottom = row + GetCountPerPage();
if
( bottom > GetItemCount() )
bottom = GetItemCount();
// Get the number of columns
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
int
nColumnCount = pHeader->GetItemCount();
// Loop through the visible rows
for
( ;row <= bottom;row++)
{
// Get bounding rect of item and check whether point falls in it.
CRect rect;
GetItemRect( row, &rect, LVIR_BOUNDS );
if
( rect.PtInRect(point) )
{
// Now find the column
for
( colnum = 0; colnum < nColumnCount; colnum++ )
{
int
colwidth = GetColumnWidth(colnum);
if
( point.x >= rect.left
&& point.x <= (rect.left + colwidth ) )
{
if
( col ) *col = colnum;
return
row;
}
rect.left += colwidth;
}
}
}
return
-1;
}
CListCtrl
类成员
CListCtrl::HitTest
int HitTest(LVHITTESTINFO* pHitTestInfo) const
int HitTest(CPoint pt,UINT* pFlags=NULL) const
返回值:
返回参数pHitTestInfo
指定位置的项的索引,否则为-1
。
参数: pHitTestInfo
含有要进行击中测试的位置以及接受击中测试有关结果信息的LVHITTESTINFO
结构的地址。
pt
被测试的指针。
pFlags
指向接受测试结果信息的整数的指针。请参阅联机文档“
平台SDK”
中有关LVHITTESTINFO
结构的flags
成员的注解。
说明:
如果有,则决定哪一个列表视图项在指定的位置上。
可以通过使用结构中flags
成员的LVHT_ABOVE,
LVHT_BELOW,LVHT_TOLEFT
以及LVHT_TORIGHT
的值来决定是否滚动列表视图控件的内容。上述两种标志可以自由组合,例如,假设其位于客户区域的左上角。
可以通过测试结构中flags
成员的LVHT_ONITEM
值来决定是否给定的位置位于列表视图项的上方。该数值通过结构flags
成员中的 LVHT_ONITEMICON
,LVHT_ONITEMLABEL,LVHT_ONITEMSTATEICON
的值的位或运算而获取。
HitTest
:得到当前鼠标位置的Item
其实关键是要有ScreenToClient
这个函数的使用,我先前没有用这个函数,HitTest
老是返回-1,
搞得我都头大了。不过这个不能用于SubItem,
那应该要用SubItemHitTest
LVHITTESTINFOht;
GetCursorPos(&(ht.pt));
m_friendList.ScreenToClient(&ht.pt);
m_friendList.HitTest(&ht);
if(ht.iItem==-1)
//
检查是否有item
选中
return;
SubItemHitTest
:
void CTest6Dlg::OnClickList1(NMHDR* pNMHDR,
LRESULT* pResult)
{
/****************************************/
/*
确定单击的listctrl
的行列号
方法1 */
/****************************************/
/*
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);
}
*pResult = 0;
}
双击时鼠标所在的位置。下面我们就再来为
CScheduleView
添加一个处理
NM_DBLCLK
通知消息的处理函数
OnDblclk()
,并输入下面的实现代码:
void CScheduleView::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult) {
if( ((LPNMLISTVIEW) pNMHDR)->iItem != -1 )
GetDocument()->OnEdittask();
*pResult = 0;
}
这个函数比较有意思,它的第一个参数本来是一个指向
NMHDR
结构的指针,然而在函数体中我们却将之强制转换成指向一个
NMLISTVIEW
结构的指针,为什么呢?原因是
4.71
版及更高版本的
List
控件(
IE 4.0
之后的
List
控件都满足版本要求)在发送通知消息
NM_DBLCLK
的时,实际上传递的是
一个
NMLISTVIEW
结构的指针,但标准的
NM_DBLCLK
消息传递的却是
NMHDR
结构的指针,
ClassWizard
在生成函数框架时是按照标
准消息格式来处理的。
NMLISTVIEW
结构除了在开头部分包含了一个
NMHDR
结构外,它还提供了被双击项目的相关信息,如果它的
iItem
成员等于
-1
,则表示用户不是对
着一个项目双击的,如果是这样的话,我们也就不必调用
OnEdittask()
,从而避免了出现不必要的操作提示信息。实际上,
OnLButtonDblClk()
也可以实现
OnDblclk()
的这个功能,但需要将相关代码改为:
if( GetListCtrl().GetSelectedCount() == 1 )
GetDocument()->OnEdittask();
现在这两个函数的功能就基本一致了,朋友们可以任意保留其中一个函数,而把另一个函数删掉,当然,今后在编写其它程序时
OnLButtonDblClk()
和
OnDblclk()
就不一定能做到等价了。另外,大家不妨进一步研究一下
WM_LBUTTONDBLCLK
和
NM_DBLCLK
之间的关系,解释为什么用户的一次双
击能引发这两种消息,它们的发生顺序又如何等等。
接下来我们再次利用
ClassWizard
为
CScheduleView
添加一个处理
WM_RBUTTONDOWN
消息的函数
OnRButtonDown()
,准备在其中弹出一个关联菜单。
编辑和使用弹出式菜单
关联菜单实质上是一种弹出式菜单,通常情况下,弹出式菜单相当于主菜单的一个子菜单项。我们打开资源编辑器,添加一个新的菜单资源,修改其
ID
为
IDR_TASKMENU
,然后在第一个顶级菜单项下面添加三个命令,它们与程序主菜单的
"
安排
"
子菜单下面的命令完全一样,包括
ID
、
Caption
和
Prompt
。编辑完毕后,以
Popup
方式来查看
IDR_TASKMENU
,其效果应如图
18-1
所示。
现在我们来为
OnRButtonDown()
编写实现代码:
void CScheduleView::OnRButtonDown(UINT nFlags, CPoint point) {
CMenu tmpMenu;
CMenu* pSubMenu;
tmpMenu.LoadMenu(IDR_TASKMENU); //
装载菜单资源
pSubMenu=tmpMenu.GetSubMenu(0); //
获得子菜单的指针
ClientToScreen(&point); //
将客户区的坐标位置转换成屏幕坐标位置
pSubMenu->TrackPopupMenu( TPM_RIGHTBUTTON|TPM_LEFTALIGN|TPM_TOPALIGN,
point.x, point.y, this,0 ); //
显示弹出式菜单
tmpMenu.DestroyMenu(); //
释放菜单资源
}
在上面的代码中,
LoadMenu()
用于装载菜单资源
IDR_TASKMENU
,由于我们使用了局部变量来存放不属于任何一个窗口的菜单对象,所以在退
出
OnRButtonDown()
函数之前必须释放相应的菜单资源,否则多次调用该函数之后,程序将会占掉不少的系统资源。
ClientToScreen()
的作用是将客户区的坐标位置转换成屏幕坐标位置,因为
WM_RBUTTONDOWN
消息中的鼠标位置参数是相对于客户区
的,而
TrackPopupMenu()
函数的参数必须是基于屏幕坐标系的,如果不经过一次转换,菜单弹出的位置就不知道会偏到哪里去了。
现在我们来运行一下
Schedule
,在客户区内单击鼠标右键,就会弹出如图
18-2
所示的关联菜单,选择命令之后它就会调用相应的处理函数。
到本讲为止,
Schedule
的编程工作也就要告一段落了,
Schedule
只是心铃用来讲解
VC
编程的一个实例,它的功能很单一,但仍有一定的实用价
值。已经用惯了各种优秀软件的朋友肯定不会满足于现在的
Schedule
,因为它现在只是一只丑小鸭而已,要把它变成一只天鹅还需要我们更多的辛
勤劳动,心铃在下面列出了一些可能的改进,希望已经喜爱上
VC
编程的朋友们自已动手来进一步修饰
Schedule
。
1
.删除
Schedule
中一些不必要的菜单命令和工具栏上的按钮;
2
.根据用户选中事件条目的情况自动改变某些菜单命令的有效状态,例如没有选中任何条目时,
"
编辑条目
"
应处于不能选择的无效状态,它所对应的工具按钮也应无效;
3
.让
Schedule
能够象网络蚂蚁那样在最小化时隐藏自己的窗口,在任务栏的通知区域内放置一个图标,并设计相关的菜单;
4
.修改
Schedule
的用户界面,设计更好的图标和位图;
5
.修改添加和编辑事件条目的对话框,让用户能更直观地设置时间;
6
.设计一个启动画面,把某些选项保存到注册表之中;
7
.为
Schedule
增添打印功能;
… …
等等
CListCtrl
几点经验
每个List
控件都有一个CHeaderCtrl
。且它的ID
是0
。
CHeaderCtrl* pHeader =(CHeaderCtrl*)m_listCtrl.GetDlgItem(0);
即使List
控件非report
模式,Header
控件也存在,只是此时它的尺寸为0
。
可利用以下代码使得控件的第一列自适应大小:
m_listctrl.SetColumnWidth( 0, LVSCW_AUTOSIZE );
List
控件中的图标初始化时可如下设置:
m_listCtrl.InsertItem( LVIF_TEXT | LVIF_IMAGE, nRow, sItemText, 0, 0, nImage
, NULL);
在运行中需动态改变可调用SetItem()
函数.
m_listCtrl.SetItem( 0, 0, LVIF_IMAGE, NULL, nImage, 0, 0, 0 );
删去图标可将nImage
设置为-1
。
以下代码可将列表框的第一列限定大小:
BOOL CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;
if((pHDN->hdr.code == HDN_BEGINTRACKW || pHDN->hdr.code == HDN_BEGIN
TRACKA)
&& pHDN->iItem == 0) // Prevent only first (col#
0) from resizing
{
*pResult = TRUE; // disable tracking
return TRUE; // Processed message
}
return CListCtrl::OnNotify(wParam, lParam, pResult);
}
选定cell
CListCtrl::OnClick(...)
{
int column;
CRect m_rect;
//the function below is provided in CListCtrl inPlace editing
int index = GetRowColumnIndex(point, &column);
if(index == -1)return;
int offset = 0;
for(int i = 0; i < column; i++)
offset += GetColumnWidth(i);
//Get the rectangle of the label and the icon
GetItemRect(index, &m_rect, LVIR_BOUNDS);
m_rect.left += offset + 4;
//Get the columnWidth of the selected column
m_rect.right = m_rect.left + GetColumnWidth(column);
Update(index);
CClientDC dc(this); //this is the pointer of the current view
dc.DrawFocusRect(m_rect);
}
Select NonFirst cell:
void CMyListCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
CListCtrl::OnLButtonDown(nFlags, point);
int index;
point.x = 2;
if( ( index = HitTest( point, NULL )) != -1 )
{
SetItemState( index, LVIS_SELECTED | LVIS_FOCUSED ,
LVIS_SELECTED | LVIS_FOCUSED);
}
}
HitTestEx
的代码如下:
判断点击的是哪一列:
// HitTestEx - Determine the row index and column index for a point
// Returns - the row index or -1 if point is not over a row
// point - point to be tested.
// col - to hold the column index
int CMyListCtrl::HitTestEx(CPoint &point, int *col) const
{
int colnum = 0;
int row = HitTest( point, NULL );
if( col ) *col = 0;
// Make sure that the ListView is in LVS_REPORT
if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
return row;
// Get the top and bottom row visible
row = GetTopIndex();
int bottom = row + GetCountPerPage();
if( bottom > GetItemCount() )
bottom = GetItemCount();
// Get the number of columns
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
int nColumnCount = pHeader->GetItemCount();
// Loop through the visible rows
for( ;row <=bottom;row++)
{
// Get bounding rect of item and check whether point falls in it.
CRect rect;
GetItemRect( row, &rect, LVIR_BOUNDS );
if( rect.PtInRect(point) )
{
// Now find the column
for( colnum = 0; colnum < nColumnCount; colnum++ )
{
int colwidth = GetColumnWidth(colnum);
if( point.x >= rect.left
&& point.x <= (rect.left + colwidth ) )
{
if( col ) *col = colnum;
return row;
}
rect.left += colwidth;
}
}
}
return -1;
}
选中一定范围内的Item
// SelItemRange - Selects/Deselect a range of items
// Returns - The number of new items selected
// bSelect - TRUE to select, FALSE to deselect
// nFirstItem - index of first item to select
// nLastItem - index of last item to select
int CMyListCtrl::SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem)
{
// make sure nFirstItem and nLastItem are valid
if( nFirstItem >= GetItemCount() || nLastItem >= GetItemCount() )
return 0;
int nItemsSelected = 0;
int nFlags = bSelect ? 0 : LVNI_SELECTED;
int nItem = nFirstItem - 1;
while( (nItem = GetNextItem( nItem, nFlags )) >=0
&& nItem <= nLastItem )
{
nItemsSelected++;
SetItemState(nItem, bSelect ? LVIS_SELECTED : 0, LVIS_SELECT
ED );
}
return nItemsSelected;
}
SetHeaderBitmap:
static int _gnCols = 5;
static int _gnColSize[] =
{
18,21,22,18,380
};
static CString _gcsColLabel[] =
{
_T("x"),
_T("x"),
_T("x"),
_T("x"),
_T("Description:")
};
void CRightView::BuildColumns()
{
// Insert the columns into the list control
LV_COLUMN lvCol;
lvCol.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM;
for (int i = 0; i < _gnCols; ++i)
{
lvCol.iSubItem = i;
lvCol.pszText = (char*)(LPCTSTR)_gcsColLabel;
lvCol.cx = _gnColSize;
lvCol.fmt = LVCFMT_LEFT;
m_ListCtrl->InsertColumn(i, &lvCol);
}
for (int x = 0; x < _gnCols-1; x++)
SetHeaderBitmap(x, nHeaderBmps[x], HDF_STRING);
}
void CRightView::SetHeaderBitmap(int nCol, int nBitmap, DWORD dwRemove)
{
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
HD_ITEM hdi;
hdi.mask = HDI_FORMAT;
pHeader->GetItem (nCol, &hdi);
hdi.mask = HDI_BITMAP | HDI_FORMAT;
hdi.fmt |= HDF_BITMAP;
hdi.hbm = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(nBitmap),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
if (dwRemove)
hdi.fmt &= ~dwRemove;
pHeader->SetItem (nCol, &hdi);
}
分享到:
相关推荐
这个"js获得1-99大写数字"的压缩包文件提供了一个已经封装好的解决方案。下面我们将详细探讨如何实现这一功能,以及相关的JavaScript知识。 首先,我们了解JavaScript中的数字转换。在JavaScript中,数字本身没有...
已获得了奖励参与机会,完成 5 个资源上传即可获得 1 次免费
3. 文章被评论:每篇文章被其他用户评论一次,博主将获得1个积分。这激励博主与读者互动,增加社区的活跃度。 4. 发表评论:用户每发表一条有价值的评论,可得1个积分。但要注意,自己给自己评论或博主回复评论是不...
每一轮会翻开一张新的卡片,玩家可以选择“bing”即标记这张卡片,如果标记的卡片与上一次标记的相同,玩家将获得1分。玩家可以随时改变标记的卡片,但只能同时标记一张。此外,有一种特殊卡片编号为999,若标记它且...
这意味着每个学生可以免费获得1张照片。但因为全班共有34位同学,我们需要额外加印30张(34 - 4 = 30)以确保每个人都能得到1张照片。 接下来,我们需要计算额外加印照片的费用。每张加印照片的价格是2.3元。因此,...
此外,默写和听写全对的学生将获得1个“笑脸”。考试成绩也被纳入评估,满分可得3分,95分和90分分别对应2分和1分的加分,其余成绩由英语组长根据具体情况决定奖励或惩罚。 整个方案由英语班长监督执行,同时其他...
现在,客户只需1万美元就可以获得V1 ColdFire内核的使用许可,享用30多年来从未停止前进脚步并经过验证的微控制器(MCU)技术。 “让开发人员花1万美元就可获得V1 ColdFire内核,飞思卡尔和IPextreme提供了一个...
对于这些销售团队,若能超额完成每季度30%的销售目标,团队成员将获得国外5日游、清华大学光华管理学院3日培训、年会表彰,店长将获得超出销售额2%的现金奖励,店员则获得1%的现金奖励。完成20%的目标,奖励为港澳5...
- **标价为零的文档**:对于免费文档,前200次下载,每被下载一次,用户获得1分系统奖励。当下载量超过500次后,在500-600次下载区间内,每被下载一次,用户将获得2分系统奖励。 4. **文档质量**:提供高质量的...
//那么getParameter("x") 得到1 function getParameter(paraName,wnd) { //如果不提供wnd参数,则默认为当前窗口 if(wnd == null) wnd = self; //得到地址栏上“?”后边的字符串 var paraStr = wnd.location....
具体来说,如果用户下载并登录电脑管家,每天保持30分钟的在线状态,就能得到1天的QQ等级加速,这个加速效果相当于原来的2天。另外,如果用户预约升级Win10,即使不下载电脑管家,也能额外获得0.2天的等级加速。 ...
因此,3号需要至少争取到一个支持,他可以选择给4号或5号1颗宝石,这样3号可以得到99颗,而另一个会得到1颗,形成多数票。 3. 对于2号,他知道3号会尝试拉拢4号或5号,所以2号可以提出一个方案,比如给4号和5号各1颗...
此时共分配了9席,剩余1席按照小数部分较大者的原则,C宿舍的小数部分最大,因此C宿舍再获得1席,最终分配结果为A2,B3,C5。 (2)Q值方法,用于衡量分配的相对不公平度。Q值是每个宿舍的学生人数与其已分配委员数...
定居点就是用来获取资源的,但就是定居点必须修建在道路连接到的地方,而且不能修在另一个定居点紧邻的几点,同时你每拥有一定居点可以获得1点積分。定居点可以升级为城市,花费为2粮食、3矿石,当有玩家掷出与城市...
这种情况下,1号海盗同样可以确保自己的生存,并且得到98枚金币,同时给予3号和4号各1枚金币以获得他们的支持。 ### 智力题2:猜牌问题 这个问题同样考验参与者的逻辑思维能力。假设S先生、P先生、Q先生三人知道...
例如,=AND(1=1,2+2=4)将得到1,因为其中的两个逻辑测试都为真。 13. OR函数 OR函数用于允许您执行复合的“或”逻辑测试。例如,=OR(1>1,2+2=4)将得到1,因为第二个逻辑测试的结果为真。 14. NOT函数 NOT函数...
潜力的候选结果中选优得到1不同层面的实验表明,层叠隐马模型的各个层面对汉语词法分析都发挥了积极的作用1实 现了基于层叠隐马模型的汉语词法分析系统ICTCLAS, 该系统在2002年的“九七三”专家组评测中获得第1名,在...
mouthbook聊天软件完成版第一部分mouthbook聊天软件完成版第一部分
3、博主的文章每被评论一次:可获得1分; 4、每发表一次评论:可获得1分(自己给自己评论、博主回复评论不获得积分); 5、博文阅读次数每超过100次:可获得1分,阅读加分最高加到100分,即文章点击上万次截止...
8. 19 - 18 - 1:连续减法,得到1,再减1得到0。 9. 73 + 15 - 26:先加15得到88,再减去26得到62。 10. 25 - 18 - 4:连续减法,先减去18得到7,再减去4得到3。 11. 87 - 48 - 14:先减去48得到39,再减去14得到25...