使用MFC的CFileDialog类导入导出csv/excel文件

2 篇文章 0 订阅

先看效果,运行之后是这样的:(当然对话框这标题应该改一改...)

说下CFileDialog类:    

CFileDialog fileDlg(
            FALSE,  //文件对话框是否打开
            _T("*.xlsx"),
            _T("csv file"),
            OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 
            szFilters);

参数说明:

bOpenFileDialog          为TRUE则显示打开对话框,为FALSE则显示保存对话文件对话框。(就是打开或者保存文件的那个按钮切换)

lpszDefExt                   指定默认的文件扩展名。

lpszFileName              指定默认的文件名。

dwFlags                       指明一些特定风格。 (默认OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT)

lpszFilter                     指明可供选择的文件类型和相应的扩展名。

pParentWnd                为父窗口指针。

lpszFilter是一个特殊的LPCTSTR类型字符串,以后缀名用来过滤对话框内的文件,

TCHAR szFilters[]= _T("csv file(*.csv)|*.csv|Microsoft Excel 工作表(*.xlsx)|*.xlsx|All Files (*.*)|*.*||");

这个字符串格式如上,文件类型和对应后缀用 | 分开,结尾用||结束。

文件菜单里有导入导出两个功能

1 导出文件:把list按csv格式导出

2 导出文件:把csv格式文件导入到list列表

先修改下文件内容

再导入到软件里,如下图:

主要用到的类,函数

CFileDialog, CStdioFile, CStringArray, CFile,CListCtrl

InsertColumn();

SetItemText();

SetMenu();

LoadMenu();

ModifyMenu();

fopen(),fwrite()

GetFirstSelectedItemPosition();

GetItemCount();

GetItemText();

ReadString();

CString.Find();

CString.Left();

CString.Right();

毕竟代码注释的毕竟清晰了,就不多说了(其实是想下了班早点回家哈~)。

1 首先创建一个MFC应用,选择 单个文档,Mfc标准

项目名为FileSaveOpen

2 去掉无用的.h  .cpp文件

这一步要求精简窗口,方法很多,我的方法是把无关的view,doc,frame等文件全删除,只留下theApp所在的文件。然后在此基础上,编写自己的窗口类(用的是模态对话框+系统菜单的组合方式)

 

1 首先, InitInstance()函数内:

把p_mainFrame  ShowWindow()之类的都删掉,这部分是框架

换成下面的,为了清晰,我把系统自带的代码注释掉

BOOL CFileSaveOpenApp::InitInstance()
{
/*
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
	//则需要 InitCommonControlsEx()。否则,将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();


	// 初始化 OLE 库
	if (!AfxOleInit())
	{
		AfxMessageBox(IDP_OLE_INIT_FAILED);
		return FALSE;
	}

	AfxEnableControlContainer();

	EnableTaskbarInteraction(FALSE);

	// 使用 RichEdit 控件需要  AfxInitRichEdit2()	
	// AfxInitRichEdit2();

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小,则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串,
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
	LoadStdProfileSettings(4);  // 加载标准 INI 文件选项(包括 MRU)
*/
	WNDCLASS wc;
	// 获取窗口类信息。MFC默认的所有对话框的窗口类名为 #32770
	::GetClassInfo(AfxGetInstanceHandle(), _T("#32770"), &wc);
	// 改变窗口类名
	wc.lpszClassName = _T("FileSaveOpen");
	// 注册新窗口类,使程序能使用它
	AfxRegisterClass(&wc);

	//显示Frame框架
	if (!runApp())
	{
		unsigned int nStart = time(NULL);
		while(TRUE) {
			// Show the previous instance and exit
			HWND hwndPrev = ::FindWindow(_T("FileSaveOpen"), NULL);
			if (hwndPrev) {
				if (::IsIconic(hwndPrev))
					::ShowWindow(hwndPrev, SW_RESTORE);
				::SetForegroundWindow(hwndPrev);
				return FALSE;
			}

			if (time(NULL) > nStart + 60)
				return FALSE;		
			if(!runApp())
				break;
		}
	}
	//显示自定义的对话框
	FileDlg dlg; //这是自己定义的对话框窗口类
	m_pMainWnd = &dlg;
	INT_PTR res = dlg.DoModal();

	return TRUE;
}
BOOL CFileSaveOpenApp::runApp()
{
	HANDLE handle = ::CreateMutex(NULL, FALSE, _T("AppMutex"));
	if(GetLastError()==ERROR_ALREADY_EXISTS)	
	{
		OutputDebugString(_T("App已经在运行"));
		return FALSE;	
	}
	return TRUE;
}

