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

论坛 期权论坛 脚本     
已经匿名di用户   2022-5-29 19:22   1779   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 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP