一、 实验内容
编程实现算术编码算法 二、实验环境
1. 计算机
2. Windows 2000 或以上 3. VS2005 三、实验目的
1. 进一步熟悉算术编码算法; 2. 掌握C语言编程(尤其是数值的进制转换,数值与字符串之间的转换等) 四、实验要求
1. 提前预习实验,认真阅读实验原理。
2. 认真高效的完成实验,实验过程中服从实验室管理人员以及实验指导老
师的管理。
3. 认真填写实验报告。 五、实验原理
算术编码是把一个信源表示为实轴上0和1之间的一个区间,信源集合中的每一个元素都用来缩短这个区间。
1. 算法流程
(1) 输入信源符号个数,信源概率分布,还有需要编码的符号序列, (2) 根据概率可以算出初始编码间隔, High——当前编码的上限, Low——当前编码的下限, high——中间变量,用来计算下一个编码符号的当前间隔的上限, low——中间变量,用来计算下一个编码符号的当前间隔的下限, d——当前间隔之间的距离。 (3)扫描需编码的符号序列,确定编码空间 第1个编码符号的当前间隔为其初始的编码间隔, 第i个编码符号的当前间隔为第i-1个编码后的[Low,High), 第i+1个编码符号的当前间隔算法如下:high=Low+d*第i+1个初始编码符号对应的上限,low=Low+d*第i+1个编码符号对应的下限,然后High=high,Low=low,d=d*第i个编码符号的概率。 六、参考书
1. 《信息论——基础理论及应用》傅祖芸,电子工业出版社
七、程序设计 7.1程序流程图
开始 输入信源符号及其概率 求出信源符号的累加概率 根据信源符号的概率和累加概率对待编码序列进行算术编码,并输出
7.2关键代码设计
1)计算部分最终得到Low
for(i = 1;i < length;i++) for(j = 0;j < count;j++) {
if(code[i] == number[j]) {
if(j == 0) { } else { }
double chance_l = 0.0; for(int k = 0;k <= j-1;k++)
chance_l += chance[k]; low = Low + d * chance_l;
high = Low + d * (chance_l + chance[j]); Low = low; High = high; d *= chance[j];
low = Low;
high = Low + chance[j] * d; High = high; d *= chance[j];
}
} else
continue;
2)计算码长
for (int i = 0;i < length;i++)
for (int j = 0;j < count;j++) { }
if (code[i] == number[j])
sum *= chance[i];
int L = (int) log(1.00/sum);
3)求最终编码
for(int i = 0;i < L;i++)
{ }
Low *= 2; if (Low > 1) { } else
cout<<0; cout << 1; Low -= 1;
7.3程序运行结果
输入信源符号及对应的概率分布:
输入符号序列:
得到相应的结果:
该数据来源为课件。 7.4、程序分析
在网上下的程序并未对码长以及最终编码进行计算和输出,根据可见所讲,将信息熵求出后计算了码长,并输出了最后的编码结果。
重新认识了算术编码的编码过程,对于解码部分,并未做相应的编程实现。但是了解了其解码过程,虽然对能否无损解码持怀疑态度。 八、源代码
#include void suanshu::get_number() { cout<<\"输入信源符号及其对应概率:\"< for(i = 0;i < N && sum <= 1;i++) int count,length; char number[N],n; long double chance[N],c; char code[M]; long double High,Low,high,low,d; suanshu() {High=0;Low=0;} void get_number(); void get_code(); void coding(); void print(); ~suanshu(){}; public: } { } if(i == 20) cout<<\"信源符号数溢出.\"< cin >> n >> c; number[i] = n; chance[i] = c; sum += c; void suanshu::get_code() { } void suanshu::coding() { int i,j=0; for(i=0;i for(i = 1;i < length;i++) for(j = 0;j < count;j++) { if(code[i] == number[j]) { if(j == 0) { low = Low; high = Low + chance[j] * d; cout<<\"输入符号序列长:\"; cin>>length; while(length>=M) { } for(int i=0;i cout<<\"输入的符号序列超长,请改小!\"; cin>>length; } } } } High = high; d *= chance[j]; else { } double chance_l = 0.0; for(int k = 0;k <= j-1;k++) chance_l += chance[k]; low = Low + d * chance_l; high = Low + d * (chance_l + chance[j]); Low = low; High = high; d *= chance[j]; else continue; void suanshu::print() { cout<<\"算数编码结果为:\"< for (int j = 0;j < count;j++) { } if (code[i] == number[j]) sum *= chance[i]; int L = (int) log(1.00/sum); for(int i = 0;i < L;i++) { } cout< cout<<0; cout << 1; Low -= 1; } void main() { } suanshu a; a.get_number(); a.get_code(); a.coding(); a.print(); 实验四 Huffman编码对英文文本的压缩和解压缩 一、实验内容 根据信源压缩编码——Huffman编码的原理,制作对英文文本进行压缩和解压缩的软件。要求软件有简单的用户界面,软件能够对运行的状态生成报告,分别是:字符频率统计报告、编码报告、压缩程度信息报告、码表存储空间报告。 二、实验环境 4. 计算机 5. Windows 2000 或以上 6. Microsoft Office 2000 或以上 7. VS2005 三、实验目的 3. 掌握Huffman编码的原理 4. 掌握VC开发环境的使用(尤其是程序调试技巧) 5. 掌握C语言编程(尤其是位运算和文件的操作) 6. 掌握数据结构的内容:链表、顺序表、堆栈、最优二叉树 7. 掌握结构化程序分析和开发的软件工程原理 四、实验要求 4. 提前预习实验,认真阅读实验原理。 5. 认真高效的完成实验,实验过程中服从实验室管理人员以及实验指导老 师的管理。 6. 认真填写实验报告。 五、实验原理 压缩/解压缩流程 压缩流程: 读取扫描文本文件——〉统计字符频率——〉生成码字——〉保存压缩文件 解压缩流程: 读取扫描压缩文件——〉提取字符频率——〉生成码树——〉保存文本文件 六、参考书 1. 《信息论——基础理论及应用》傅祖芸,电子工业出版社 2. 《数据结构》,清华大学出版社 七、程序设计 7.1数据结构描述: 以下是哈夫曼树结点的结构: 哈夫曼树以数组形式保存,其元素个数是2n-1,其中n为叶子数。typedef struct talNode{ 对应结点的哈夫曼编码用一个数组 unsigned char c; //叶结点时对应ASCII记录,该数组元素是指向字符的指值 针 int weight; //该结点权值 7.2主要算法描述 int lt,rt; //左、右结点下标 7.2.1压缩 talNode(){} 其基本实现方法是,因为英文 talNode(unsigned char _c,int _p): 文件中都是ACSII码(包括英文的 c(_c),weight(_p),lt(-1),rt(-1) 标点符号),所以对选定的文件文本 {} 读入,一次读入一个字符,然后对 talNode(unsigned char _c,int _p,int 每个ASCII字符进行统计,如此循l,int r) 换,这就统计出文件的每个字符的 :c(_c),weight(_p),lt(l),rt(r) 权值了。 {} 得出文件各字节的权值后,就 bool operator < (talNode a) 可以构造对应哈夫曼的哈夫曼树, {//重载运算符“<”用于二叉堆内的比较 从而就可以构造出对应字符的哈夫 return weight 解压时,先读出哈夫曼编码的节点及其权值,然后对编码部分读取一个字节(8 bit)用一个函数转换为8个字符(用一个数组记录,其元素只是一个0或一个1),然后按哈夫曼树从顶向下查找,如果到达叶子结点,就读出该叶子结点的值,放入缓冲区中,如果不是,则继续找,如此重复,直到缓冲区满了,就写入到解压文件中,再循环以上过程,直到处理完所有数据。 7.3具体函数设计 7.3.1压缩函数设计 点击压缩后,调用压缩函数EnCodeFile() //哈夫曼树结点结构体实现 SaveHuffHead(fpt); l=data=0; puts(\"Encoding ... \"); //编码压缩过程,依次对源文件字符进行编码 while(true){ //存入一个字符中,用移位操作实现,每位前 //缀码对应一个字符,将该字符存入目标文件, //最终不足位的记录最后一位占用的前缀//源文件长度增加 //对当前字符的前缀码当前们存储于data c=fgetc(fp); //写入压缩文件的头信息!!!注意,此时 lastcodelenth为空,需压缩结束时重置 if(feof(fp)) break; soucelen++; data<<=1; 码长度 for(i=0;i 中 } } //对最后的一个字符进行处理 //记录实际占用位的长度 //空出剩余位 data+=code[c][i]; if(++l%8==0){ } //满位,则存储 fputc(data,fpt); targetlen++; //目标文件长度增加 lastcodelenth=l%8; fputc(data,fpt); targetlen++; data<<=8-lastcodelenth; //输出至文件 //目标文件长度增加 该函数主要是涉及三个步骤:构造哈夫曼树、构造哈弗曼编码、压缩。 7.3.2解压函数设计 点击解压后,调用解压函数DeCodeFile() DeCodePre(fp); } for(i=l+7;i>=l;i--){ tmp[i]=c&1; c>>=1; //对最后一个字符做特殊处理 //取出每一位 while(l>=32){ //如果当前前缀码段超出一定的长度,则 取出前缀码进行解码 for(i=0,cur=arr[size-1];!cur.c;i++) cur=tmp[i]?arr[cur.rt]:arr[cur.lt];//找到前缀码段对应第一个字符 //输出至目标文件 //前缀码段减去当前字符前缀码//数组顺移至开头,即从开始记 fprintf(fpt,\"%c\",cur.c); l-=i;targetlen++; for(i=l+7;i>=l;i--){ tmp[i]=c&1;c>>=1; }l+=8; //按位取出前缀码 l=0; //解码过程,压缩过程的逆过程,取出编 puts(\"Decoding ... \"); fscanf(fp,\"%c\",&c); 码了的字符, //按位取出,存于tmp[]中,找出前缀码对应的字符 while(!feof(fp)){ soucelen++; fscanf(fp,\"%c\",&t); if(feof(fp))break; 长度 memmove(tmp,tmp+i,sizeof(bool)*l); 录当前的前缀码段 }c=t; 符 } l+=lastcodelenth; while(l){ } fclose(fp);fclose(fpt); //关闭文件 //只利用最后一个字符的前//输出剩余的前缀码段对应的字 lastcodelenth位 for(i=0,cur=arr[size-1];!cur.c;i++) cur=tmp[i]?arr[cur.rt]:arr[cur.lt]; fprintf(fpt,\"%c\",cur.c);l-=i;targetlen++; memmove(tmp,tmp+i,sizeof(bool)*l); 7.4程序体验 7.4.1程序界面: 7.4.2选择文件并压缩: 源文件“test.txt”的内容 选取文件 压缩完成 选择的源文件为:“D:\\我的文档\est.txt”压缩后的文件存储在相同路径 下,压缩后的文件名:“test.huf”,文件长度减小了7908。其内容为下: 压缩后的内容 7.4.3解压 选择刚才的压缩文件进行解压: 选取文件 解压成功 解压后的文件名为:“test.txt” 解压后的文件内容 经过压缩解压后得到的文件内容和压缩前的一致。 利用MD5比较,得到压缩前文件与解压得到的文件为同一文件。 DE01E3358BCA716ACB444661E862CBDD DE01E3358BCA716ACB444661E862CBDD 八、源代码 Huffman.h: #pragma once //*************************************************************** //课程:信息论与编码 //题目:霍夫曼编码实现文本压缩解压 //老师:余林琛 //作者:刘宇豪 //时间:-11-2 //*************************************************************** #include #define SWAP(a,b,tmp) {tmp=a;a=b;b=tmp;} using namespace std; //实现二叉堆模板类,小顶堆 template HeapType *data,tmp; int size; void HeapUp(int ix) {//自底向顶维护堆 } void HeapDown(int ix) {//自顶向底维护堆 } CHeap() {//这里特殊应用,堆内元素个数不超过 size=0; data=new HeapType[256]; int l,r,t; HeapType min,tmp; if(ix>=size) return ; l=L(ix),r=R(ix); min=data[ix],t=ix; if(l public: }; } ~CHeap() {//释放内存 } int getsize() {//返回堆大小 } void clear() {//清空堆 } void insert(HeapType e) {//向堆尾中插入元素,并向顶维护堆 } HeapType top() {//从堆顶取出元素,并向底维护堆 } HeapType ret=data[0]; data[0]=data[--size]; HeapDown(0);return ret; data[size++]=e; HeapUp(size-1); size=0; return size; delete data; //哈夫曼树结点结构体实现 typedef struct talNode{ unsigned char c; //叶结点时对应ASCII值 int weight; int lt,rt; talNode(){} talNode(unsigned char _c,int _p): c(_c),weight(_p),lt(-1),rt(-1) {} talNode(unsigned char _c,int _p,int l,int r) {} bool operator < (talNode a) {//重载运算符“<”用于二叉堆内的比较 } return weight }HuffNode; class CHuffMan{ HuffNode arr[512]; //哈夫曼树结点数组 }; int size; //哈夫曼树结点个数 //ASCII对应编码方案 //ASCII对应编码长度 //文件最后一个字符实用几位 bool code[256][64]; int lenth[256]; int lastcodelenth; int ps[256]; //lastcodelenth,ps[256],用于存储压缩文件中作为文件头 //ASCII对应出现频率 int soucelen,targetlen; //源及目标文件长度 //私有成员函数,用于实现内部功能 void SetHuffTree(int []); void CreateHuff(int []); void EnCodePre(CString); void DeCodePre(FILE *); void SaveHuffHead(FILE *); void ReadHuffHead(FILE *); CHuffMan(){Clear();} ~CHuffMan(){} void Clear(); //根据字符频率生成哈夫曼树 //创建哈夫曼树及编码方案 //压缩前预处理 //解压前预处理 //保存压缩文件头 //读取压缩文件头 void SetHuffCode(int ,bool [],int );//根据哈夫曼树生成编码方案 public: //构造函数 //析构函数 //清空当前对象内容 //公有成员函数,用于提供使用接口 void EnCodeFile(CString,CString); //编码,用于压缩文件,第一个参数为源文件名,第void DeCodeFile(CString,CString); //解码,用于解压文件,第一个参数为源文件名,第int GetSouceLen(); //输出当前工作项的源文件长度 //输出当前工作项的目标文件长度 二个参数为目标文件名 二个参数为目标文件名 int GetTargetLen(); void CHuffMan::SetHuffTree(int ps[]) { //每次取出两权值最小的结点合并成新树, //加入堆,直至堆中只余有一个元素 CHeap //初始化哈夫曼树中结点个数 //取出权值最小的两个结点 while(hp.getsize()>1){ arr[size++]=hp.top(); arr[size++]=hp.top(); hp.insert(HuffNode(0, arr[size-1].weight+arr[size-2].weight, size-1,size-2)); //合并结点,并插入堆 if(ps[i]) hp.insert(HuffNode(i,ps[i])); //二叉堆对象 //如果字符i出现过,则插入二插堆 for(int i=0;i arr[size++]=hp.top(); //arr[size-1]为哈夫曼树根 void CHuffMan::SetHuffCode(int ix,bool stk[],int top) { } void CHuffMan::CreateHuff(int ps[]) { } void CHuffMan::EnCodePre(CString sfilename) { //压缩文件预处理,读取字符出现频率 //及构造哈夫曼树及前缀码 FILE *fp; int c; char *file_tmp; DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,sfilename,-1,NULL,0,NULL,FALSE); file_tmp = new char[dwNum]; WideCharToMultiByte(CP_OEMCP,NULL,sfilename,-1,file_tmp,dwNum,NULL,FALSE); fp=fopen(file_tmp,\"rb\"); if(fp==NULL){ if(MessageBox(NULL,L\"打开文件出错\",L\"梦已喂马\",MB_OK)) } memset(ps,0,sizeof(ps)); while(true){ } fclose(fp); c=fgetc(fp); if(feof(fp))break; ps[c]++; //读取字符出现频率 exit(0); //构造哈夫曼树及前缀码 bool stk[64]; SetHuffTree(ps); //根据字符频率构造哈夫曼树 //根据哈夫曼树生成前缀码 SetHuffCode(size-1,stk,0); //递归深搜哈夫曼树,生成所有存在的ASCII的//如果 前缀码 if(arr[ix].c){ } stk[top]=0; stk[top]=1; //左子树的边设为 //递归进入左子树 //右子树的边设为 //递归进入右子树 SetHuffCode(arr[ix].lt,stk,top+1); SetHuffCode(arr[ix].rt,stk,top+1); if(top){ } else lenth[arr[ix].c]=1; return ; //此判断用于只含有一类字符的文件 memmove(code[arr[ix].c],stk,sizeof(bool)*top); lenth[arr[ix].c]=top; } CreateHuff(ps); //构造哈夫曼树及前缀码 void CHuffMan::DeCodePre(FILE *fp) { } void CHuffMan::SaveHuffHead(FILE *fp) { } void CHuffMan::ReadHuffHead(FILE *fp) { } void CHuffMan::Clear() { } int CHuffMan::GetSouceLen() { } int CHuffMan::GetTargetLen() { } void CHuffMan::EnCodeFile(CString sfilename,CString gfilename) { //将文件sfilename压缩为文件gfilename FILE *fp,*fpt; int c,data,l,i; char *file_tmp; file_tmp = new char[sfilename.GetLength() + 1]; DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,sfilename,-1,NULL,0,NULL,FALSE); //获取当前工作项的目标文件长度 return targetlen; //获取当前工作项的源文件长度 return soucelen; //清空前前工作项 size=0;soucelen=targetlen=0; lastcodelenth=0; memset(lenth,0,sizeof(lenth)); memset(ps,0,sizeof(ps)); //从缩文件中读文件头 //从lastcodelenth的地址开始的连续 fread((void *)&lastcodelenth,4,257,fp); //4*257个字节,即lastcodelenth和 soucelen+=4*257; //ps[256]数组内容 //向压缩文件中写文件头 fwrite((void *)&lastcodelenth,4,257,fp);//从lastcodelenth的地址开始的连续 //4*257个字节,即lastcodelenth和 //ps[256]数组内容 targetlen+=4*257; //解压文件预处理,读取压缩文件头 //根据读取头信息构千哈夫曼树及前缀码 ReadHuffHead(fp); CreateHuff(ps); 中 至 } file_tmp = new char[dwNum]; WideCharToMultiByte (CP_OEMCP,NULL,sfilename,-1,file_tmp,dwNum,NULL,FALSE); EnCodePre(sfilename); fp=fopen(file_tmp,\"rb\"); if(fp==NULL){ } delete [] file_tmp; dwNum = WideCharToMultiByte(CP_OEMCP,NULL,gfilename,-1,NULL,0,NULL,FALSE); file_tmp= new char[dwNum]; WideCharToMultiByte (CP_OEMCP,NULL,gfilename,-1,file_tmp,dwNum,NULL,FALSE); fpt=fopen(file_tmp,\"wb\"); SaveHuffHead(fpt); l=data=0; puts(\"Encoding ... \"); //编码压缩过程,依次对源文件字符进行编码 while(true){ } //满位,则存储 //存入一个字符中,用移位操作实现,每位前 //缀码对应一个字符,将该字符存入目标文件, //最终不足位的记录最后一位占用的前缀//源文件长度增加 //对当前字符的前缀码当前们存储于data c=fgetc(fp); //写入压缩文件的头信息!!!注意,此时 if(MessageBox(NULL,L\"打开文件出错\",L\"梦已喂马\",MB_OK)) exit(0); //压缩预处理,生成哈曼树及字符前缀码 lastcodelenth为空,需压缩结束时重置 if(feof(fp)) break; soucelen++; } data<<=1; 码长度 for(i=0;i data+=code[c][i]; if(++l%8==0){ } fputc(data,fpt); targetlen++; //目标文件长度增加 //对最后的一个字符进行处理 //记录实际占用位的长度 //空出剩余位 lastcodelenth=l%8; fputc(data,fpt); targetlen++; data<<=8-lastcodelenth; //输出至文件 //目标文件长度增加 //!!!回溯至文件头,更新lastcodelenth//真实值 //关闭文件 fseek(fpt,0,SEEK_SET); fwrite(&lastcodelenth,4,1,fpt); fclose(fp); fclose(fpt); void CHuffMan::DeCodeFile(CString sfilename,CString gfilename) { //解压文件sfile至gfile FILE *fp,*fpt; char *file_tmp; DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,sfilename,-1,NULL,0,NULL,FALSE); file_tmp = new char[dwNum]; WideCharToMultiByte(CP_OEMCP,NULL,sfilename,-1,file_tmp,dwNum,NULL,FALSE); fp=fopen(file_tmp,\"rb\"); delete []file_tmp; dwNum = WideCharToMultiByte(CP_OEMCP,NULL,gfilename,-1,NULL,0,NULL,FALSE); file_tmp = new char[dwNum]; WideCharToMultiByte(CP_OEMCP,NULL,gfilename,-1,file_tmp,dwNum,NULL,FALSE); fpt=fopen(file_tmp,\"wb\"); int c,t,l,i; HuffNode cur; bool tmp[64]; DeCodePre(fp); l=0; //解码过程,压缩过程的逆过程,取出编 puts(\"Decoding ... \"); fscanf(fp,\"%c\",&c); //tmp[]用于记录当前的前缀码段 //l用于记录当前前缀码段的长度 码了的字符, //按位取出,存于tmp[]中,找出前缀码对应的字符 while(!feof(fp)){ } for(i=l+7;i>=l;i--){ } l+=lastcodelenth; //只利用最后一个字符的前 tmp[i]=c&1; c>>=1; //对最后一个字符做特殊处理 //取出每一位 soucelen++; fscanf(fp,\"%c\",&t); if(feof(fp))break; for(i=l+7;i>=l;i--){ tmp[i]=c&1;c>>=1; //如果当前前缀码段超出一定的长度,则 }l+=8; while(l>=32){ //按位取出前缀码 取出前缀码进行解码 for(i=0,cur=arr[size-1];!cur.c;i++) cur=tmp[i]?arr[cur.rt]:arr[cur.lt];//找到前缀码段对应第一个字符 //输出至目标文件 //前缀码段减去当前字符前缀码//数组顺移至开头,即从开始记 fprintf(fpt,\"%c\",cur.c); l-=i;targetlen++; 长度 memmove(tmp,tmp+i,sizeof(bool)*l); 录当前的前缀码段 }c=t; lastcodelenth位 符 } test_MFCDlg.cpp: // test_MFCDlg.cpp : 实现文件 // #include \"stdafx.h\" #include \"test_MFC.h\" #include \"test_MFCDlg.h\" #include \"Huffman.h\" #ifdef _DEBUG #define new DEBUG_NEW #endif // Ctest_MFCDlg 对话框 Ctest_MFCDlg::Ctest_MFCDlg(CWnd* pParent /*=NULL*/) { } void Ctest_MFCDlg::DoDataExchange(CDataExchange* pDX) { } BEGIN_MESSAGE_MAP(Ctest_MFCDlg, CDialog) ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_ChBtn, &Ctest_MFCDlg::OnBnClickedChbtn) ON_BN_CLICKED(IDC_Unzip, &Ctest_MFCDlg::OnBnClickedUnzip) CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_FileEdit, f_edit); DDX_Control(pDX, IDC_Show, s_edit); m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); : CDialog(Ctest_MFCDlg::IDD, pParent) } fclose(fp);fclose(fpt); //关闭文件 for(i=0,cur=arr[size-1];!cur.c;i++) cur=tmp[i]?arr[cur.rt]:arr[cur.lt]; fprintf(fpt,\"%c\",cur.c);l-=i;targetlen++; memmove(tmp,tmp+i,sizeof(bool)*l); while(l){ //输出剩余的前缀码段对应的字 END_MESSAGE_MAP() // Ctest_MFCDlg 消息处理程序 BOOL Ctest_MFCDlg::OnInitDialog() { CDialog::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 } // 执行此操作 SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE); // 设置大图标 // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回TRUE // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的MFC 应用程序, // 这将由框架自动完成。 void Ctest_MFCDlg::OnPaint() { 0); } //当用户拖动最小化窗口时系统调用此函数取得光标显示。 // HCURSOR Ctest_MFCDlg::OnQueryDragIcon() { } void Ctest_MFCDlg::OnBnClickedChbtn() { // TODO: 在此添加控件通知处理程序代码 CHuffMan work; CFileDialog filedlg(true); filedlg.m_ofn.lpstrTitle=L\"Huffman压缩文件打开框\"; filedlg.m_ofn.lpstrFilter=L\"Text Files(*.txt)\\0*.txt\\0All Files(*.*)\\0*.*\\0\\0\"; return static_cast CDialog::OnPaint(); // 使图标在工作矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast } if(IDCANCEL == filedlg.DoModal()) { } CString str = filedlg.GetPathName(); f_edit.SetSel(0,-1); f_edit.ReplaceSel(str); int pos = str.Find(L\".\"); CString str_tmp = str.Left(pos + 1); str_tmp += L\"huf\"; work.Clear(); work.EnCodeFile(str,str_tmp); str_tmp = L\"\"; str_tmp.Format(_T(\"源文件长度:\%d 目标文件长s_edit.SetSel(0,-1); s_edit.ReplaceSel(str_tmp); return; 度:\%d\"),work.GetSouceLen(),work.GetTargetLen()); void Ctest_MFCDlg::OnBnClickedUnzip() { } // TODO: 在此添加控件通知处理程序代码 CHuffMan work; CFileDialog filedlg(true); filedlg.m_ofn.lpstrTitle=L\"Huffman解压文件打开框\"; filedlg.m_ofn.lpstrFilter=L\"Text Files(*.huf)\\0*.huf\\0All Files(*.*)\\0*.*\\0\\0\"; if(IDCANCEL == filedlg.DoModal()) { } CString str = filedlg.GetPathName(); f_edit.SetSel(0,-1); f_edit.ReplaceSel(str); int pos = str.Find(L\".\"); CString str_tmp = str.Left(pos + 1); str_tmp += L\"txt\"; work.Clear(); work.DeCodeFile(str,str_tmp); str_tmp = L\"\"; str_tmp.Format(_T(\"源文件长度:\%d 目标文件长s_edit.SetSel(0,-1); s_edit.ReplaceSel(str_tmp); return; 度:\%d\"),work.GetSouceLen(),work.GetTargetLen()); 因篇幅问题不能全部显示,请点此查看更多更全内容