现在的位置: 首页 > 综合 > 正文

学习0

2013年09月14日 ⁄ 综合 ⁄ 共 8258字 ⁄ 字号 评论关闭

2.

关于list
control

的高级应用---
条目编辑


http://www.fa39.com/Article/c/200610/1952.html

论坛中搜索一下,
你会发现不少类似的提问:
我如何编辑list control
的条目?
如何直接编辑list control...
等等;list control
可用来做数据库表的视图,
十分有用.

但报表风格的list control
只能编辑第一列,
其余的该死的微软没为vc
做到.
它怕VB
卖不出.
于是C++
程序员只好DIY.
主要思想是在list control
中动态创建一个控件,
动态移动该控件到相应位置.
这些方法早有人讨论过了,
本文也是基于如上思想的,
但注重于可扩充性与使用的方便.

List control
这头主要是重载OnLButtonDown
方法,
计算出被点中的条目.
这里重要的函数是SubItemHitTest
GetSubItemRect,
msdn
上有相关说明.
用户点中后,
就要负责显示控件了:
如果之前选中了其他,
就要验证之前的改动是否成功.
不成功就要回到原来的地方,
成功就应用修改并移到新位置.
看代码:

static     const UINT
IDCHAILD="3000";

void CValidateList::OnLButtonDown(UINT nFlags, CPoint
point)

{

             
CListCtrl::OnLButtonDown(nFlags, point);

       LVHITTESTINFO hi;

    hi.pt = point;

       if(SubItemHitTest(&hi)
!= -1 )//

没有点中条目就不管

       {if(m_col==-1||//-1
还没被选过

                    
true==(m_col+m_validate)->Validate (m_row))

             
{

m_row = hi.iItem, m_col= hi.iSubItem;//m_row,m_col

//
员分别跟踪选中的行列

}

((m_col+m_validate))->Move (_GetRect(),m_row);

       }

}

 

WinBlast* CValidateList::SetValidate( WinBlast*in)//
设置验证的

//
控件群,in
对应第一列,in+1
第二列……

