[MFC]CListBox列表框类

来源:互联网 发布:免费身份证扫描软件 编辑:程序博客网 时间:2024/05/29 12:30

1. 列表框控件简单介绍:

    1) 也是传统控件的一种;

    2) 其显示了包含叫做项的文本字符串列表,注意和下拉列表框(Combo Box)相区别,列表框中的项是永远显示出来的,而下拉列表框必须要点击下拉按钮,项才会显示出来,即列表框就是下拉列表框一直下拉出来的效果;

    3) 列表框可以选择性地(并不是强制性地将其中的项目分类),还具有滚动功能,使列表框中可以显示的项目数量不受列表框物理尺寸的限制;

    4) 只允许一次选择一个项,被选中的项用系统颜色COLOR_HIGHLIGHT加亮显示,鼠标移动到项上并不会加亮项,只有选中后才会高亮;

    5) 可以利用自制列表框的样式使列表框显示图形而不是字符串;


2. 创建列表框:

    1) 还是使用Create创建,但是列表框不再有标题了(字符串直接以项的形式出现),因此第一个参数lpszCaption就没有了,其他和CButton的Create的参数相同;

    2) 函数原型:BOOL CListBox::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);

    3) 示例:m_wndListBox.Create(WS_CHILD | WS_VISIBLE | LBS_STANDARD, rect, this, IDC_LISTBOX);

    4) dwStyle:WS都是正常的普通窗口的风格,以LBS打头的都是列表框独有的风格,即List Box Style的缩写,这里列举一些最常用的

LBS_STANDARD:是WS_BORDER、WS_VSCROLL、LBS_NOTIFY和LBS_SORT的组合,其中WS_BORDER指定了列表框具有可见的边框,WS_VSCROLL使其具有垂直滚条,LBS_NOTIFY使其产生的通知可以发给父窗口,LBS_SORT使其可以按字母顺序对项进行排序;

!!滚条并不是在任何时候都能出现,只有在尺寸小于显示全部数量时才会出现,如果想在任何时候都显示滚条,则必须OR一个LBS_DISABLENOSCROLL;

LBS_NOSEL:只能查看不能选择

LBS_MULTIPLESEL:可多选


3. 列表框的键盘接口:

    1) CListBox本身就具有键盘接口,可以使用上下、Page Up、Page Down等移动当前选项(当然高亮也会跟着移动);

    2) 字母快捷键:即按下一个字母键就会选中下一个以该字符开头的选项;

    3) 如果是多选列表框,则使用上下等方向键只能移动焦点矩形的位置而不能决定选中项的移动,只有按下空格键的时候才代表当前具有焦点的项被选中;


4. 在项中使用制表符:

    1) 同样,列表框中的项也是按照比例调间距的,所以无法使用空格来调整项中字符串的间距;

    2) 一种标准而美观的做法是利用制表符来调节项中字符串之间的间距;

    3) 要想在项中使用制表符,必须在Create的时候OR上一个LBS_USETABSTOPS;

    4) 要设置制表符之前必须先确定一个制表符的长度是多少,可以使用SetTabStops函数:

         i. 原型:BOOL CListBox::SetTabStops(const int &cxEachStop);

         ii. cxEachStop就是每个制表符的宽度,单位是”对话框单位测量距离“,一单位大约等于系统字体宽度的四分之一;

         iii. 在设置制表符之前一定要先使用该函数设定每个制表符的宽度,默认情况下该值为8,该数值还是比较合理的,因此不建议修改;

    5) 接下来就是在项中直接使用制表符了,但是不能直接在字符串中加入\t表示制表符,而必须通过SetTabStops来制定制表符具体出现在每个项的哪些位置:

         i. 对没错,还是SetTabStops因为MFC重载了它,可以让它有多种功能;

         ii. 原型:BOOL CListBox::SetTabStops(int nTabStops, LPINT rgTabStops);

         iii. nTabStops就是每个项中有几个制表符;

         iv. rgTabStops是一个int数组,依次存放每个制表符出现的位置,单位也是"对话框单位测量距离";

         v. 没错,Windows要求每个项中制表符出现的位置和数量都相同,毕竟这也是出于逻辑和美观;

    6) 使用范例:

m_wndListBox.SetTabStops(9); // 设置每个制表符的宽度为9int rgTabStops[4] = { 32, 48, 64, 128 }; // 每个项中制表符出现的位置m_wndListBox.SetTabStops(4, rgTabStops);