2 FileDlg类用类向导创建

点击添加类,修改类名,基类选CDialogEx

//FileDlg.h
#pragma once

#include "resource.h"       // 主符号
// FileDlg 对话框
#include <vector>
using namespace std;

enum _columnTag{
	COL_INDEX = 0,
	COL_NAME,
	COL_AGE,
	COL_ADDRESS,
	COL_SALARY,
	COL_END
};

typedef struct _LISTINFO{
	CString Name;
	CString Age;
	CString Address;
	CString Salary;
	int nFlag;
}LISTINFO;

class FileDlg : public CDialogEx
{
	DECLARE_DYNAMIC(FileDlg)
public:
	FileDlg(CWnd* pParent = NULL);   // 标准构造函数
	virtual ~FileDlg();
// 对话框数据
	enum { IDD = IDD_FILEDLG };

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
	//自定义
	virtual BOOL OnInitDialog();
	BOOL InitList();
	CListCtrl mList;
	vector<TCHAR*> colName; 
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnExportFile();
	afx_msg void OnImportFile();
};
extern FileDlg* g_pMainDlg;
//FileDlg.cpp 
#include "stdafx.h"
#include "afxdialogex.h"
#include "FileDlg.h"
#include "FileSaveOpen.h"
#include <string>
using namespace std;
FileDlg* g_pMainDlg;
LISTINFO ListInfo[5];
// FileDlg 对话框
int SplitString(const CString str, char split, CStringArray &strArray);
IMPLEMENT_DYNAMIC(FileDlg, CDialogEx)

FileDlg::FileDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(FileDlg::IDD, pParent)
{
}

BOOL FileDlg::InitList(){
	//初始化列名
	mList.SetExtendedStyle(LVS_EX_FULLROWSELECT);
	const int colWidth = 70;//列宽
	const int colCount = COL_END;
	int rowCount = 3;//3行
	//LPWSTR colName[colCount] = {L"序号",L"名字",L"年龄",L"住址",L"工资"};
	//for(int i = 0; i < COL_END;i++)
	colName.push_back(_T("序号"));
	colName.push_back(_T("名字"));
	colName.push_back(_T("年龄"));
	colName.push_back(_T("住址"));
	colName.push_back(_T("工资"));

	for(int i = 0; i < colCount; i++)
		mList.InsertColumn(i,colName[i],LVCFMT_CENTER,colWidth);
	


	//初始化列表信息
	CString rowName;//行名
	for(int row = 0; row < rowCount; row++){
		//添加一行
		rowName.Format(_T(" %d"),row+1);
		mList.InsertItem(row,rowName);//行名为序号,又因为从第二行开始计数
		//为添加的行插入数据
		mList.SetItemText(row,COL_NAME,_T("张三丰"));
		mList.SetItemText(row,COL_AGE,_T("99"));
		mList.SetItemText(row,COL_ADDRESS,_T("北京"));
		mList.SetItemText(row,COL_SALARY,_T("99000"));
	}
	/*
	//修改列名
	LVCOLUMN col[colCount];
	char* col_text[ColCount] = {"colname1","colname2",...}
	for(int i = 0;i<colCount;i++){
		col[i].pszText = col_text[i];
		col[i].mask = LVCF_TEXT;
		col[i].cchTextMax = lstrlen(col_text[i]);
		mList.SetColumn(i,&col[i]);
	}*/
	return 1;
}
BOOL FileDlg::OnInitDialog(){
	CDialogEx::OnInitDialog();
	g_pMainDlg = this;

	//CMenu* pSysMenu = GetSystemMenu(FALSE);
    CMenu m;
	m.LoadMenu(IDR_MAINFRAME);
	g_pMainDlg->SetMenu(&m);
	//m.ModifyMenuW(0,MF_BYPOSITION|MF_STRING,0,L"File");
	//m.ModifyMenuW(1,MF_BYCOMMAND|MF_STRING,0,L"编啥");
	//m.ModifyMenuW(2,MF_BYPOSITION|MF_STRING|MF_GRAYED,0,L"帮谁");
	CMenu *File= m.GetSubMenu(0); 
	File->ModifyMenu(0, MF_BYPOSITION|MF_STRING,ID_EXPORT,_T("导出文件"));
	File->ModifyMenu(1, MF_BYPOSITION|MF_STRING,ID_IMPORT,_T("导入文件"));
	//初始化列表
	InitList();
	return TRUE;
}
FileDlg::~FileDlg()
{
}

void FileDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST, mList);
}


BEGIN_MESSAGE_MAP(FileDlg, CDialogEx)
	ON_COMMAND(ID_EXPORT, &FileDlg::OnExportFile)
	ON_COMMAND(ID_IMPORT, &FileDlg::OnImportFile)
END_MESSAGE_MAP()


// FileDlg 消息处理程序


void FileDlg::OnExportFile()
{
	// TODO: 在此添加命令处理程序代码
	TCHAR szFilters[]= _T("csv file(*.csv)|*.csv|All Files (*.*)|*.*||");
	CFileDialog dlgFile(
		FALSE,  
		_T("*.csv"),
		_T("data file"),
		OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 
		szFilters);
	CString fileName = _T("data.csv");
	dlgFile.GetOFN().lpstrFile = fileName.GetBuffer(MAX_PATH);
	if(dlgFile.DoModal() == IDOK){
		fileName = dlgFile.GetOFN().lpstrFile;
/*
		//Unicode下把fileName从宽字节转为char*
		//以下nBytes和len的值大小不同,nBytes是按字符计算的,len是按字节计算的
		int nBytes = fileName.GetLength();
		//获取宽字节字符的大小,大小是按字节计算的
		int len = WideCharToMultiByte(CP_ACP,0,fileName,nBytes,NULL,0,NULL,NULL);
		//为多字节字符数组申请空间,数组大小为按字节计算的宽字节字节大小
		char* pFileName = new char[len+1];
		//宽字节编码转换成多字节编码
		WideCharToMultiByte(CP_ACP,0,fileName,nBytes,pFileName,len,NULL,NULL);
		//多字节字符以'\0'结束
		pFileName[len+1] = '\0';
*/
		try {
			FILE* pFile = fopen(fileName.GetBuffer(0),_T("w"));
			if(!pFile){
				CString str;
				str.Format(_T("file open failed,error code:%d"),WSAGetLastError());
				throw -1;

			}

			//导出列名
			CString allColName;//保存每一列的列名信息
			for(int i = 0;i < COL_END;i++){
				allColName += colName[i];
				allColName += _T(",");
			}
			allColName += _T("\n");
	
			size_t size = fwrite(allColName.GetBuffer(0), 1, allColName.GetLength(), pFile);
			if(size <=0){
				throw -2;
			}

			//导出内容
			POSITION pos;
			pos = g_pMainDlg->mList.GetFirstSelectedItemPosition();
			CString totalInfo = _T("");
			if (pos == NULL){			// 导出所有
				int itemCount = mList.GetItemCount();
				for(int i = 0; i < itemCount; i++) { // 处理行	
					totalInfo = _T("");	
					for(int j = 0;j < COL_END; j++){ // 处理列
						//每一列的数据保存再eachRowInfo
						totalInfo += mList.GetItemText(i,j);				
						if(j != COL_END){
							totalInfo += _T(",");
						}
					}end inner for
					totalInfo += _T("\n");
					size_t size = fwrite(totalInfo.GetBuffer(0),1,totalInfo.GetLength(),pFile);
					if(size <= 0){
						throw -3;
					}
					
				}
			}//end if pos == Null
			fclose(pFile);
		}catch(int e){ //随便写点错误
			CString str;
			if(e == -1){
				str.Format(_T("fopen error:%d\n"),WSAGetLastError());
				printf("%s",str);
			}else if(e == -2){
				str.Format(_T("fwrite error:%d\n"),WSAGetLastError());
				printf("%s",str);
			}else if(e == -3){
				str.Format(_T("fwrite2 error:%d\n"),WSAGetLastError());
				printf("%s",str);
			}
		}
	}
	fileName.ReleaseBuffer();
}


