无我

让内心永远燃烧着伟大的光明的精神之火!
灵活的思考,严谨的实现
豪迈的气魄、顽强的意志和周全的思考

MFC的listctrl控件中水平添加按钮并刷新

      这个项目中需要用MFC实现一个界面功能:listctrl中水平添加按钮。
      MFC本身的listctrl控件只能显示简单的文本,简单的添加按钮也不是一两句代码能解决的问题,从这方面讲,MFC开发界面真是不得已而为之。
   
      因为需要的按钮数目是不确定的,所以只能是动态创建,然后再根据listctrl控件的位置计算出按钮应该放置的位置,然后将按钮移动到指定坐标。
      对MFC里面的类和关系,我并不熟悉,所以花了很长时间搜索,最终在下载的好几个版本的代码中找了一个基本可用的,修改开发。

   一、      针对我们需要管理自己动态创建的按钮,所以我们自定义了一个CButton的子类。

 1
 2class CButtonEx : public CButton
 3{
 4    DECLARE_DYNAMIC(CButtonEx)
 5
 6public:
 7    CButtonEx();
 8    CButtonEx( int nItem, int nSubItem, CRect rect, HWND hParent,void * pData );
 9    virtual ~CButtonEx();
10
11protected:
12    DECLARE_MESSAGE_MAP()
13public:
14    afx_msg void OnBnClicked(); //点击响应函数
15    int m_inItem;           //所属listctrl的行
16    int m_inSubItem;        //所属listctrl的列
17    CRect m_rect;           //按钮所在的位置
18    HWND m_hParent;         //按钮的父窗口
19    BOOL bEnable;
20    void * m_pData;         //按钮带的用户自定义数据
21}
;

1CButtonEx::CButtonEx( int nItem, int nSubItem, CRect rect, HWND hParent,void * pData )   
2{
3    m_inItem = nItem;
4    m_inSubItem = nSubItem;
5    m_rect = rect;
6    m_hParent = hParent;
7    bEnable = TRUE;
8    m_pData = pData;
9}

      按钮点击的响应逻辑在OnBnClicked函数中。之所以加入m_pData成员变量,是便于存放用户自定义数据,这样就可以在OnBnClicked函数中根据自定义变量做出相应的处理。

  二、自定义listctrl子类
 1#pragma once
 2
 3#include "ButtonEx.h"
 4#include <map>
 5using namespace std;
 6
 7typedef map<int,CButtonEx*> button_map;
 8// CListCtrlEx
 9
10class CListCtrlEx : public CListCtrl
11{
12    DECLARE_DYNAMIC(CListCtrlEx)
13
14public:
15    CListCtrlEx();
16    virtual ~CListCtrlEx();
17
18protected:
19    DECLARE_MESSAGE_MAP()
20
21public:
22    //动态创建Button
23    void createItemButton( int nItem, int nSubItem, HWND hMain,LPCTSTR lpszCaption ,void * pData);
24    //释放创建的Button
25    void release();
26    void deleteItemEx( int nItem );
27    button_map m_mButton;
28
29public:
30    UINT m_uID;     
31    CFont font ;    //按钮上面的字体
32    void updateListCtrlButtonPos(); //更新按钮的位置
33    //void enableButton( BOOL bFlag, int iItem );
34    //重载水平滚动条滚动函数
35    afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
36}
;

CListCtrlEx实现如下:
 1CListCtrlEx::CListCtrlEx()
 2{
 3    m_uID = 0;
 4
 5    font.CreatePointFont(100,"宋体");
 6}

 7
 8CListCtrlEx::~CListCtrlEx()
 9{
10    release();
11}

然后是创建按钮的逻辑,注意我这里是在ListCtrl控件中水平添加按钮(同一行的每一列),而不是垂直(同一列的每一行):
 1void CListCtrlEx::createItemButton( int nItem, int nSubItem, HWND hMain,LPCTSTR lpszCaption ,void * pData)
 2{
 3    CRect rect;
 4    /*if( !EnsureVisible(nItem, TRUE)) 
 5        return ;*/

 6
 7    GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);
 8    rect.bottom = rect.top + 150;
 9    //rect.right = rect.left + 150;
10
11    DWORD dwStyle =  WS_CHILD | WS_VISIBLE | BS_MULTILINE;
12    CButtonEx *pButton = new CButtonEx(nItem,nSubItem,rect,hMain,pData);
13    m_uID++;
14
15    pButton->Create(lpszCaption,dwStyle, rect, this, m_uID);
16    //CDC* pDC = pButton->GetDC();
17    //pDC->SetTextColor(RGB(255,0,0));
18    pButton->SetFont(&font);
19    
20   // m_mButton.insert( make_pair( nItem, pButton ) );    //纵向添加用
21    m_mButton.insert( make_pair( nSubItem, pButton ) ); //单行横向添加用
22    
23    return;
24}

