代码改变世界

CListBox的一个改写类(VC6添加文件的效果)

2014-11-25 01:31  sylar_liang  阅读(523)  评论(0编辑  收藏  举报

编写一个类似VC6添加文件,单击则动态显示一个Edit编辑框与一个Button。效果如下图:

1.新建一个类(如CMyListBox),继承自CListBox

2.头文件中定义Edit与CButton变量

CEdit m_edit;

CButton m_btn;

3.定义一个初始化函数,供对话框调用。

首先在.cpp中定义2个ID

#define MY_EDIT 10001

#define MY_BTN  10002

void CMyListBox::Init()
{
    m_edit.Create(WS_BORDER | WS_CHILD | ES_AUTOHSCROLL,CRect(0,0,10,10),this,MY_EDIT);
    // 设置字体
    // 方法一:
    HFONT hf = reinterpret_cast<HFONT>(::GetStockObject(DEFAULT_GUI_FONT));
    m_edit.SetFont(CFont::FromHandle(hf));
    // 方法二:
    //HFONT hf = CreateFont(22,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
    //    CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY,FIXED_PITCH,_T("Courier New"));
    //if(hf != NULL)
    //{
    //    ::SendMessage(GetDlgItem(MY_EDIT)->m_hWnd,WM_SETFONT,reinterpret_cast<WPARAM>(hf),TRUE);
    //}

    m_btn.Create(_T("..."),WS_CHILD,CRect(0,0,10,10),this,MY_BTN);

    m_menu.LoadMenu(IDR_MY_MENU);
}

4.重载OnLButtonDown 与 OnLbnSelchange 函数

(1)OnLbutton函数要做的是:

获取数据个数(GetCount);

判断左键按下是否在有效的行(GetItemRect); 不在,SetCurSel(-1);调用 更新显示函数(UpdateDisplay)。

void CMyListBox::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值

    // 获取个数
    int nCount = GetCount();
    int i = 0;
    CRect rc;
    for(i=0; i<nCount; ++i)
    {
        GetItemRect(i,rc);
        if(rc.PtInRect(point))
        {
            break;
        }
    }

    if(i >= nCount) // 未找到,不在
    {
        SetCurSel(-1);
        UpdateDisplay(); // 更新位置函数
    }

    CListBox::OnLButtonDown(nFlags, point);
}

(2)OnLbnSelchange函数:

判断edit与button是否可见,可见则隐藏。更新显示(UpdateDisplay)

void CMyListBox::OnLbnSelchange()
{
    // TODO: 在此添加控件通知处理程序代码
    if(m_edit.IsWindowVisible())
    {
        m_edit.ShowWindow(SW_HIDE);
    }
    if(m_btn.IsWindowVisible())
    {
        m_btn.ShowWindow(SW_HIDE);
    }
    UpdateDisplay();
}

更新显示函数(UpdateDisplay):

获取当前所选项(GetCurSel);为LB_ERR则让edit与button隐藏

获取按下位置的当前矩形大小GetItemRect;

edit与button根据获取到的矩形区域,设置rect,调用MoveWindow;

获取当前行的text,更新到edit控件上显示。

edit设置焦点。

// 更新显示函数
void CMyListBox::UpdateDisplay()
{
    int index = GetCurSel();
    if(index == LB_ERR)
    {
        if(m_edit.IsWindowVisible())
        {
            m_edit.ShowWindow(SW_HIDE);
        }
        if(m_btn.IsWindowVisible())
        {
            m_btn.ShowWindow(SW_HIDE);
        }
        return;
    }

    CRect rc;
    GetItemRect(index,rc); // 获取在第几行

    CRect rcEdit(rc.left,rc.top,rc.right-20,rc.bottom+5);
    m_edit.MoveWindow(rcEdit);

    CRect rcBtn(rc.right-20,rc.top,rc.right,rc.bottom+5);
    m_btn.MoveWindow(rcBtn);

    // 更新Edit显示内容
    CString strContent;
    GetText(index,strContent);
    m_edit.SetWindowText(strContent);
    m_edit.SetSel(0,-1); // 全选

    if(!m_edit.IsWindowVisible())
    {
        m_edit.ShowWindow(SW_SHOW);
    }
    if(!m_btn.IsWindowVisible())
    {
        m_btn.ShowWindow(SW_SHOW);
    }

    m_edit.SetFocus();
}

动态按钮(MY_BTN):

自定义消息与响应函数

afx_msg void OnMyBtnClick();
ON_BN_CLICKED(MY_BTN,OnMyBtnClick)

响应为 弹出一个选择文件夹对话框,点击确定后,更新CListBox中内容。

void CMyListBox::OnMyBtnClick()
{
    CString strPath;

    TCHAR szDir[MAX_PATH];
    BROWSEINFO bi;    
    bi.hwndOwner = this->m_hWnd;
    bi.pidlRoot = NULL;
    bi.pszDisplayName = szDir;
    bi.lpszTitle = _T("请选择目录");
    bi.ulFlags = BIF_STATUSTEXT | BIF_USENEWUI | BIF_RETURNONLYFSDIRS;
    bi.lpfn = NULL;
    bi.lParam = 0;
    bi.iImage = 0;

    ITEMIDLIST *pidl = SHBrowseForFolder(&bi);
    if(pidl == NULL)
    {
        return;
    }
    if(!SHGetPathFromIDList(pidl,szDir))
    {
        return;
    }
    else
    {
        strPath = szDir;
        UpdateContent(strPath); // 更新CListBox数据
    }
}

更新CListBox数据UpdateContent:

删除默认行,重新插入数据到当前行,末尾加上默认行,让edit与button隐藏

// 更新ListBox内容
void CMyListBox::UpdateContent(const CString str)
{
    int index = GetCurSel();
    DeleteString(index);
    AddString(str);

    InsertFlagString();
    SetCurSel(-1);
    SetFocus();

    if(m_edit.IsWindowVisible())
    {
        m_edit.ShowWindow(SW_HIDE);
    }
    if(m_btn.IsWindowVisible())
    {
        m_btn.ShowWindow(SW_HIDE);
    }
}

4. 右键菜单:删除

资源中添加菜单,类中定义一个CMenu变量。初始化时LoadMenu。

右键按下时响应函数OnRButtonDown:

void CMyListBox::OnRButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    CRect rc;
    CMenu *popMenu = m_menu.GetSubMenu(0);

    int nCount = GetCount();
    int i = 0;
    for(; i<nCount; ++i)
    {
        GetItemRect(i,rc);
        if(rc.PtInRect(point))
        {
            if(i == nCount-1)
            {
                SetCurSel(-1);
                popMenu->EnableMenuItem(ID_DELETE,MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); 
            }
            else
            {
                SetCurSel(i);
                popMenu->EnableMenuItem(ID_DELETE,MF_BYCOMMAND | MF_ENABLED); 
                break;
            }
        }
    }
    ClientToScreen(&point);
    popMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,point.x,point.y,this);

    CListBox::OnRButtonDown(nFlags, point);
}

删除(ID_DELETE)添加处理函数OnDelete:

void CMyListBox::OnDelete()
{
    // TODO: 在此添加命令处理程序代码
    int index = GetCurSel();
    DeleteString(index);
}

 

此时,初步完成以上效果,当点击...按钮弹出 "选择文件对话框",点OK后,更新显示在ListBox中。唯一不足是,edit数据内容只能通过...按钮点确定后才更改,直接点击修改不起作用。可能需要窗口子类化。有时间再修改。