!!!项的附加文本:

            a. 每个项虽然都有自己的文本描述,但有时也有对该项进行一些附加描述的需要;

            b. 大多数附加描述不希望用户看到而只用于程序开发,因此这些附加文本不能显示给用户看;

            c. 解决这个需求的最简单方法就是使用制表符,只要将制表符定义在项宽度以外的地方,然后将附加文本写在该项之后即可;

            d. 这样附加文本不会显示在界面中,但是程序员可以通过GetText函数获取完整的具有附加文本的项的内容了;

            e. 函数原型:两个版本,一种是C风格字符串,一种格式CString

                 i. int CListBox::GetText(int nIndex, LPTSTR lpszBuffer) const;

!!如果调用之前不知道字符串的大小,则可以使用GetTextLen看一下字符串长度:int CListBox::GetTextLen(int nIndex); // 如果错误则返回LB_ERR

!!该函数根据索引返回相应项的字符串,保存在lpszBuffer中;

!!返回值表示返回的字符串的长度;

                 ii. void CListBox::GetText(int nIndex, CString& rString) const;

!!返回的字符串输出到参数rString中;


5. 列表框的重画:

    1) 默认条件下,每当列表框添加或删除项的时候列表框都会重画,但有时候你并不像这样做,比如一次性添加大量项,而此时每添加一项就会重画一次,这会导致难看的闪烁;

    2) 一种消极的方法就是在列表框Create的时候OR上一个LBS_NOREDRAW标记,这样列表框永远都不会重画了,除非整个客户区重画才会跟着一块儿被重画,这种方式下就必须在修改完列表框之后调用Invalidate函数重画整个客户区;

    3) 第二种方法是标准合理的做法,就是用SendMessage给列表框发送WM_SETREDRAW消息:

         i. 函数原型:LRESULT CWnd::SendMessage(UINT message, WPARAM wParam, LPARAM lParam);

         ii. 当然message应该传WM_SETREDRAW,而wParam对于消息WM_SETREDRAW只有两个选项,一个是FALSE还有一个就是TRUE,lParam对于WM_SETREDRAW没有用,因此传0即可;

         iii. FALSE表示关闭重画功能,TRUE表示开启重画功能,并且调用完SendMessage后立马就重画一次,因此可以在大批量修改列表框之前先FALSE,修改完之后再还原为TRUE,这样就只重画了一次列表框,而不是整个客户区,节省了大量的时间和资源;


6. 添加、插入和删除项:

    1) 添加项:使用AddString即可

         i. 原型:int CListBox::AddString(LPCTSTR lpszItem);

         ii. 该函数直接将lpszItem添加到末端,如果列表框具有LBS_SORT样式则会对其排序;

         iii. 返回实际添加到的位置(从0开始索引);

    2) 插入项:使用InsertString即可

         i. 原型:int CListBox::InsertString(int nIndex, LPCTSTR lpszItem);

         ii. 将lpszItem插入到nIndex指定的索引位置处(从0开始的索引);

         iii. 该函数将返回实际被插入的位置;

         iv. 使用InsertString由于是直接指定了具体的位置,所以LBS_SORT样式也对其无效,无法加入排序;

    3) 插入和添加失败的时候会返回LB_ERRSPACE表明内存不够,或者直接返回LB_ERR表示其它类型的错误;

    4) 获取列表框中当前项的个数:int CListBox::GetCount() const;

    5) 删除项:使用DeleteString即可

         i. 原型:int CListBox::DeleteString(UINT nIndex);

         ii. 该函数根据索引值删除,返回值表示删除该项后剩余的项的数量;


7. 检索项:

    1) 使用GetCurSel获取当前被选中的项的索引号:

         i. 原型:int CListBox::GetCurSel() const;

         ii. 该函数不能对多选列表框调用,因为其只能返回一个项的索引;

    2) 指定选中的项:

         i. 原型:int CListBox::SetCurSel(int nSelect);

         ii. 将nSelect索引号所指的项设为当前被选中的项;

         iii. 选中后,目标项被滚入视野,并且高亮移动,该函数同样不能使用在多选列表框中;

!!GetCurSel和SetCurSel都会在发生错误的时候返回LB_ERR;

    3) 根据字符串内容来选择项:SelectString

         i. 原型:int CListBox::SelectString(int nStartAfter, LPCTSTR lpszItem);

         ii. nStartAfter:从该项指定的后一项开始匹配,也就是说nStartAfter指定了开始匹配的前一项的索引;

         iii. lpszItem:匹配的内容,规则是前缀匹配,并且大小写不敏感,从开始处匹配到第一个符合要求的就立即返回;

         iv. 如果出现错误或者没有匹配到则返回LB_ERR,并且当前选中项不会改变;

         v. 如果成功的话则返回选中项的索引号;

    4) 查找但不修改:使用Find函数,根据字符串内容返回项的索引

         i. 前缀匹配,无视大小写:int CListBox::FindString(int nStartAfter, LPCTSTR lpszItem) const;

         ii. 精确匹配,无视大小写:int CListBox::FindStringExact(int nStartAfter, LPCTSTR lpszItem) const;


8. 多选列表框的操作:

     1) 由于可以同时选中多个项因此GetCurSel、SetCurSel、SelectString函数都不能使用了;

     2) 选中和取消选中:使用SetSel和SelItemRange,这些都是都选列表框专用的!!

          i. int CListBox::SetSel(int nIndex, BOOL bSelect = TRUE);

!!将指定索引处的项设为TRUE(被选中,并且被高亮),FALSE将取消选中(同时取消高亮);

!!该函数可以反复调用,进行多项的修改;

          ii. int CListBox::SelItemRange(BOOL bSelect, int nFirstItem, int nLastItem);

          iii. 该函数支持一次性修改一整个连续的范围,从nFirstItem到nLastItem返回的索引值,bSelect决定选中还是不选中;

    3) 获取选中项的个数:int CListBox::GetSelCount() const;

    4) 获取选中项的列表:使用GetSelItems

         i. 原型:int GetSelItems(int nMaxItems, LPINT rgIndex) const;

         ii. nMaxItems指定最多返回多少个被选中的项,rgIndex为选中项的列表,元素是索引;

         iii. 当然可能nMaxItems给太多,超出实际被选中的项的数量,但不过返回值就是实际被选中的数量,所以nMaxItems要足够大,rgIndex也要足够大;

    5) 焦点矩形:既然有多个项可以被选中,那么键盘上下键等的移动怎么被反应出来呢?因为键盘上下键等的移动在单选列表框中是直接移动选中项的,所以,多选列表框中移动的是焦点矩形,焦点矩形在视觉画面上就是项的边框被高亮了,如果按下空格,焦点矩形所在的项就会被选中(整个项的矩形被高亮),如果再按空格,则有会不选中;

!!也就是说选中项可以有多个,但焦点矩形只有一个,表示当前正注视着的位置;

    6) 获取焦点矩形的位置:int CListBox::GetCaretIndex() const; // 可以看到焦点矩形被形象地称作光标,因为光标就只是当前注视的位置

    7) 设置焦点矩形的位置:int CListBox::SetCaretIndex(int nIndex, BOOL bScroll = TRUE); // bScroll是滚动选项,一般选TRUE即可,无需改变

    8) GetText、GetTextLen、FindString、FindStringExact等使用还是和单选列表框一样;


9. 列表通知:

    1) 列表框可产生的通知有很多,以LBN_打头,即List Box Notify的缩写;

    2) 通知同样也是包装在WM_COMMAND中的;

    3) 主要有以下几个:

LBN_SETFOCUS:列表框获得输入焦点

LBN_KILLFOCUS:列表框失去输入焦点

LBN_ERRSPACE:内存不足

!!以上三种消息和列表框本身的样式无关,都是普通窗口具有的能力

LBN_DBCLK:项被双击

LBN_SELCHANGE:项被修改

LBN_SELCANCEL:项被取消

!!以上这三个都和列表框本身的样式有关,必须是LBS_NOTIFY后者LBS_STANDARD样式的才会产生这3个通知;

    4) 项双击消息LBN_DBCLK:双击后在消息处理程序中,单选列表用GetCurSel获取被选中的项,而在多选列表中使用GetCaretIndex获取当前焦点矩形,因为单击一次选中,再单击一次又取消选中了,就只剩高亮的外框了;

    5) LBN_SELCHANGE:

         i. 对于单选列表:当选中项改变(移动)的时候产生;

         ii. 对于多选列表:焦点矩形移动时产生;

0 0
原创粉丝点击