WTL分列显示的ListBox

本文介绍如何在WTL中创建一个类似MFC类向导中分列显示的ListBox。通过设置ListBox属性为LBS_OWNERDRAWFIXED和LBS_HASSTRINGS,并在消息宏中添加REFLECT_NOTIFICATION()支持自画消息。数据列通过‘;’分隔,源代码中的m_nDivider控制列宽,当内容超宽时会自动调整。你可以根据需求修改代码以适应更多列数或自定义分隔符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        在界面数据显示时一般使用ListBox或支持分列显示的ListCtrl,如果同一个界面中有两个以上关联数据表格要显示,那么使用ListBox的好处在任何时候都可以清晰的表明数据行选中/未选中状态,从而表示表格之间的关系,而使用ListCtrl中则状态不明显,比如MFC类向导,其中的数据显示使用ListBox,在多个ListBox窗口中可以同时显示每个窗口的数据选中状态,注意一点,MFC类向导使用的ListBox是分列显示的。那么我们能否也实现一个分列显示的ListBox。在WTL可以轻易实现这一点。代码队在最后:

     如何使用:在WTL使用时,需要注意的是在资源编辑器中将ListBox属性设计为LBS_OWNERDRAWFIXED和LBS_HASSTRINGS,需要在消息宏添加REFLECT_NOTIFICATION()以支持自画消息。

BEGIN_MSG_MAP(CMainDlg)
    ...
    REFLECT_NOTIFICATION()
END_MSG_MAP()

在添加数据时数据之间使用“;”来进行列之间分开,当然你也可以修改源代码使用其他分隔符或者定义一个变量来指示分隔符,CDevListBoxImpl中的m_nDivider 用来控制列的宽度,如果某一行的列宽超过这个宽度将自动增加宽度来容纳内容,就象MFC的类向导所做的一样,我并没有指定具体一列的宽度,对于我来言,两列足够了。然后需要的话你也可以修改代码使用一个int数组来保存列宽,我相信这对你来言相当容易。

CDevListBoxImpl m_list

m_list.SubclassWindow(GetDlgItem(IDC_LISTBOX1);
m_list.AddString(_T(
" Item0;True " );
m_lsit.AddString(_T(
" Item1;False " );
....

CDevListBoxImpl的代码

class  CDevListBoxImpl :  public  CWindowImpl < CDevListBoxImpl, CListBox > ,                         public  COwnerDraw < CDevListBoxImpl >
{
public:
    CDevListBoxImpl()
    
{
        m_nDivider 
= 200
    }


    BEGIN_MSG_MAP(CDevListBoxImpl)
    MESSAGE_HANDLER(WM_CREATE, OnCreate)
    CHAIN_MSG_MAP_ALT(COwnerDraw
<CDevListBoxImpl>1)
                     DEFAULT_REFLECTION_HANDLER()
    END_MSG_MAP()

    
// overridden to provide proper initialization
    BOOL SubclassWindow(HWND hWnd)
    
{
        BOOL bRet 
= CWindowImpl<CDevListBoxImpl, CListBox>::SubclassWindow(hWnd);
        
if(bRet)
            Init();
        
return bRet;
    }

    LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
& bHandled)
    
{
        
// TODO : Add Code for message handler. Call DefWindowProc if necessary.
        Init();
        bHandled 
= FALSE;
        
return 1;
    }

// Implementation
    void Init()
    
{
        
// We need this style to prevent Windows from painting the button
        ModifyStyle(0, BS_OWNERDRAW | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS );
    }


    
void DrawItem ( LPDRAWITEMSTRUCT lpDIS )
    
{
        CDCHandle dc 
= lpDIS->hDC;
        CRect rect 
= lpDIS->rcItem;
        
if (m_nDivider==0)
            m_nDivider 
= rect.Width() / 2;

        
        
if (lpDIS->itemID != (UINT) -1)
        
{
            TCHAR sz[
128= {0};
            CListBox::GetText(lpDIS
->itemID,sz);
            COLORREF oldColor;
            
//draw two rectangles, one for each row column
            if (lpDIS->itemState & ODS_SELECTED  == ODS_SELECTED )
            
{
                dc.FillSolidRect(
&lpDIS->rcItem,RGB(0,0,128));
                oldColor 
= dc.SetTextColor(RGB(255,255,255));
            }

            
else
            
{
                dc.FillSolidRect(
&lpDIS->rcItem,RGB(255,255,255));
                oldColor 
= dc.SetTextColor(RGB(0,0,0));
            }


            dc.SetBkMode(TRANSPARENT);

            TCHAR 
* tok = ::_tcstok(sz,_T(";"));
            
while (tok != NULL)
            
{
                dc.DrawText(tok,lstrlen(tok),rect,DT_LEFT 
| DT_SINGLELINE);
                rect.left 
+= m_nDivider;
                SIZE sz;
                dc.GetTextExtent(tok,
-1,&sz);
                
if (sz.cx >= 2*m_nDivider)
                
{
                    rect.left 
= rect.left-m_nDivider+sz.cx+20;
                }

                
else if (sz.cx >= m_nDivider)
                
{
                    rect.left 
+= m_nDivider;
                }

                tok 
= ::_tcstok(NULL,_T(";"));
            }


            dc.SetTextColor(oldColor);
        }

        SetMsgHandled(FALSE);
    }

    
int    m_nDivider;
}
;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值