MFC—MFC的一些常用类

MFC的一些常用类

  • MFC 为应用程序开发封装了一些常用的类,如字符串类、集合类、时间日期类、MFC文件操作类和MFC已成类等

一、字符串类(CString)

  • CString 类用于储存和管理字符数组的类。CString 类在内存中完成字符串的连接和比较等操作。由于它对字符串操作时自动处理储存空间的大小,不需要开发人员手动处理内存的分配等问题,大大简化了开发人员维护字符串的工作量。

1、创建 CString 对象

  • CString 类提供了以下几种构造函数来构造 CString 对象。

    CString()  //默认构造函数
    CString(const CString& stringSrc);  //使用 CString 参数的构造函数
    CString(TCHAR ch,nRepeat=1); //使用重复字符的构造函数
    CString(LPCTSTR lpch,int nLength);  //带指定长度字符串的构造函数
    CString(const unsigned char* psz);  //带以NULL结束的字符串的构造函数
    CString(LPCWSTR lpsz);  //带以 NULL 结束的多字符集字符串的构造函数
    CString(LPCSTR lpsz);  //带以 NULL 结束的单字符集字符串的构造函数
    

2、CString 类成员函数

  • CString 类提供了进行赋值、连接、比较、转换、数据存取、序列化和格式化等字符串操作的成员函数,见下表:
函数名 说明
=操作符 为CString对象赋值
+操作符 连接两个字符串,并返回连接后的新字符串
+=操作符 连接两个字符串,并将连接后的新字符串赋值给操作符左边的变量
==、<、>等比较运算符 比较字符串的大小,区分大小写
Compare() 比较两个字符串,区分大小写
CompareNoCase() 比较两个字符串,不分大小写
Collate() 使用本地化比较两个字符串,区分大小写
CollateNoCase() 使用本地化比较两个字符串,不分大小写
Find() 从字符串头开始查找字符或子字符串
ReverseFind() 从字符串尾开始查找字符或子字符串
FindOneOf() 从字符串头开始查找第一个匹配的字符或子字符串
MakeUpper() 将字符串中的所有字符转换成大写
MakeLower() 将字符串中的所有字符转换成小写
MakeReverse() 反转字符串中的字符
Replace() 替换字符串中指定字符
Remove() 移除字符串中指定字符
Insert() 在字符串中的指定位置插入一个字符或另一个子字符串
Delete() 从字符串中删除一个字符或子字符串
Format() 使用 sprintf方式格式化字符串
FormatV() 使用vsprintf方式格式化字符串
TrimLeft() 取消字符串前面的空格
TrimRight() 取消字符串后面的空格
FormatMessage() 格式化消息字符串
Mid() 截取字符串中间的数据
Left() 截取字符串左边的数据
Right() 截取字符串右边的数据
SpanIncluding() 截取字符串中包含指定字符的部分
SpanExcluding() 截取字符串中不包含指定字符的部分
operator<< 插入字符串对象
operator>> 提取字符串对象
GetLength() 返回 CString对象的字符串数。对于多字符集,也是按照8位字符计数,也就是每个多字节字符算作两个字符
IsEmpty() 判断CString对象是否不包含任何字符
Empty() 其空字符串内容
GetAt() 返回指定位置的字符
[] 返回指定位置的字符
SetAt() 设置指定位置的字符
LPCTSTR操作符 直接反问储存在CString对象中的字符串
GetBuffer() 返回字符串对象的字符指针
GetBufferSetLength() 返回字符串中指定长度的字符串的指针
ReleaseBuffer() 释放有GetBuffer函数获取的对缓冲区的控制
FreeExtra() 移除字符串对象以前分配给字符串前面的字符
LockBuffer() 锁定字符缓冲区,并关闭引用计数
UnlockBuffer() 释放字符缓冲区,并开启引用计数
AllocSysString() 从字符串对象复制数据到新建的BSTR对象的变量中
SetSysString() 复制字符串对象的数据到一个存在的BSTR对象中
LoadString() 从Windows资源中装载一个存在的字符串对象
AnsiToOem() 将字符串对象中的字符从ANSI字符集转换成OEM字符集
OemToAnsi() 将字符串对象中的字符从OEM字符集转换成ANSI字符集

3、CString 常用操作

  • CString 类通过提取操作符和插入操作符实现对序列化的支持,这两个函数的原型:

    //提取操作符
    friend CArchive& operator <<(CArchive& ar,const CString& string);
    //插入操作符
    friend CArchive& operator >>(CArchive& ar,CString& string);
    //提取操作符
    friend CDumpContext& operator <<(CDumpContext& dc,const CString& string);
    
  • 提取操作符 << 将 CString 对象序列化到文件等对象中,插入操作符 >> 从文档对象中反序列化 CString 对象。

  • CString 类提供 GetLength() 函数获取字符串长度;CString 类以 TCHAR 为基本数据类型储存字符——Unicode 字符编码下用16位字符储存字符串,否则 CString 存储的是8位的字符;CString 类支持双字节字符集(double-byte character sets, DBCS),以8位字符为基准,每个字节算一个字符,其函数原型:

    int GetLength() const;
    
//清空字符串
void Empty();
//判断字符串是否为空,如果对象长度为零,返回True,否则返回False
BOOL IsEmpty() const;

