MFC - 控件 - VSLISTBOX

文章介绍了如何在MFC中对VSListBox控件进行子类化以增加功能,如插入重复文本的控制、添加和重命名项目后的操作,以及设置回调函数。同时,还展示了如何遍历文件目录并使用ShellListControl。

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

VSListBox 控件

VSListBox与其它list控件不同,它们的类从CStatic的继承时已经分开了,并且vslistbox比较封闭,没有提供任何消息时间和命令,我们使用该控件的唯一方法子类化CVSListBox类,通过重载其中虚函数的方式来实现我们的功能。虽然vslistbox非常封闭,但是我们依然可以从微软MSDN的文档中窥见一隅,实现一些并不十分复杂的功能。

VSLISTBOX的继承:CStatic  —-  CVSListBoxBase  —-  CVSListBox  —-  CVSLIST(我们自己从CVSListBox中继承的类)

MFC中CVSListBox看起来很好的样子,其实并不是像看起来那样。这个控件封装的很严密,在向导里并不能添加消息响应事件之类的东西。
微软MSDN上也没有什么有用的信息,幸好略微提供了一个源码,说了怎样写派生类。

#pragma once
// VSListBoxWLS.h : 定义文件
#include"afxvslistbox.h"
//
// CVSListBoxWLS
//by wls 作者
//The memory leaks is made by  MFC,not me,for the little buttons in CVSListBox called CMFCToolTipCtrl or something named XXXButton.
//内存泄漏是由MFC,而不是我,为CVSListBox中称为CMFCToolTipCtrl或命名为XXXButton的小按钮。
//If you change the Appearance of CVSListBox to false,it will work with no memory leaks.
// 如果您将CVSListBox的Appearance更改为false,它将在没有内存泄漏的情况下工作。

// 注:wls是作者写的

// 函数指针
typedef BOOL (*FUNCDOSOMETHING)(LPVOID /*lpRawData*/,LPVOID /*lpNewData*/,CObject* /*pObj*/); //You know that

BOOL FuncDoNothing(LPVOID,LPVOID,CObject*);//An idle function to do nothing

class CVSListBoxWLS : public CVSListBox
{
    DECLARE_DYNAMIC(CVSListBoxWLS)

public:
    CVSListBoxWLS();
    virtual ~CVSListBoxWLS();

private:
    BOOL m_bEnableRepeatText;	
    // True for enable to insert repeat text,false for disable.启用插入重复文本为True,禁用为false。
    
    BOOL m_bDoAfterAddItemWhenever;
    // True for enable to do something whenever really insert text or not due to m_bEnableRepeatText, false for only really inserting text
    // 由于m_bEnableRepeatText,当真正插入文本或不插入文本时启用为True,仅真正插入文本为false
    
    BOOL m_bDoAfterRenameWhenever;// The usage like above
    BOOL m_bAddItem;
    BOOL m_bCheckTextLen;
    BOOL m_nTextLen;

    CString m_strWhenSelecting;		// The raw string
    CString m_strAfterOp;			// The new string
    CObject* m_pObjforOperatingFunc;

    FUNCDOSOMETHING m_fdsBeforeRemoveItem;
    FUNCDOSOMETHING m_fdsAfterAddItemNoRepeat;
    FUNCDOSOMETHING m_fdsAfterAddItemWhenever;
    FUNCDOSOMETHING m_fdsAfterRenameItemNoRepeat;
    FUNCDOSOMETHING m_fdsAfterRenameItemWhenever;

private:
    BOOL IsExistText(CString strText);
    void GetItemTextAfterOp(int nItem);

public:
    CString GetTextWhenSelecting();

    void EnableRepeatText(BOOL bRepeat=FALSE);
    // It depends the client code in where you save all the data to the very end.
    // 这取决于你把所有数据保存到最后的客户端代码。
    void EnableDoAfterAddItemWhenever(BOOL bRepeat=FALSE);		// 添加新item之后,作用呢?
    void EnableDoAfterRenameWhenever(BOOL bRepeat=FALSE);		// 改名之前??

    void EnableCheckTextLen(BOOL bChk=FALSE);		// 检查文本长度
    void SetTextLegalLength(int nLen=10);			// 设置合法长度

    void SetObjforOperation(CObject* obj=NULL);		// 设置对象操作属性