{

      
WinBlast*ret=m_validate;

       m_validate=in;

       int
counts="GetHeaderCtrl"()->GetItemCount();;

       RECT rect;

    
memset(&rect,0,sizeof(rect));

       for(int
i="0";i< span>

        
(in+i)->Create (this,rect,IDCHAILD+i,i);

       m_col=-1;//
没有被选中的

       return ret;

}

 

 

RECT CValidateList::_GetRect()//
内部使用,
得到相应显示位置

{

       CRect ret;

GetSubItemRect(m_row,m_col,LVIR_BOUNDS,ret);

return ret;

}

 

void CValidateList::NoSelect()//
置未选中状态

{

m_col=-1;//
没有被选中的

}

看到了WinBlast*ret=m_validate
.WinBlast
是用来修改和验证数据的控件看它的实现:

class WinBlast 

{

       int m_col;//
跟踪列,
为什么要这个?
因为你可以让一种控件对

//
不同列用不同的验证策略

CWnd* m_win;//
你的控件窗口

       CListCtrl
*m_parent;//

用它获得文本

public:

      
WinBlast(){m_win=NULL;}

      
~WinBlast(){m_win->DestroyWindow();delete m_win;}

 

virtual     bool Create( CWnd*
pParentWnd,

             
const RECT& rect, UINT nID,

             
int col)

       {

             
m_col=col;m_parent=(CListCtrl *)pParentWnd;

             
m_win=new CEdit;

             
      return  ((CEdit*)m_win)->

                    
Create(ES_NOHIDESEL,rect,pParentWnd,nID);

             
}

       void Move(const RECT
&rect,int row)//

最重要的函数但前面

//
两个动作是必作的,SetText
为虚,
你在那做你喜欢的

; {

             
m_win->ShowWindow(SW_SHOW);

             
m_win->MoveWindow(&rect);

             
SetText(row);

       }

       virtual bool
Validate(int row)//

验证,
虚函数.
这里永远返回true

       {

             
m_win->ShowWindow(SW_HIDE);

             
CString set;

             
m_win->GetWindowText(set);

             
m_parent->SetItemText(row,m_col,set);

             
return true;

       }

       virtual void
SetText(int row)

       {

             
m_win->SetWindowText(m_parent->GetItemText(row,m_col));

             
((CEdit*)m_win)->SetSel (0,-1);

             
}

      

       };

实际使用通常是这样的:

       WinBlast*p=new
WinBlast[sizeof(col)/sizeof(col[0])];//col

         //
列名字符数组,sizeof(col)/sizeof(col[0])
计算列数

       m_test.SetValidate
(p);//m_test

CValidateList

你可以继承WinBlast,
重载Create
建立一个下拉框,
加入你喜爱的验证方法.

注意我的设计漏洞:CValidateList
应接收WinBlast**,
而不是WinBlast*-----
不理解这个漏洞其实也不要紧:
但要记住,
不改正的话你的WinBlast
后继类就不能加数据成员了.

 

3.

如何在
VC
MFC


List Control
中实现拷贝功能?

Reference:
http://zhidao.baidu.com/question/13639294.html


我在单文档视图中加入一个
List Control
控件
(Report
形式
)
,并关联类
CListCtrl
的一个对象,往里面写数据什么的都行,但在界面上无法实现对报表数据的拷贝(快捷或右键都不行),想请教如何实现拷贝该报表显示的数据?

1

CListCtrl
创建
click
事件,记录
item

2
在视图所在的类创建虚函数
PreTranslateMessage

加入代码

if(pMsg->message
== WM_KEYDOWN)

{

if(pMsg->wParam==13)//
这里
13
是表示回车键盘,你也可以改成其他的

{

copy();

}

}

3.
编写
copy
函数,取得
item
处的文本,保存只剪切板

 

4.

更改列表控件样式

创建列表控件 (List Control) (CListCtrl)
后,可以在任何时间更改它的窗口样式。通过更改窗口样式来更改控件使用的视图类型。例如,为了模拟“资源管理器”,您可以提供菜单项或工具栏按钮以在不同的视图(图标视图、列表视图等)之间切换控件。

例如,用户选择您的菜单项后,您可以调用 GetWindowLong
来检索控件的当前样式,然后调用 SetWindowLong
来重置样式。有关更多信息,请参见 Platform SDK

中的使用列表视图 (ListView)
控件。

可用样式在 Create
中列出。样式 LVS_ICON

LVS_SMALLICON

LVS_LIST


LVS_REPORT



指定四种列表控件 (List Control)
视图。

扩展样式

除了列表控件 (List Control)
的标准样式之外,还有另一个称为扩展样式的样式集。Platform SDK
中的扩展列表视图样式讨论了这些样式,这些样式可提供自定义列表控件 (List Control)
行为的各种有用功能。若要实现某个样式的行为(如随意选择),请调用 CListCtrl::SetExtendedStyle
传递所需的样式。下面的示例说明该函数调用:

m_myListCtrl.SetExtendedStyle(LVS_EX_TRACKSELECT |
LVS_EX_ONECLICKACTIVATE);

注意

   
要使随意选择起作用,还必须打开 LVS_EX_ONECLICKACTIVATE


LVS_EX_TWOCLICKACTIVATE

 

5.

在列表控件(
List
Control

)中实现工作区

Reference: http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/vccore/html/_core_changing_list_control_styles.asp


默认情况下,列表控件 (List Control)
按标准网格格式排列所有项。但也支持另一种方法:工作区。工作区将列表项排列到矩形组中。有关实现工作区的列表控件 (List Control)
的图像,请参见 Platform SDK
中的“使用列表-
视图控件”。

注意

   
工作区只有当列表控件 (List Control)
处于图标或小图标模式时才可见。但是,如果视图切换到报表或列表模式,将维持任何当前工作区。

工作区可用来显示空边框(在项的左侧、顶部和/
或 右侧),或在通常不会有水平滚动条的时候显示水平滚动条。另一个普通用法是创建多个工作区,可以将项移动或放置到这些工作区。使用该方法可以在单一视图中
创建具有不同意义的区域。然后用户可以将项放置到不同的区域以对它们分类。此类示例可以是一个文件系统的视图,它包含一个读/
写文件区,一个只读文件区。如果将文件项移动到只读区,它将自动变为只读。将文件从只读区移动到读/
写区会使文件成为可读/
写的。

CListCtrl


为创建和管理列表控件 (List Control)
工作区提供几个成员函数。GetWorkAreas
SetWorkAreas
检索并设置 CRect


对象(或 RECT


结构)数组,该数组存储当前实现的列表控件 (List Control)
工作区。另外,GetNumberOfWorkAreas
检索列表控件 (List Control)
的当前工作区数目(默认值为零)。

项和工作区

工作区创建后,工作区中的项成为其成员。同样,如果将一个项移动到某个工作区,则该项成为它所移动到的工作区的成员。如果某个项不在任何工作区中,则它自动成为第一个工作区(索引 0
)的成员。如果想创建项并将其放置到一个特定的工作区,则需要创建该项,然后调用
SetItemPosition

将项移动到所需工作区。下面的第二个示例说明该技术。

下面的示例在列表控件 (List Control) (

m_listctrl
)
中实现四个大小相等的工作区 (

rcWorkAreas
)
,每个工作区都有 10
像素宽的边框。

CRect curRect;

CSize size;

 

size= m_listctrl.ApproximateViewRect();

size.cx+= 100;

size.cy+= 100;

 

CRect rcWorkAreas[4];

 

rcWorkAreas[0].SetRect(0, 0, (size.cx / 2) - 5, (size.cy
/ 2) - 5);

rcWorkAreas[1].SetRect((size.cx / 2) + 5, 0, size.cx,
(size.cy / 2) - 5);

rcWorkAreas[2].SetRect(0, (size.cy / 2) + 5, (size.cx /
2) - 5, size.cy);

rcWorkAreas[3].SetRect((size.cx / 2) + 5, (size.cy / 2) +
5, size.cx, size.cy);

 

//set work areas

m_listctrl.SetWorkAreas(4, rcWorkAreas);

调用 ApproximateViewRect
来获取在一个区域显示所有项所需要的总区域大小的估计值。之后,该估计值被分成四个区域并用 5
像素宽的边框填充。

下一个示例将现有列表项分配给每一组 (

rcWorkAreas
)
并刷新控件视图 (

m_listctrl
)
以实现此效果。

// set insertion points for each work area

CPoint     rgptWork[4];

for (int i = 0; i < 4; i++)

{

     rgptWork[i].x =
rcWorkAreas[i].left + 10;

     rgptWork[i].y =
rcWorkAreas[i].top + 10;

}

// now move all the items to the different quadrants

for (i = 0; i < 20; i++)

     m_listctrl.SetItemPosition(i,
rgptWork[i % 4]);

 

// force the control to rearrange the shuffled items

m_listctrl.Arrange(LVA_DEFAULT);

 

6.

处理列表控件(
List
Control

)中的通知消息

Reference: http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/vccore/html/_core_changing_list_control_styles.asp


用户单击列标题、拖动图标、编辑标签等时,列表控件 (List Control) (CListCtrl)
将通知消息发送给它的父窗口。如果要进行某种响应,请处理这些消息。例如,用户单击列标题后,可能想基于单击的列的内容对项排序,如在 Microsoft Outlook
中所做的那样。

在视图或对话框类中处理列表控件 (List Control)
WM_NOTIFY


消息。基于正在处理的通知消息,用“属性”窗口创建带 switch
语句的 OnChildNotify
处理函数。

有关列表控件 (List Control)
可以发送到其父窗口的通知的列表,请参见 Platform SDK
中的列表视图 (ListView)
控件参考。

 

7.

虚拟列表控件

Reference: http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/vccore/html/_core_changing_list_control_styles.asp


虚拟列表控件指具有
LVS_OWNERDATA



样式的列表视图
(ListView)
控件。该样式启用控件来支持项数达到
DWORD


(默认的项数只扩展到
int


)。然而,该样式的最大便利是可以使内存中一次只有一个数据项子集。这使虚拟列表视图
(ListView)
控件可以将自己借给大型信息数据库使用,而在这类数据库中已存在特定的数据访问方法。

注意

   MFC
除了在
CListCtrl



中提供虚拟列表功能外,还在
CListView
类中提供相同的功能。

在开发虚拟列表控件时应注意一些兼容性问题。有关更多信息,请参见
Platform SDK

列表

-
视图控件
主题的
兼容性问题
一节。

处理



LVN_GETDISPINFO


通知

虚拟列表控件维护非常少的项信息。除了项选择和焦点信息,所有项信息都由控件的所有者管理。框架通过
LVN_GETDISPINFO



通知消息来请求信息。若要提供请求的信息,虚拟列表控件的所有者(或控件本身)必须处理该通知。使用
属性
窗口可以很容易地完成此操作(请参见

将消息映射到函数




)。所得到的代码应类似于下面的示例(其中

CMyListCtrl

是虚拟列表控件对象,控件正在处理通知)。

BEGIN_MESSAGE_MAP(CMyListCtrl,
CListCtrl)

  
ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)