void FileDlg::OnImportFile()
{
	// TODO: 在此添加命令处理程序代码
	CFileDialog fileOpenDlg(TRUE,_T("*.csv"),NULL,OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY,
		_T("csv file(*.csv)|*.csv|All files (*.*)|*.*||",NULL));
	fileOpenDlg.m_ofn.lpstrTitle = _T("Open File");
	if(fileOpenDlg.DoModal() == IDOK){//导入对话框打开
		CString szLine;
		CStdioFile file;
		if(file.Open(fileOpenDlg.GetPathName(),CFile::modeRead)){//打开选中的文件
			int i = 0;
			mList.DeleteAllItems();//清空list列表
            file.ReadString(szLine);//把文件中列名那一行读走
			while(file.ReadString(szLine)){//读取一行文本到szLine,遇到回车换行符停止读取
				if(szLine.GetLength() > 2){//每行读取大于两个字符(一个逗号一个回车,剩下是内容)
					CStringArray strArr;
					SplitString(szLine, ',', strArr);//分割行,每个字符串添加到字符串数组
					mList.InsertItem(i,strArr.GetAt(0));//插入行,以及行名(即读到的每行的第一个字符串)
					for(int j = 1; j < strArr.GetCount(); j++){
						mList.SetItemText(i,j,strArr.GetAt(j));//每行的具体信息
					}
					i++;
				}
			}
			file.Close();

		}

	}
}
int SplitString(const CString str, char split, CStringArray &strArray)
{
	strArray.RemoveAll();
	CString strTemp = str;
	int iIndex = 0;
	while (1)
	{
		iIndex = strTemp.Find(split);//分隔符位置确定,下标从0开始计算
		if(iIndex >= 0)
		{
			strArray.Add(strTemp.Left(iIndex));//把分隔符左边iIndex个字符保存到strArray
			strTemp = strTemp.Right(strTemp.GetLength()-iIndex-1);//把分隔符右边iIndex-1个字符保存到strTemp
		}
		else
		{
			break;
		}
	}
	strArray.Add(strTemp);

	return strArray.GetSize();
}

 

  • 0
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC CFileDialog是一个内置的对话框,它提供了文件选择的功能。重载指的是在该重新定义或修改已有的方法或函数。 我们可以通过重载CFileDialog的一些方法来实现我们自己的定制需求。重载的概念是在派生重新定义基已有的方法,以便根据具体需求进行定制。这样就能够在文件选择对话框添加自己的一些功能或修改已有的功能。 例如,在CFileDialog重载OnInitDialog方法,可以在对话框初始化时执行自定义的一些任务,比如设置一些默认的选项、修改文件过滤器等。可以在重载的OnInitDialog方法调用基的OnInitDialog方法,以保持基的原有功能。 另外,还可以重载OnFileNameOK方法,这个方法在用户选择了文件并点击了对话框的“确定”按钮时触发。我们可以在重载的方法进行一些自定义的处理,比如文件检查、文件路径的存储等操作。 重载CFileDialog还可以通过定义自己的消息映射函数来处理一些特定的消息,比如在重载的消息映射函数处理文件选择对话框的特定消息,以实现对话框的特定行为。 总之,通过重载MFC的CFileDialog,我们可以根据自己的需求进行一些自定义的操作,添加新的功能或修改已有的功能。这样可以在保留基的原有功能的基础上,实现更灵活、更符合实际需求的文件选择对话框功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值