    void SetOperationBeforeRemoveItem(FUNCDOSOMETHING fds);				// 移除操作之前 操作
    void SetOperationAfterAddItemNoRepeat(FUNCDOSOMETHING fds);			// 添加item 没有重复
    void SetOperationAfterAddItemWhenever(FUNCDOSOMETHING fds);			// 添加item
    void SetOperationAfterRenameItemNoRepeat(FUNCDOSOMETHING fds);		// 重命名item 没有重复
    void SetOperationAfterRenameItemWhenever(FUNCDOSOMETHING fds);		// 重命名item

public:
    void SetItemText(int nIndex, const CString& strText);				// 更改item内容

    BOOL OnBeforeRemoveItem(int iItem);									// 移除 item 之前
    void OnAfterAddItem(int nItem);										// 添加 item
    void OnAfterRenameItem(int nItem);									// 重命名 item
    void OnSelectionChanged();											// 更改选中item

protected:
    DECLARE_MESSAGE_MAP()
};

说明:

  • Enable开头的函数设置功能开关,默认关闭状态。
  • SetOperation开头的函数设置类似回调函数的功能,默认执行空操作。
  • SetObjfor开头的函数设置类似回调函数中执行功能时可能用到的外部类变量
  • Get和Set不解释。
  • On开头的函数是重写了基类的响应函数
// VSListBoxWLS.cpp : 实现文件
//

#include "stdafx.h"
#include "VSListBoxWLS.h"

BOOL FuncDoNothing(LPVOID,LPVOID,CObject*){return TRUE;}
// CVSListBoxWLS

IMPLEMENT_DYNAMIC(CVSListBoxWLS, CVSListBox)

CVSListBoxWLS::CVSListBoxWLS()
{
    m_bEnableRepeatText=FALSE;
    m_bDoAfterAddItemWhenever=FALSE;
    m_bDoAfterRenameWhenever=FALSE;
    m_bAddItem=FALSE;

    m_bCheckTextLen=FALSE;
    m_nTextLen=10;

    m_fdsBeforeRemoveItem=FuncDoNothing;
    m_fdsAfterAddItemNoRepeat=FuncDoNothing;
    m_fdsAfterAddItemWhenever=FuncDoNothing;
    m_fdsAfterRenameItemNoRepeat=FuncDoNothing;
    m_fdsAfterRenameItemWhenever=FuncDoNothing;

    m_strWhenSelecting=TEXT("");
    m_strAfterOp=TEXT("");

    m_pObjforOperatingFunc=NULL;
}

CVSListBoxWLS::~CVSListBoxWLS()
{
}

BEGIN_MESSAGE_MAP(CVSListBoxWLS, CVSListBox)
END_MESSAGE_MAP()

void CVSListBoxWLS::SetTextLegalLength(int nLen/*=10*/)
{
    m_nTextLen=nLen;
}

void CVSListBoxWLS::EnableDoAfterRenameWhenever(BOOL bRename)
{
    m_bDoAfterRenameWhenever=bRename;
}

void CVSListBoxWLS::EnableRepeatText(BOOL bRepeat)
{
    m_bEnableRepeatText=bRepeat;
}

void CVSListBoxWLS::EnableDoAfterAddItemWhenever(BOOL bRepeat)
{
    m_bDoAfterAddItemWhenever=bRepeat;
}

void CVSListBoxWLS::EnableCheckTextLen(BOOL bChk/*=FALSE*/)
{
    m_bCheckTextLen=bChk;
}

void CVSListBoxWLS::OnSelectionChanged()
{
    m_strWhenSelecting=GetItemText(GetSelItem());
    OutputDebugString(TEXT("[")+m_strWhenSelecting+TEXT("]\n"));
}

void CVSListBoxWLS::SetItemText(int nIndex, const CString& strText)
{
    CString strPrompt;
    if (m_bEnableRepeatText==FALSE && IsExistText(strText))
    {
        strPrompt.Format(TEXT("【%s】已存在"),strText);
        MessageBox(strPrompt,TEXT("提示"),MB_ICONINFORMATION|MB_OK);

        m_bAddItem=FALSE;

        return;
    }

    if (strText==TEXT(""))
    {
        strPrompt.Format(TEXT("未输入内容"),strText);
        MessageBox(strPrompt,TEXT("提示"),MB_ICONINFORMATION|MB_OK);

        m_bAddItem=FALSE;
    }

    if (m_bCheckTextLen==TRUE && strText.GetLength()>m_nTextLen)
    {
        strPrompt.Format(TEXT("请输入%d个以内的字符"),m_nTextLen);
        MessageBox(strPrompt,TEXT("提示"),MB_ICONINFORMATION|MB_OK);

        m_bAddItem=FALSE;

        return;
    }

    m_bAddItem=TRUE;

    CVSListBox::SetItemText(nIndex,strText);
}