25
上面的代码中,我将按钮的高都设为了150,而不是listctrl默认的一点点高。
 1void CListCtrlEx::release()
 2{
 3    button_map::iterator iter = m_mButton.begin();
 4    while ( iter != m_mButton.end() )
 5    {
 6        delete iter->second;
 7        iter->second = NULL;
 8        iter++;
 9    }

10    m_mButton.clear();
11}

当完成以上代码以后,就可以在对话框中添加listctrl控件的成员变量了:CListCtrlEx m_lsPath;
然后在OnInitDialog函数中给listctrl控件添加按钮:
1int i = 0;
2    m_lsPath.InsertColumn(i,_T(""),LVCFMT_LEFT,150); 
3
4    nRow = m_lsPath.InsertItem(0"tim");
5
6    TCHAR caption[1000= {0};//标题
7    ImageCfg * pImageCfg = new ImageCfg;//自定义数据
8    m_lsPath.createItemButton(nRow,i++,m_lsPath,caption,pImageCfg);

这样看起来一切很好,但是运行时发现,当按钮较多需要水平滚动条时,拖动水平滚动条并不能正确的显示按钮!
所以我们还需要处理CListCtrlEx的水平滚动命令:
1void CListCtrlEx::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
2{
3    // TODO: 在此添加消息处理程序代码和/或调用默认值    
4    CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
5    updateListCtrlButtonPos();
6    //Invalidate(FALSE);
7}
 
 1void CListCtrlEx::updateListCtrlButtonPos()
 2{
 3    button_map::iterator iter = m_mButton.begin();
 4    button_map::iterator itrEnd = m_mButton.end();
 5    //调整横向的
 6    int posx = GetScrollPos(SB_HORZ);//取得水平滚动条的位置
 7    for (;iter != itrEnd;++iter)
 8    {
 9        CRect rect;
10        rect = iter->second->m_rect;
11        rect.left -= posx;
12        rect.right -= posx;
13        iter->second->ShowWindow( SW_HIDE );
14
15        iter->second->MoveWindow( &rect );
16        iter->second->ShowWindow( SW_SHOW );
17        /*if( iLine < iTopIndex )
18        {
19            iterUp->second->ShowWindow( SW_HIDE );
20        }*/

21    }

22    return;
23}

这里操作的过程是:取得控件水平滚动条的位置,然后将所有按钮的水平坐标左移响应的值。其实这里可以优化一下:判断只有那些按钮会被显示才处理,其他的并不需要处理,例如:
 1void CListCtrlEx::updateListCtrlButtonPos()
 2{
 3    button_map::iterator iter = m_mButton.begin();
 4    button_map::iterator itrEnd = m_mButton.end();
 5
 6    CRect rect;
 7    GetClientRect(rect);
 8    LONG width = rect.right;
 9    //调整横向的
10    int posx = GetScrollPos(SB_HORZ);//取得水平滚动条的位置
11    for (;iter != itrEnd;++iter)
12    {
13        iter->second->ShowWindow( SW_HIDE );
14
15        rect = iter->second->m_rect;
16        rect.left -= posx;
17        rect.right -= posx;
18        if (rect.right > 0)
19        {
20            if (rect.left > width)
21            {
22                //其他的都超出了显示范围
23                break;
24            }

25            iter->second->MoveWindow( &rect );
26            iter->second->ShowWindow( SW_SHOW );
27        }

28                
29        /*if( iLine < iTopIndex )
30        {
31            iterUp->second->ShowWindow( SW_HIDE );
32        }*/

33    }

34    return;
35}
 
这样,按钮就能正确刷新了。

不过,还有一个小问题:在拖动滚动条时,我们发现界面有些闪烁。但是我还没找到合适的解决方法。欢迎大家给出可行的方案。

posted on 2014-05-10 17:01 Tim 阅读(5722) 评论(0)  编辑 收藏 引用 所属分类: windows系统


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2014年5月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

导航

统计

公告

本博客原创文章,欢迎转载和交流。不过请注明以下信息:
作者:TimWu
邮箱:timfly@yeah.net
来源:www.cppblog.com/Tim
感谢您对我的支持!

留言簿(9)

随笔分类(173)

IT

Life

搜索

积分与排名

最新随笔

最新评论

阅读排行榜