//字符串比较函数
int Collate(LPCTSTR lpsz) const; 
int collateNoCase(LPCTSTR lpsz) const; //不区分大小写的比较字符串函数
int Compare(LPCTSTR lpsz) const;  //使用单字符集比较函数
int Compare(LPCSTR lpsz) const;  //使用单字符集不区分大小写的比较字符串
//其中,参数lpsz为要比较的字符串。Collate 和 Compare 的区别在于,前者基于字符集设置进行比较,支持多字符集比较,后者基于单字符集进行比较

//增加字符和删除字符
int Delete(  //返回值为成功删除的字符的个数
	int nIndex,//开始删除字符的第一个字符的索引
	int nCount = 1); //要删除的字符个数
int Insert( //在指定位置插入字符,返回值为增加字符后的字符串长度
	int nIndex, //要在其增加的字符的索引
	TCHAR ch);//要增加的字符
int Insert( //在指定位置插入字符,返回值为增加字符后的字符串长度
	int nIndex, //要在其增加的字符的索引
	LPCTSTR pstr); //要增加的字符串的指针

//字符查找
int Find(TCHAR ch) const; //查找指定字符ch,返回索引位置
//查找指定字符串并返回开始匹配的索引位置
int Find(LPCTSTR lpszSub) const;
//从指定位置开始查找指定字符
int Find(TCHAR ch,int nStart) const;
//从指定位置开始查找指定字符串
int Find(LPCTSTR pstr,int nStart) const;
//反向查找指定字符
int ReverseFind(TCHAR ch) const;
//返回字符串中是否包含lpszCharSet中的任一个字符以及这个字符的位置
int FindOfOne(
	LPCTSTR lpszCharSet,  //要查找的字符的字符集,其中的字符没有顺序
	) const;

//字符串截取
//截取指定索引处的字符,返回值为TCHAR
TCHAR GetAt(int nIndex) const;
//截取字符串中nIndex索引处的字符,大于0小于GetLength()返回值
TCHAR operator [](int nIndex) const;
//将字符串作为数组操作,但此操作是只读操作

//操作缓冲区数据的函数
void FreeExtra();  //释放字符串占用的内存
LPRTSTR GetBuffer(  //获取字符串缓冲区,返回字符串对象的内部字符缓冲区指针
		int nMinBufferLength); //表示字符缓冲区中最小的字符数
//设置字符串长度,返回字符串对象的内部字符缓冲区指针
LPTSTR GetBufferSetLength(
		int nNewLength); //表示设置的缓冲区字符的精确长度,-1表示当前字符串长度
//释放字符串缓冲区
void ReleaseBuffer(int nNewLength = -1);
//锁定字符串,保护数据不被其他字符串引用,也不能引用其他字符串
LPTSTR LockBuffer();
void UnlockBuffer();  //解锁字符串

//字符串数据截取函数
CString Left(int nCount) const; //截取字符串左边nCount个字符
CString Right(int nCount) const; //截取字符串右边nCount个字符
Cstring Mid(int nFirst) const; //获取从nFirst位置开始的字符串
CString Mid(int nFirst,int nCount) const; //获取从nFirst位置开始的nCount字符
//返回排除lpszCharSet字符集的字符串
CString SpanExcluding(LPCTSTR lpszCharSet) const;
//返回包含lpszCharSet字符集的字符串
CString SpanIncluding(LPCTSTR lpszCharSet) const;

4、CString 格式转换和类型转换

void Format(LPCTSTR lpszFormat,...); //按照格式化字符串格式化
void Format(UINT nFormatID,...);//按照格式化ID格式化字符串
void FormatV(LPCTSTR lpszFormat,va_list arglist);//使用参数格式化字符串
void FormatMessage(LPCTSTR lpszFormat,...);//格式化消息字符串
void FormatMessage(UINT nFormatID,...);//按照格式化ID格式化消息字符串
//lpszFormat 参数是一个格式化空制字符串,nFormatID 参数是一个包含格式化控制字符串资源的标识,arglist 参数是一个传入的参数列表。
//不能在次函数中使用字符串对象本身作为可选参数写入字符串对象,这样会造成循环递归,发生不可知的错误

//格式化字符串头和字符串尾的函数
void TrimLeft(); //去除左边的空格,包括换行、空格和制表符
void TrimLeft(TCHAR chTarget); //去除字符串左边的chTarget字符
void TrimLeft(LPCTSTR lpszTargets); //去除字符串左边的lpszTarget字符串
void TrimRight(); //去除右边的空格,包括换行、空格和制表符
void TrimRight(TCHAR chTarget); //去除字符串右边的chTarget字符
void TrimRight(LPCTSTR lpszTargets); //去除字符串右边的lpszTarget字符串

void MakeLower(); //将字符串中的字符全部换成小写字母
void MakeUpper(); //将字符串中的字符全部换成大写字母

void MakeReverse(); //反转字符串中的字符
int ReMove(TCHAR ch); //移除字符串中的所有ch字符,并返回移除的字符数目
//替换chOld(lpszOld)字符(串)为chNew(lpszNew)字符(串)
int Replace(TCHAR chOld,TCHAR chNew);
int Replace(LPCTSTR lpszOld,LPCTSTR lpszNew);
void SetAt(int nIndex,TCHAR ch); //设置nIndex索引处的字符为ch字符

//赋值操作
const CString& operator = (const CString& stringSrc); //使用CString参数的赋值符
const CString& operator = (TCHAR ch); //使用自负参数的赋值符
const CString& operator = (const unsigned char* psz); //使用字符串参数的赋值符
const CString& operator = (LPCWSTR lpsz); //使用多字符集字符串参数的赋值符
const CString& operator = (LPCSTR lpsz); //使用单字符集字符串参数的赋值符
const CString& operator +=(const CString& string); //使用CString参数的加法操作符
const CString& operator +=(TCHAR ch); //使用字符参数的加法赋值操作符
const CString& operator +=(LPCTSTR lpsz);//使用字符串参数的加法赋值操作符

//类型转换
BOOL LoadString(UINT nID); //装载字符串,nID参数为 Windows 字符串资源的 ID
//从 OEM 类型转换成ANSI类型,如果定义了 _UNICODE宏,则此函数无效
void OemToAnsi();
//将字符串pbstr复制到BSTR类型中,并返回
BSTR SetSysString(BSTR* pbstr) const;
operator LPCTSTR() const; //将CString对象转换成LPCTSTR对象

5、CString 使用示例

#include "pch.h"
#include 
#include
using namespace std;

int main()
{
    //定义字符串
	CString s(_T("abcdef"));
	printf("%ls\n", LPCTSTR(s));
	wcout << "初始化字符串=" <

二、集合类

  • 集合是储存多个数据结构相同的对象的容器。MFC 提供了顺序结构的数组类和指针结构的链表类实现集合的功能;并且在这两种结构的基础上,扩展了常用的数据类型的数组和数组模板,以及常用数据类型的链表和链表模板类。

1、数组类

  • MFC 中封装了 CArray 类实现数组的功能,并且实现动态缩减和增加数组长度的功能,索引也是从 0 开始,其类声明如下:

    template
    class CArray:public CObject
    //其中,模板参数 TYPE 指定存储在数组中的对象类型,也是 CArray 类中返回的参数的类型 。
    //模板参数 ARG_TYPE 指定用于访问储存在数组中的对象的参数类型,通常是 TYPE 的引用,也是传入 CArray的参数
    
  • CArray 类的数组操作成员函数

函数名 功能
GetSize() 获取数组中的元素个数
GetUpperBound() 返回数组最大的有效索引
SetSize() 设置数组中包含的元素数目
FreeExtra() 释放当前数组范围下,不使用的内存
RemoveAll() 从数组中移除所有的元素
GetAt() 返回指定索引处的元素值
SetAt() 设置指定索引处的值,不能使用此函数增加元素,只能修改已经存在的元素值
ElementAt() 返回数组中指定索引处的元素的引用
GetData() 允许访问数组中的元素,可以为NULL
SetAtGrow() 设置指定索引处的值,如果需要,此函数可以自动增加数组大小
Add() 向数组尾添加元素,如果需要,会自动增加数组大小
Append() 添加其他数组中的元素到数组中,如果需要,会自动增加数组大小
Copy() 复制其他数组中的元素到数组中,如果需要,会自动增加数组大小
InsertAt() 在指定索引处插入元素或者其他数组中的所有元素
RemoveAt() 移除指定索引处的元素
operator 设置或获取指定索引处的元素
  • 在使用数组前,最好用 SetSize() 确定数组大小,系统会为其分配空间。如果不使用这个函数,增加元素时,有时候会重新分配空间,并频繁地进行复制,这样会降低程序效率,并产生很多内存碎片。
  • MFC 中从 CArray 类派生的数组类有以下几个:
  • CByteArray:存储 BYTE 类型的元素的数组;
  • CDWordArray:存储 DWORD 类型元素的数组;
  • CObArray:存储 CObject 类对象或派生自 CObject 类的对象的数组;
  • CPtrArray:存储指向 void 的指针元素的数组;
  • CUIntArray:存储UINT类型元素的数组;
  • CWordArray:存储WORD类型元素的数组;
  • CStringArray:存储CString类型元素的数组。

2、数组类使用示例

// MFC代码测试.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include 
#include
#include
using namespace std;

CArraym_ptArray; //定义数组对象
void PrintArray()
{
	for (int i = 0; i < m_ptArray.GetSize(); i++)
	{
		cout << "第" << i + 1 << "个元素=(" << m_ptArray[i].x << "," << m_ptArray.GetAt(i).y << ")" << endl;
	}
}
int _tmain()
{
	CPoint ptA(0, 0), ptB(20, 50), ptC(120, 30); //构造CPoint对象
	m_ptArray.Add(ptA);//增加元素
	m_ptArray.Add(ptB);
	m_ptArray.Add(ptC);
	cout << "初始CArray对象中共有" << m_ptArray.GetSize() << "个元素:" << endl;
	PrintArray();

	CPoint ptD(800, 600);
	m_ptArray[1] = ptD;
	cout << endl << "修改第二个元素后CArray对象中共有" << m_ptArray.GetSize() << "个元素:" << endl;
	PrintArray();

	m_ptArray.RemoveAt(0);
	cout << endl << "删除第一个元素后CArray对象中共有" << m_ptArray.GetSize() << "个元素:" << endl;
	PrintArray();

	m_ptArray.RemoveAll();
	cout << endl << "删除所有元素后CArray对象中共有" << m_ptArray.GetSize() << "个元素:" << endl;
	PrintArray();

	return 0;
}

//输出结果
初始CArray对象中共有3个元素:
第1个元素=(0,0)
第2个元素=(20,50)
第3个元素=(120,30)

修改第二个元素后CArray对象中共有3个元素:
第1个元素=(0,0)
第2个元素=(800,600)
第3个元素=(120,30)

删除第一个元素后CArray对象中共有2个元素:
第1个元素=(800,600)
第2个元素=(120,30)

删除所有元素后CArray对象中共有0个元素:

D:\users\lenovo\source\code\day02\MFC代码测试\Debug\MFC代码测试.exe (进程 13840)已退出,返回代码为: 0。

三、链表类

1、CList 类

  • CList 类实现对象的链式存储方式,使用 POSITION 类型的变量表示元素的位置,链表类声明如下:

    template
    class CList:public CObject
    //模板参数的意义与数组类的一致
    //链表类对于频繁插入删除元素的情况非常适用。
    
  • 链表类CList成员函数

    函数名 函数功能
    GetHead() 获取链表的头元素,即第一个元素
    GetTail() 获取链表的尾元素,即最后一个元素
    RemoveHead() 移除链表的头元素
    RemoveTail() 移除链表的尾元素
    AddHead() 在链表头处增加新元素或将其它链表中的元素增加到链表头
    AddTail() 在链表尾处增加新元素或将其它链表中的元素增加到链表尾
    RemoveAll() 移除链表中所有的元素
    GetHeadPosition() 返回链表头的位置值
    GetTailPosition() 返回链表尾的位置值
    GetNext() 相对于当前元素,获取链表中的下一个元素
    GetPrev() 相对于当前元素,获取链表中的前一个元素
    GetAt() 获取指定位置的元素值
    SetAt() 修改指定位置的元素值
    RemoveAt() 移除指定位置值的元素值
    InsertAfter() 在指定位置值后插入一个新元素
    InsertBefore() 在指定位置值前插入一个新元素
    Find() 查找指定元素的位置
    FindIndex() 返回基于0索引的元素的位置值
    GetCount() 获取链表中元素的数目
    IsEmpty() 判断链表是否为空
  • MFC中从CList派生的链表类有以下3个:

  • CObList:存放CObject对象的链表

  • CPTRList:存放指针对象的链表

  • CStringList:存放CString对象的链表

2、示例

// MFC代码测试.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include 
#include
#include
#include
using namespace std;

//CStringList m_stringList;
CListm_stringList;
void PrintList()
{
	cout << "当前字符串链表中共有" << m_stringList.GetCount()
		<< "个元素:" << endl;
	if (m_stringList.IsEmpty())
		return;
	POSITION pos = m_stringList.GetHeadPosition();
	int i = 0;
	while (pos != NULL)
	{
		cout << "第" << i + 1 << "个元素='";
		std::wcout.imbue(std::locale("chs"));
		wcout << LPCTSTR(m_stringList.GetAt(pos));
		//printf("%ls", LPCTSTR(m_stringList.GetAt(pos)));
		cout<< "'" << endl;
		m_stringList.GetNext(pos);
		i++;
	}
	cout << endl;
}
int _tmain()
{
	CListm_intList;
	m_intList.AddHead(2008);
	m_intList.AddHead(2019);
	cout << "整个链表中共有" << m_intList.GetCount() << "个元素" << endl;
	POSITION posINT = m_intList.GetHeadPosition();
	int i = 0;
	while (posINT != NULL)
	{
		cout << "第" << i + 1 << "个整数元素="
			<< m_intList.GetAt(posINT) << endl;
		m_intList.GetNext(posINT);
		//i++;
	}

	for (i = 0; i < 3; i++)
	{
		CString element;
		element.Format(_T("这是第%d个元素"), (i + 1));
		m_stringList.AddTail(element);//向链表尾添加元素
	}
	//m_stringList.AddTail(_T("这是第1个元素"));//向链表尾添加元素
	//m_stringList.AddTail(_T("这是第2个元素"));//向链表尾添加元素
	//m_stringList.AddTail(_T("这是第3个元素"));//向链表尾添加元素
	PrintList();

	POSITION pos = m_stringList.FindIndex(1);
	if (pos != NULL)
	{
		cout << "执行操作-----使用InsertBefore函数在当前链表的";
		cout << "第二个元素插入新元素" << endl;
		m_stringList.InsertBefore(pos, _T("在第二个元素前插入的新元素"));
		PrintList();

		pos = m_stringList.FindIndex(1);
		cout << "执行操作-------使用SetAt函数修改第二个元素值" << endl;
		m_stringList.SetAt(pos, _T("修改了第二个元素"));
		PrintList();
        
        cout << "执行操作-----使用RemoveTail函数移除最后一个元素" << endl;
		m_stringList.RemoveTail();
		PrintList();

		cout << "执行操作-------使用Removeall函数移除所有元素" << endl;
		m_stringList.RemoveAll();
		PrintList();
		return 0;
	}
}

//效果
整个链表中共有2个元素
第1个整数元素=2019
第1个整数元素=2008
当前字符串链表中共有3个元素:
第1个元素='这是第1个元素'
第2个元素='这是第2个元素'
第3个元素='这是第3个元素'

执行操作-----使用InsertBefore函数在当前链表的第二个元素插入新元素
当前字符串链表中共有4个元素:
第1个元素='这是第1个元素'
第2个元素='在第二个元素前插入的新元素'
第3个元素='这是第2个元素'
第4个元素='这是第3个元素'

执行操作-------使用SetAt函数修改第二个元素值
当前字符串链表中共有4个元素:
第1个元素='这是第1个元素'
第2个元素='修改了第二个元素'
第3个元素='这是第2个元素'
第4个元素='这是第3个元素'

执行操作-----使用RemoveTail函数移除最后一个元素
当前字符串链表中共有3个元素:
第1个元素='这是第1个元素'
第2个元素='修改了第二个元素'
第3个元素='这是第2个元素'

执行操作-------使用Removeall函数移除所有元素
当前字符串链表中共有0个元素:

三、日期、时间类

  • MFC 中提供了强大的的日期时间类——CTime,使用它可以完成常见的有关时间日期的操作。

1、CTime 类

  • CTime 没有基类,表示一个绝对的时间和日期,是一个 time_t 的数据类型,与运行时库函数相连,包括与格林威治(GMT)日期和24小时制时间之间的转换。CTime 的值基于 UTC 时区的,格林威治(GMT)是零时区,中国大部分是跨越6时区和8时区。计算机本地的时区在 TZ 的环境变量中设置。
  • CTime 的对象大小为4个字节,不能派生而且大部分函数是内联函数。
  • CTime 类主要成员函数
函数名 功能
GetCurrentTime() 创建一个取值为当前时间的 CTime对象。此函数为静态函数
GetTime() 返回 CTime 对象对应的 time_t 类型的取值
GetYear() 返回 CTime 对象当前时间年的取值
GetMonth() 返回 CTime 对象当前时间月的取值,范围1~12
GetDay() 返回 CTime 对象当前时间天的取值,范围1~31
GetHour() 返回 CTime 对象当前时间小时的取值,范围0~23
GetMinute() 返回 CTime 对象当前时间分钟的取值,范围0~59
GetSecond() 返回 CTime 对象当前时间秒的取值,范围0~59
GetDayOfWeek() 返回 CTime 对象当前时间是星期几,其中1代表星期日,2代表星期一,以此类推
GetGmtTime() 将 CTime 对象的时间按照 UTC 解释,并将其赋值给 tm 结构
GetLocalTime() 将 CTime 对象的时间按照 本地时区解释,并将其赋值给 tm 结构
GetAsSystemTime() 将 CTime 对象转换成 Win32 兼容的SYSTEMTIME结构
Format() 将 CTime 对象转换成基于本地时区的格式化字符串
FormatGmt() 将 CTime 对象转换成基于格林威治时间的格式化字符串
<< 对象序列化操作,将对象输出到 CArchive 对象或 CdumpContext 对象中
>> 对象反序列化操作,从 CArchive 对象导入到 CTime 对象
= 为 CTime 对象赋值
+、- CTime 对象与 CTimeSpan 对象或 CTime 对象之间进行相加相减 的操作
+=、-= 赋值加减运算,操作与+、-运算相同,区别在于这两个操作数会将运算结果赋值给目标对象,即操作符左边的对象。
==、<、etc 比较 CTime 对象的绝对时间

2、格式化 CTime 对象

  • 格式化 CTime 对象有两种方法:一种是通过构造函数,一种是通过 Fromat() 成员函数。

  • 构造函数方法通常用于与多种时间结构之间进行转换:

    CTime();//默认构造函数
    CTime(const CTime& timeSrc); //带 CTime 参数的构造函数
    CTime(time_t time); //带 time_t 参数的构造函数
    //带年、月、日、时、分、秒参数的构造函数
    CTime(int nYear,int nMonth,int nDay,int nHour,int nMin,int nSec,int nDST=-1);
    CTime(WORD wDosDate,WORD wDosTime,int nDST=-1);//带日期值、时间值和差值的构造函数
    CTime(const SYSTEMTIME& sysTime,int nDST=-1); //带 SYSTEMTIME 参数的构造函数
    CTime(const FILETIME& fileTime,int nDTS=-1);//带 FILETIME 参数的构造函数
    
    //参数 wDosDate 和 wDosTime 表示 MS-DOC 的日期和时间值转换成 CTime 对象。
    //sysTime表示使用 STSTEMTIME 结构初始化 CTime 对象
    //fileTime表示使用 FILETIME 结构初始化 CTime 对象
    //nDST 参数表示是否使用夏令时,0表示标准时间,大于0表示使用夏令时,小于0表示根据计算机上的设置决定是否使用夏令时
    //使用案例如下:
     time_t osTime;
    time(& osTime);
    CTime time1;
    CTime time2 = time1;
    CTime time3(osTime);
    CTime time4(2019,4,19,18,3,45);
    
  • 使用 Format() 函数格式化 CTime 对象。

    CString Format(LPCTSTR pFormat) const; //使用指定格式格式化字符串
    CString Format(UINT nFormatID) const; //使用格式化ID格式化字符串
    //参数 pFormat 有效的格式化代码如下
    //%D:CTime 时间的当前天数
    //%H:当天小时数
    //%M:当前小时的分钟数
    //%S:当前分钟的秒数
    //%%:百分号
    //案例:
    
    CTime t(2009,1,19,22,15,59);
    CString s = t.Format(L"%A,%B,%d,%Y");
    //判断格式化后的时间字符串与指定值是否相同
    ASSERT(s=="Friday,January 19,2009");
    

3、CTimeSpan 类

  • CTimeSpan 类,表示一个时间间隔,即两个不同的 CTime 对象之间的间隔,结合 ANSI 的 time_t 数据类型,并且与运行时函数相关。

  • CTimeSpan 对象以秒保存时间,由于它存储为4个字节的有符号数,因此最大的时间间隔值为-68~68年。

  • CTimeSpan 常用成员函数:

    函数名 功能
    GetDays() 返回 CTimeSpan 对象中的整天的数目
    GetHours() 返回 CTimeSpan 对象中的当天的小时数
    GetTotalHours() 返回 CTimeSpan 对象中的整小时数
    GetMinutes() 返回 CTimeSpan 对象中的当前小时的分钟数
    GetTotalMinutes() 返回 CTimeSpan 对象中的整分钟数
    GetSeconds() 返回 CTimeSpan 对象中的当前分钟的秒数
    GetTotalSeconds() 返回 CTimeSpan 对象中的整秒数
    CTimeSpan ts(7,5,5,1);
    ASSERT(ts.GetDays()==7); //判断CTimeSpan对象的天数是否为7
    

4、制作计时器

// CTimerSampleDlg 对话框

class CTimerSampleDlg : public CDialogEx
{
	DECLARE_DYNAMIC(CTimerSampleDlg)

public:
	CTimerSampleDlg(CWnd* pParent = nullptr);   // 标准构造函数
	virtual ~CTimerSampleDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_DIALOG2 };
#endif

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
	virtual BOOL OnInitDialog();
	DECLARE_MESSAGE_MAP()
public:
	CStatic m_staticTime;
	CTime m_BeginTime;
	

	afx_msg void OnButtonStart();
	afx_msg void OnButtonStop();
	afx_msg void OnTimer(UINT nIDEvent);
};


// CTimerSampleDlg.cpp: 实现文件
//

#include "stdafx.h"
#include "MFCApplication1.h"
#include "CTimerSampleDlg.h"
#include "afxdialogex.h"


// CTimerSampleDlg 对话框

IMPLEMENT_DYNAMIC(CTimerSampleDlg, CDialogEx)

CTimerSampleDlg::CTimerSampleDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_DIALOG2, pParent)
{
#ifndef _WIN32_WCE
	EnableActiveAccessibility();
#endif

}

CTimerSampleDlg::~CTimerSampleDlg()
{
}

void CTimerSampleDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_STATIC_TIMELOG, m_staticTime);
}


BEGIN_MESSAGE_MAP(CTimerSampleDlg, CDialogEx)
	ON_BN_CLICKED(IDC_BUTTON_START,OnButtonStart)
	ON_BN_CLICKED(IDC_BUTTON_STOP,OnButtonStop)
	ON_WM_TIMER(IDC_BUTTON_STOP, OnTimer)
END_MESSAGE_MAP()


// CTimerSampleDlg 消息处理程序
BOOL CTimerSampleDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	return TRUE;
}
void CTimerSampleDlg::OnButtonStart()
{
	SetTimer(100, 1000, NULL);
	m_BeginTime = CTime::GetCurrentTime();
}
void CTimerSampleDlg::OnButtonStop()
{
	KillTimer(100);
}
void CTimerSampleDlg::OnTimer(UINT nIDEvent)
{
	CTime m_EndTime = CTime::GetCurrentTime();
	CTimeSpan m_span = m_EndTime - m_BeginTime;
	CString log;
	log.Format(L"%d", m_span.GetSeconds());
	m_staticTime.SetWindowText(log);
	UpdateData(FALSE);
	CDialog::OnTimer(nIDEvent);
}

//主窗口添加菜单命令
afx_msg void OnTestTime();
	DECLARE_MESSAGE_MAP()
        
ON_COMMAND(ID_T,OnTestTime)
        
void CMFCApplication1App::OnTestTime()
{
	CTimerSampleDlg timeDlg;
	timeDlg.DoModal();
}

四、MFC 文件操作类——CFile

  • MFC 中使用 CFile 类封了有关文件的操作,是 MFC 的基类,直接提供了非缓冲的、二进制磁盘输入/输出服务。通过派生类间接支持文本文件和内存文件,并且与 CArchive 类结合使用可以提供序列化的支持。
  • 文件的操作包括创建、打开、读文件、写文件和文件定位等操作。

1、构造文件对象并打开文件

  • CFile 类的构造函数如下:

    CFile(); //默认构造函数
    CFile(int hFile);  //带文件句柄参数的构造函数
    CFile(
    	//要打开的文件的路径,此路径可以是绝对路径,也可以是相对路径
    	LPCTSTR lpszFilename,
    	UINT nOpenFlags); //打开文件时的共享和访问方式
    
  • CFile 类打开文件的操作函数

    virtual BOOL Open(
    	//要打开的文件的路径,此路径可以是绝对路径,也可以是相对路径
    	LPCTSTR lpszFilename,
    	UINT nOpenFlags,//打开文件时的共享和访问方式
    	CFileException* pError = NULL //打开文件的异常捕获常量
    	);
    
  • nOpenFlags 参数指定共享和访问的方式,可以是下列选项的任意组合,使用位或(|)组合

    CFile::modeCreate:新建文件,如果文件已经存在,则截取文件的长度为0;
    CFile::modeNoTruncate:与 modeCreate 组合使用,如果创建的文件已经存在,则不会截取长度为0长度。因此,其含义。因此,其含义是打开已经存在的文件或新建文件。
    CFile::modeRead:以只读方式打开文件
    CFile::modeReadWrite:以可读写的方式打开文件
    CFile::modeNoInherit:阻止文件从子进程中继承
    CFile::shareDenyNone:共享读写的打开文件。
    CFile::shareDenyRead:排它读权限打开文件
    CFile::shareDenyWrite:排它写权限打开文件
    CFile::shareExclusive:排它模式打开文件
    CFile::typeText:文本模式打开文件
    CFile::typeBinary:二进制模式打开文件。
    
  • 创建文件并以写模式打开文件

    CString filename = L"comm.log";
    void main()
    {
    	TRY
    	{
    		//以创建方式和可写方式打开文件
    		CFile f(filename,CFile::modeCreate | CFile::modeWrite);
    	}
    	CATCH(CFileException, e)
    	{
    #ifdef DEBUG
    		//显示打开文件错误的原因
    		afxDump << "打开文件失败" << e->m_cause << "\n";
    #endif // DEBUG
    
    	}
    	END_CATCH
    }
    

2、读写文件

  • CFile 类提供了以下两个函数实现读文件的功能:

    virtual UINT Read( //从文件中获取指定长度的数据到缓冲区中
    		void* lBuf,  //存放读取的数据缓冲区指针
    		UINT nCount); //要读的字节数
    DWORD ReadHuge(  //获取指定长度的大量数据
    		void* lpBuffer,//存放读取的数据的缓冲区指针
    		DWORD dwCount); //要读取的字节数
    //区别:Read() 函数最多可以读取64k-1个字节,超过64k的数据,则需要使用ReadHuge()函数读取。
    //共同点:这两个函数的返回值都是读取的字节数。
    //例:
    
    char pbuf[50];
    UINT nBytesread = cfile.Read(pbuf,50); 
    
  • 类似的,CFile 提供两种写文件的函数。

    virtual void Write( //向文件中写入指定长度的数据
    		const void* lpBuf,//存放写入文件的数据的缓冲区指针
    		UINT nCount);//要写入的字节数
    void WriteHuge(  //向文件写入指定长度的大量数据
    		const void* lpBuf,  //存放写入文件的数据缓冲区指针
    		DWORD dwCount);  //要写入的字节数
    //Write() 函数最多可以一次性写入小于64k-1的数据,超过64k的数据,需要使用 WriteHuge() 函数来操作。
    //例
    
    char pBuf[100];
    cfile.Write(pBuf,100);
    
    //CFile 还提供了一个 Flush() 函数,用于强制将文件缓冲区的内容刷新到文件中。
    virtual void Flush(); //刷新文件缓冲区中的数据
    
  