BOOL CVSListBoxWLS::OnBeforeRemoveItem(int nItem)
{
    GetItemTextAfterOp(nItem);

    CString strPrompt;
    strPrompt.Format(TEXT("确定删除【%s】吗?"),m_strAfterOp);
    if (MessageBox(strPrompt,TEXT("提示"),MB_ICONQUESTION|MB_OKCANCEL)==IDOK)
    {
        //by wls op
        m_fdsBeforeRemoveItem((LPVOID)&m_strWhenSelecting,(LPVOID)&m_strAfterOp,m_pObjforOperatingFunc);

        return TRUE;
    }

    return FALSE;
}

CString CVSListBoxWLS::GetTextWhenSelecting()
{
    return m_strWhenSelecting;
}

void CVSListBoxWLS::GetItemTextAfterOp(int nItem)
{
    m_strAfterOp=GetItemText(nItem);
}

void CVSListBoxWLS::OnAfterAddItem(int nItem)
{
    GetItemTextAfterOp(nItem);

    if (m_bDoAfterAddItemWhenever==FALSE && m_bAddItem==TRUE)
    {
        OutputDebugString(TEXT("不重复 成功\n"));
        //by wls op
        m_fdsAfterAddItemNoRepeat((LPVOID)&m_strWhenSelecting,(LPVOID)&m_strAfterOp,m_pObjforOperatingFunc);

        return;
    }
    else if (m_bDoAfterAddItemWhenever==TRUE /*&& m_bAddItem==TRUE*/)
    {
        OutputDebugString(TEXT("重复+不重复 成功\n"));
        //by wls op
        m_fdsAfterAddItemWhenever((LPVOID)&m_strWhenSelecting,(LPVOID)&m_strAfterOp,m_pObjforOperatingFunc);
    }

    if (m_strAfterOp==TEXT(""))
    {
        RemoveItem(nItem);//by wls Remove the item with no text
    }
}

void CVSListBoxWLS::OnAfterRenameItem(int nItem)
{
    GetItemTextAfterOp(nItem);

    if (m_bDoAfterRenameWhenever==FALSE && m_bAddItem==TRUE)
    {
        OutputDebugString(TEXT("重命 不重复 值\n"));
        //by wls op
        m_fdsAfterRenameItemNoRepeat((LPVOID)&m_strWhenSelecting,(LPVOID)&m_strAfterOp,m_pObjforOperatingFunc);

        return;
    }
    else
    if (m_bDoAfterAddItemWhenever==TRUE)
    {
        //by wls op
        m_fdsAfterRenameItemWhenever((LPVOID)&m_strWhenSelecting,(LPVOID)&m_strAfterOp,m_pObjforOperatingFunc);
    }
}

BOOL CVSListBoxWLS::IsExistText(CString strText)
{
    for (int i=0;i<GetCount();i++)
    {
        if (strText==GetItemText(i))
        {
            return TRUE;
        }
    }

    return FALSE;
}

void CVSListBoxWLS::SetObjforOperation(CObject* obj)
{
    m_pObjforOperatingFunc=obj;
}

void CVSListBoxWLS::SetOperationBeforeRemoveItem(FUNCDOSOMETHING fds)
{
    m_fdsBeforeRemoveItem=fds;
}
void CVSListBoxWLS::SetOperationAfterAddItemNoRepeat(FUNCDOSOMETHING fds)
{
    m_fdsAfterAddItemNoRepeat=fds;
}
void CVSListBoxWLS::SetOperationAfterAddItemWhenever(FUNCDOSOMETHING fds)
{
    m_fdsAfterAddItemWhenever=fds;
}
void CVSListBoxWLS::SetOperationAfterRenameItemNoRepeat(FUNCDOSOMETHING fds)
{
    m_fdsAfterRenameItemNoRepeat=fds;
}
void CVSListBoxWLS::SetOperationAfterRenameItemWhenever(FUNCDOSOMETHING fds)
{
    m_fdsAfterRenameItemWhenever=fds;
}

MFC VSListBox遍历文件目录、ShellList Control浏览文件目录相关操作

VSListBox、ShellList控件


/*!
* 获取exe所在目录
*/
CString CFilesSelecterDlg::getExePath()
{
	CString path;
	GetModuleFileName(NULL, path.GetBufferSetLength(MAX_PATH + 1), MAX_PATH);//!<得到exe的完整路径
	path.ReleaseBuffer();
	int pos = path.ReverseFind('\\');
	path = path.Left(pos);//!< exe所在路径
	return path;
	//MessageBox(path);
}

