先看效果,运行之后是这样的:(当然对话框这标题应该改一改...)
说下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();
}
|