### 3、定位文件

* CFile 类提供了用于文件定位的函数,使用这些函数可以实现在文件中的快速定位。

  ```C++
  virtual LONG Seek(LOMG lOff,UINT nFrom);  //定位文件中指定位置的数据
  void SeekToBegin();    //定位到文件头
  DWORD SeekToEnd();		//定位到文件尾
  virtual DWORD GetLength() const;		//获取文件的长度
  virtual void SetLength(DWORD dwNewLength);		//设置文件长度
  
  //Seek() 函数按照指定条件执行文件定位。lOff 参数表示要定位的字符的偏移量;nFrom 参数用于指定定位模式,有下面三种:
  //CFile::Begin:从文件头开始定位字符
  //CFile::current:从文件当前位置开始定位字符
  //CFile::end:从文件尾开始定位字符。
  //Seek() 函数如果定位成功则返回定位位置的字符;否则,抛出异常。
  //SeekToBegin() 和 SeekToEnd() 两个函数的返回值都是文件的字节数
  //SetLength() 函数会扩展或截取文件的长度,参数为要设置的文件长度
  //例:
  
  LONG lOff = 255, lResult;  //定义文件定位使用的变量
  //定位到文件的第226个字符的位置
  lResult = cfile.Seek(lOff,CFile::begin);
  cfile.SeekToBegin(); //定位到文件头
  DWORD dsResult = cfile.SeekToEnd();  //定位到文件尾
  DWORD dwNewLen = 100;
  cfile.SetLength(dwNewLen);  //设置文件长度为100

4、文件管理操作

  • CFile 提供的一些文件管理操作函数,如下:

    函数名 功能
    LockRange() 锁定文件中的一个范围的字节
    UnlockRange() 解锁文件中的一个范围的字节
    GetPosition() 获取文件当前位置的位置指针
    GetStatus() 获取指定文件的状态
    GetFileName() 获取选定的文件名
    GetFileTitle() 获取选定的文件标题
    GetFilePath() 获取选定的文件的完整路径
    SetFilePath() 设置选定的文件的完整路径
    Rename() 重命名指定文件
    Remove() 删除指定文件
    SetStatus() 设置指定文件的状态
  • 示例:

    DWORD dwPos = 5;		//定义位置变量
    DWORD dwCount = 20;		//定义个数变量
    //锁定指定位置处,制定个数的文件的内容
    cfile.LockRange(dwPos,dwCopunt);
    cfile.UnlockRange(dwPos,dwCount);		//解锁对文件的锁定
    DWORD dwPos = cfile.GetPosition();		//获取当前位置
    CFileStatus status;		//定义文件状态变量
    cfile.GetStatus(status);				//获取当前文件的状态
    char* pOldname="old.log";				//原来的文件名
    char* pNewname = "new.log";				//新的文件名
    CFile::Rename(pOldname,pNewname);		//重命名文件名
    char* pFilename = "test.log";			//定义文件名变量
    try
    {
        CFile::Remove(pFilename);			//删除指定文件
    }
    catch(CFileException,e)					//如果删除文件时发生异常
    {
        #ifdef _DEBUG
        	afxDump<<"删除文件"<

5、示例

void CTimerSampleDlg::OnButtonRead()
{
	CFile file;
	file.Open(L"data.txt", CFile::modeRead);  //打开文件
	//获取读取的内容的长度
	int len = min(file.GetLength(), MAX_FILE_LEN);
	char buf[MAX_FILE_LEN] = { 0 };
	char* pOldLocale = _strdup(setlocale(LC_CTYPE, NULL));
	setlocale(LC_CTYPE, "chs");
	file.Read(buf, len); //读取文件内容
	setlocale(LC_CTYPE, pOldLocale);
	free(pOldLocale);
	buf[len] = '\0';
	USES_CONVERSION;//转化为wchar_t* 可以使用CString的Format函数。
	wchar_t* temp = new wchar_t[len + 1];
	temp = A2T(buf);
	CString temp1;
	temp1.Format(_T("%s"), temp);
	SetDlgItemText(IDC_EDIT_FILE, temp1);
	file.Close();
	UpdateData(FALSE);
}
void CTimerSampleDlg::OnButtonWrite()
{
	UpdateData();
	CFile file;
	//打开文件
	file.Open(L"data.txt", CFile::modeCreate | CFile::modeWrite);
	//向文件写入内容
	CString temp;
	GetDlgItem(IDC_EDIT_FILE)->GetWindowText(temp);
	CStringA str_ANSI(temp.GetBuffer(0)); //将字符从UTF-8转成ANSI
	file.Write(str_ANSI.GetBuffer(), str_ANSI.GetLength());
	file.Close(); //关闭文件
	MessageBox(L"写入成功", L"提示");
}

五、异常类

  • MFC 为异常提供了强大的支持,其中 CException 类是 MFC 中所有异常类的基类。使用 MFC 的异常捕获方式,可以增强程序的健壮性,并能为用户提供较详细的错误提示。

1、异常类简介

  • CException 是 MFC 异常类的基类,封装了所有异常共有的操作。使用 CExecption 的 GetErrorMessage() 成员函数可以获取异常的描述说明;使用 ReportError() 函数可以以消息框的方式向用户报告错误信息。

  • 在 CException 类的基础上,MFC 提供了对应多种操作的异常类,使程序可以准确定位异常情况。

    异常类 实现的功能
    CMemoryException 管理内存异常
    CNotSupportException 管理不支持的请求异常
    CArchiveException 管理序列化异常
    CFileException 管理文件异常
    CresourceException 管理资源异常,主要是资源没找到或创建失败的情况
    COleException OLE 异常
    CDBException 数据库异常,主要是基于 MFC 的 ODBC 操作发生的异常
    COleDispatchException OLE 调度异常
    CUserException 表示资源找不到的异常
    CDaoException 数据访问对象异常,由 DAO 类产生
    CInternetException Internet 异常

2.文件异常类 CFileException

  • CFileException 类表示与文件相关的异常情况。CFileException 类包含下面三个数据成员:

  • m_cause:包含异常对应的原因代码。

  • m_IOsError:包含于操作系统相关的错误代码。

  • m_strFileName:包含异常对应的文件名

  • 其中,m_cause 是用于表示文件异常的直接原因的,有效的取值如下:

    原因
    CFileException::none 没有错误发生
    CFileException::generic 发生未指定错误
    CFileException::fileNotFount 没有找到文件
    CFileException::badPath 文件路径无效
    CFileException::tooManyOpenFiles 打开的文件太多
    CFileException::accessDenied 文件不能访问
    CFileException::invalidFile 无效的文件句柄
    CFileException::removeCurrentDir 要移除的文件夹是当前工作的文件夹,不能移除
    CFileException::diretoryFull 文件夹已满
    CFileException::badSeek 在定位文件时发生错误
    CFileException::hardIO 发生硬件错误
    CFileException::sharingViolation 没有装载 SHARE.EXE,或已锁定了共享区域。
    CFileException::lockViolation 要锁定的区域已被锁定
    CFileException::diskFull 磁盘已满
    CFileException::endOfFile 已到达文件尾

3、异常的捕获

  • 捕获异常,需要使用 THROW、THROW_LAST、TRY、CATCH、AND_CATCH 和 END_CATCH 宏。

  • 捕获特殊的异常,必须使用 CException 类相应的派生类;要捕获所有类型的异常,可以使用 CException 类,然后使用 CObject::IsKindOf() 函数判断是否是 CException 类的派生类对象。

  • 注意:CException 类是抽象基类,要抛出异常,必须创建 CException 类的派生类对应的对象。

  • 示例:

    CString pFilename = L"omm.ini";
    void main()
    {
    	TRY
    	{
    		CFile f(pFilename,CFile::modeRead);
    	}
    		CATCH(CFileException, e)
    	{
    		if (e->m_cause == CFileException::fileNotFound)
    			printf("错误:文件没有找到\n");
    	}
    	END_CATCH
    }
    

你可能感兴趣的:(MFC)