void CFilesSelecterDlg::OnBnClickedButton1()
{
	CString exePath = getExePath();//!< 应用程序目录
	int pos = exePath.ReverseFind('\\');
	teachFilePath = exePath.Left(pos);
	teachFilePath += "\\project";//!< txt文件所在路径
	// MFC ShellList Control
	m_shelllistL.DisplayFolder(teachFilePath);//!< 可选项列表显示
	// MFC VSListBox
	//CString filename = _T("");
	//CString fullname = _T("");
	//CFileFind find;
	//BOOL IsFind = find.FindFile(teachFilePath + _T("/*.txt"));
	//while (IsFind)//遍历txt所在文件夹
	//{
	//	IsFind = find.FindNextFile();
	//	if (find.IsDots())
	//	{
	//		continue;
	//	}
	//	else
	//	{
	//		filename = find.GetFileName();
	//		fullname = teachFilePath + filename;
	//		m_selections.AddItem(filename);//!< 添加到文件列表
	//	}
	//}
}

void CFilesSelecterDlg::OnBnClickedButton2()
{
	int index = m_shelllistL.GetNextItem(-1, LVIS_SELECTED);//获取当前选中项的索引
	CString selPath;
	m_shelllistL.GetItemPath(selPath, index);
	if (0 == m_selected.GetCount())
	{
		m_selected.AddItem(selPath);
		return;
	}
	for (int index = 0; index < m_selected.GetCount(); index++)
	{
		CString temp = m_selected.GetItemText(index);
		if (0 == temp.Compare(selPath))//!< 如果有重复项直接返回
		{
			return;
		}
	}
	m_selected.AddItem(selPath);//!< 到此说明没有重复项,添加
}


CStdioFile读取TXT文件

CString allCodes = "";
		for (int index = 0; index < teachFiles.size(); index++)
		{
			CStdioFile stdFile(teachFiles.at(index), CFile::typeBinary | CFile::modeRead);
			CString temp = "";
			while (true)
			{
				if (stdFile.ReadString(temp))//!< 按行读取,读取完成返回flase
				{
					allCodes += temp;
					allCodes += "\n";
					temp = "";
					continue;
				}
				break;
			}
			stdFile.Close();
		}

### 解决PyCharm无法加载Conda虚拟环境的方法 #### 配置设置 为了使 PyCharm 能够成功识别并使用 Conda 创建的虚拟环境,需确保 Anaconda 的路径已正确添加至系统的环境变量中[^1]。这一步骤至关重要,因为只有当 Python 解释器及其关联工具被加入 PATH 后,IDE 才能顺利找到它们。 对于 Windows 用户而言,在安装 Anaconda 时,默认情况下会询问是否将它添加到系统路径里;如果当时选择了否,则现在应该手动完成此操作。具体做法是在“高级系统设置”的“环境变量”选项内编辑 `Path` 变量,追加 Anaconda 安装目录下的 Scripts 文件夹位置。 另外,建议每次新建项目前都通过命令行先激活目标 conda env: ```bash conda activate myenvname ``` 接着再启动 IDE 进入工作区,这样有助于减少兼容性方面的问题发生概率。 #### 常见错误及修复方法 ##### 错误一:未发现任何解释器 症状表现为打开 PyCharm 新建工程向导页面找不到由 Conda 构建出来的 interpreter 列表项。此时应前往 Preferences/Settings -> Project:...->Python Interpreter 下方点击齿轮图标选择 Add...按钮来指定自定义的位置。按照提示浏览定位到对应版本 python.exe 的绝对地址即可解决问题。 ##### 错误二:权限不足导致 DLL 加载失败 有时即使指定了正确的解释器路径,仍可能遇到由于缺乏适当的操作系统级许可而引发的功能缺失现象。特别是涉及到调用某些特定类型的动态链接库 (Dynamic Link Library, .dll) 时尤为明显。因此拥有管理员身份执行相关动作显得尤为重要——无论是从终端还是图形界面触发创建新 venv 流程均如此处理能够有效规避此类隐患。 ##### 错误三:网络连接异常引起依赖下载超时 部分开发者反馈过因网速慢或者其他因素造成 pip install 操作中途断开进而影响整个项目的初始化进度条卡住的情况。对此可尝试调整镜像源加速获取速度或是离线模式预先准备好所需资源包后再继续后续步骤。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值