END_MESSAGE_MAP()


LVN_GETDISPINFO



通知消息的处理程序中,必须检查正在请求的信息的类型。可能值是:

·
                

LVIF_TEXT

   
必须填写
pszText


成员。

·
                

LVIF_IMAGE

   
必须填写
iImage


成员。

·
                

LVIF_INDENT

   
必须填写
iIndent


成员。

·
                

LVIF_PARAM

   
必须填写
lParam


成员。

·
                

LVIF_STATE

   
必须填写
state


成员。

然后应将所有请求的信息提供给框架。

下面的示例摘自列表控件
(List Control)
对象的通知处理程序体,它通过为文本缓冲区和项的图像提供信息来说明一种可能的方法:

LV_DISPINFO* pDispInfo =
(LV_DISPINFO*)pNMHDR;

LV_ITEM* pItem=
&(pDispInfo)->item;

 

int iItemIndx=
pItem->iItem;

 

if (pItem->mask &
LVIF_TEXT) //valid text buffer?

{

   
switch(pItem->iSubItem){

       
case 0: //fill in main text

           
lstrcpy(pItem->pszText,

                m_Items[iItemIndx].m_strItemText);

           
break;

       
case 1: //fill in sub item 1 text

           
lstrcpy(pItem->pszText,

               
m_Items[iItemIndx].m_strSubItem1Text);

           
break;

       
case 2: //fill in sub item 2 text

           
lstrcpy(pItem->pszText,

               
m_Items[iItemIndx].m_strSubItem2Text);

           
break;

    }

}

 

if pItem->mask &
LVIF_IMAGE) //valid image?

       
pItem->iImage=

            m_Items[iItemIndx].m_iImageIndex;

缓存和虚拟列表控件


由于这种类型的列表控件
(List Control)
是提供给大的数据集的,因此建议您缓存请求的项数据以提高检索性能。框架提供缓存提示机制,通过发送
LVN_ODCACHEHINT



通知消息来帮助优化缓存。但是,您必须使用一种稍有不同的方法来处理该通知。使用
属性
窗口,重写列表控件

(List
Control)

对象的
OnChildNotify



函数。在该示例的情况下为

CMyListCtrl

在处理程序体中检查
LVN_ODCACHEHINT

抱歉!评论已关闭.