|
迷梦小筑—让灵魂在代码中无限升华
我幸运,并不是所有的猫都可以拥有大脑! |
项目需要将阿拉伯数字转为中文序号,google了一下,网上散发的源代码片断颇有点混乱,我不喜欢为这种小问题使用太长的代码,自己动手丰衣足食.看起来还是很简洁的,只实现int类型转汉字。由于中文小数就是一个位一个位读,所以直接将double.toString(),然后小数点后的阿拉伯数字字符与一个中文数字字符数组配对就可以了,不予实现。源代码实现为int的扩展方法,如下:
/// <summary>
/// 将整数转为大写的中文数字
/// </summary>
/// <param name="ni_intInput"></param>
/// <returns></returns>
public static string ToCNUpperCase(this int ni_intInput)
{
string tstrRet = "";
int tintInput;
int tintRemainder, tintDigitPosIndex = 0;
int tintLoopX = 0;
string[] tastrNumCNChar = new string[] { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
string[] tastrDigitPosCNChar = new string[] { "", "十", "佰", "仟", "万", "亿" };
tintInput = ni_intInput;
tintLoopX = 0;
while (tintInput / 10 > 0 || tintInput > 0)
{
tintRemainder = (tintInput % 10);
if (tintLoopX == 5)//十万
tintDigitPosIndex = 1;
else if (tintLoopX == 8)//亿
tintDigitPosIndex = 5;
else if (tintLoopX == 9)//十亿
tintDigitPosIndex = 1;
//end if
if (tintRemainder > 0)
tstrRet
= tastrNumCNChar[tintRemainder] + tastrDigitPosCNChar[tintDigitPosIndex] + tstrRet;
else
tstrRet
= tastrNumCNChar[tintRemainder] + tstrRet; ;
//end if
tintDigitPosIndex += 1;
tintLoopX += 1;
tintInput /= 10;
}//end while
tstrRet = System.Text.RegularExpressions.Regex.Replace(tstrRet, "零零*零*", "零");
return tstrRet;
}//end
/// <summary>
/// 将整数转为小写的中文数字
/// </summary>
/// <param name="ni_intInput"></param>
/// <returns></returns>
public static string ToCNLowerCase(this int ni_intInput)
{
string tstrRet = "";
int tintInput;
int tintRemainder, tintDigitPosIndex = 0;
int tintLoopX = 0;
string[] tastrNumCNChar = new string[] { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
string[] tastrDigitPosCNChar = new string[] { "", "十", "百", "千", "万", "亿" };
tintInput = ni_intInput;
tintLoopX = 0;
while (tintInput / 10 > 0 || tintInput > 0)
{
tintRemainder = (tintInput % 10);
if (tintLoopX == 5)//十万
tintDigitPosIndex = 1;
else if (tintLoopX == 8)//亿
tintDigitPosIndex = 5;
else if (tintLoopX == 9)//十亿
tintDigitPosIndex = 1;
//end if
if (tintRemainder > 0)
tstrRet
= tastrNumCNChar[tintRemainder] + tastrDigitPosCNChar[tintDigitPosIndex] + tstrRet;
else
tstrRet
= tastrNumCNChar[tintRemainder] + tstrRet; ;
//end if
tintDigitPosIndex += 1;
tintLoopX += 1;
tintInput /= 10;
}//end while
tstrRet = System.Text.RegularExpressions.Regex.Replace(tstrRet, "零零*零*", "零");
return tstrRet;
}//end
很久没有写程序了,宝宝出世后不再系统地写代码,弹指间已是两年。最近随手翻翻两年前买的《Visual Basic 2005技术内幕》 的正则表达式一篇(此书的各个版本内容均博大精深,直至现在我对第一版的内容还没看完),想起旧日曾经在csdn提问过IP地址正则表达式的写法,往事历历,几若隔世。当时在csdn的答案考虑不周,如今重写代码修正并记于此间:
^(?!
时日不待,当了解得越多发现自己愈是无知,十年代码不复回望,如果可以让我重学十年......
Treeview控件是我的老伙伴了,但直到前几天,一个希望设定treenode背景色的问题才令我发现,我一直没有深入到它的核心。不过一切都会好转,我决定重新复习windows的基础控件的内部动作。有部电影的对白令我记忆深刻:面包会有的,牛奶会有的。一个能自描绘Treenode的Treeview也会有的8)
根据网上得到的部分代码资料及MSDN的帮助,我先在完整版中继承了一个Treeview对象,并试图处理TreeView的OCM_NOTIFY消息,所有的一切令人愉快,我轻易地截获了TreeNode对象在重绘前发出OCM_NOTIFY消息,消息中的lParam参数代表的NMTVCUSTOMDRAW结构的子结构NMTVCUSTOMDRAW中包含的dwDrawStage成员代表CDDS_ITEMPREPAINT/CDDS_ITEMPOSTPAINT标志,而且这个结构还包含有Treenode重绘时的DC,这意意味着我可以在Treenode的重绘前/后处理这个消息,并不再使用默认的Treeview消息处理过程而达到自描绘的效果。代码片段如下:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
Select Case m.Msg
Case OCM_NOTIFY
Dim NMTVCD As NMTVCUSTOMDRAW
NMTVCD = Marshal.PtrToStructure(m.LParam, GetType(NMTVCUSTOMDRAW))
Select Case NMTVCD.NMCD.hdr.code
Case NM_CUSTOMDRAW
Select Case NMTVCD.NMCD.dwDrawStage
Case CDDS_PREPAINT
' 我要得到Treenode中绘图处理前后的通知
m.Result = CDRF_NOTIFYITEMDRAW
Case CDDS_ITEMPREPAINT //这个通知将在Treenode绘图处理前收到
Dim ptr As New IntPtr
Dim rcItem As New Rectangle
Dim g As Graphics = Graphics.FromHdc(NMTVCD.NMCD.hdc)
Dim b As New SolidBrush(Color.Blue)
rcItem.X = NMTVCD.NMCD.dwItemSpec
SendMessageItemRect(m.HWnd, TVM_GETITEMRECT, 1, rcItem)
//你可以利用Graphics对象g来进行TreeNode的绘图,例如:
g.FillRectangle(New SolidBrush(Color.Yellow), New RectangleF(rcItem.X, rcItem.Y, rcItem.Width, rcItem.Height))
g.Dispose()
b.Dispose()
m.Result = CDRF_SKIPDEFAULT //这个返回值将通知Treeview控件不需再进行这个Treenode的绘图操作
Case CDDS_ITEMPOSTPAINT ////这个通知将在Treenode处理后收到
//和你可以以这儿进行和CDDS_ITEMPREPAINT过程相似的绘图操作
//这代表在Treeview进行treenode描绘后你还可以为treenode再多画一些东西8)
//代码略…
m.Result = CDRF_SKIPDEFAULT
End Select
End Select
Case Else
MyBase.WndProc(m)
End Select
End Sub
但在精简版中,我挂接了TreeView控件的消息处理过程,却始终无法收到OCM_NOTIFY消息,查阅了PPC2003的SDK也没有发现该消息的说明,讨厌的WinCE系统没有提供这个通知。然后我在文档中迷醉了7~80分钟才发现,系统提供的Treeview只向父窗体发送WM_NOTIFY消息,消息的lParam代表的意义和OCM_NOTIFY通知完全一致。与是我不再继承,而是采取了使用一个自定义控件上放一个Treeview的方法。然后我在这个自定义控件中截到了WM_NOTIFY通知消息,接下来的Treenode绘图处理就和上面的示例大同小异了。
//本控件的消息处理过程
private int ThisWindowProc(IntPtr hwnd, uint uMsg, uint wParam, uint lParam)
{
bool tblnUseOldWinProc = true;
int tintFuncReturn = 0;
switch (uMsg)
{
case WM_NOTIFY:
tagNMHDR tudtNMHDR;
tagNMCUSTOMDRAWINFO tudtTreeViewCustomDrawInfo;
tagNMTVCUSTOMDRAW tudtTreeViewCustomDraw;
tudtNMHDR = (tagNMHDR)Marshal.PtrToStructure(new IntPtr(lParam), typeof(tagNMHDR));
if (tudtNMHDR.hwndFrom == treMain.Handle)
{
switch (tudtNMHDR.code)
{
case NM_CUSTOMDRAW:
tudtTreeViewCustomDraw = (tagNMTVCUSTOMDRAW)Marshal.PtrToStructure((IntPtr)lParam,
typeof(tagNMTVCUSTOMDRAW));
tudtTreeViewCustomDrawInfo = tudtTreeViewCustomDraw.nmcd;
switch (tudtTreeViewCustomDrawInfo.dwDrawStage)
{
case CDDS_PREPAINT:
//本控件在Item重画前后都将获得Treeview控件的 NM_CUSTOMDRAW消息
tintFuncReturn = (int)CDRF_NOTIFYITEMDRAW;
tblnUseOldWinProc = false;//不再使用原始窗体的消息处理过程
break;
case CDDS_ITEMPREPAINT:
{
tintFuncReturn = fnCDDS_ITEMPREPAINT_NotifyMessage(hwnd, uMsg, wParam, lParam,
ref tudtTreeViewCustomDraw, ref tblnUseOldWinProc);
Marshal.StructureToPtr(tudtTreeViewCustomDraw, (IntPtr)lParam, false);//这是重绘TreeNode的处理过程
break;
}
default:
break;
}//end switch
break;
}//end switch
}//end if
break;
default:
//对不处理的消息使用treeview的默认消息处理过程
break;
}//end switch
if (tblnUseOldWinProc == true)
return clsCECoreAPI.CallWindowProc(m_intThisPreviousWinProc, hwnd, uMsg, wParam, lParam);
else
return tintFuncReturn;
//end if
}//end function
得到的运行效果如下:
如移动设备开发感兴趣可以加入以下群24123368
入群需知:
1、不是编程开发人员请勿加入。
2、没时间讨论问题或喜欢潜水的请勿加入。
3、只想获得源程序的请勿加入
本blog文档,未经作者同意,谢绝转载。谢谢你对我的blog的访问.
联系方式: missilecat@163.com QQ:85403578
想拥有一个自己的压缩算法实现很久了,但直到net2.0微软才开始提供官方的压缩算法。并且激动永远只是短暂的,作为智能开发的这一片,我们仿佛总是处于遗忘的角落。Net Compact framework (以下简单ncf) 1.0是不必说了,那是一个玩具,绝不是工具!ncf2有了较大改观,可以说这开始成为一种工具了。我们拥有了更多的功能,com的部分支持(但没有ActiveX控件及一些完整Com的功能)。但在System.IO命名空间,失望的我也没有找到Compression空间。。。
在对微软无视使用net精简版的我的需求,我在表达了最强烈的愤慨后,无奈地接受了这一现实。但我实在无法接受等待下一版ncf3的漫长等待,也许等待永远都意味着失望。我决定用行动改变这一切!
我查阅了net2的MSIL源程序,虽然逆向工程并不是一件伟大的事,但我认为我根据net完整版的源程序帮微软提供NCF2的扩充功能对微软应该不是什么坏事8)
System.IO.Compression处于net完整版那臃肿的system.dll中,接下来的事就不细说了,我痛苦地copy/paste并删除了一些ncf2不支持的属性,并将System.SR类合并入这个空间中,4 个小时后,我生成了和完整版功能一模一样的CECompression.dll(当然是一模一样啦,程序都是微软写的,我只是负责修正8))象普罗米修斯从宙斯控制下偷火一样,我将System.IO.Compression带到了幸福的智能开发世界。
在这儿你可以获得这个dll/Files/DreamlikeAttic/CECompression.rar。至于使用嘛,在项目中添加对这个dll的引用就可以了,帮助看msdn对System.IO.Compression的说明就行。。。。
这此我也提供一个使用这个dll的实用程序,可以对指定的源文件进行(压缩/解压缩)后得到目标文件。
完整代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.Compression;
namespace testGzip
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void menuItem1_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnSelectSource_Click(object sender, EventArgs e)
{
dlgFileOpen.FileName = "";
DialogResult tdlgResult = dlgFileOpen.ShowDialog();
if (tdlgResult == DialogResult.OK)
txtSource.Text = dlgFileOpen.FileName;
//end if
}//end sub
private void btnSelectDest_Click(object sender, EventArgs e)
{
dlgSaveFile.FileName = "";
DialogResult tdlgResult = dlgSaveFile.ShowDialog();
if (tdlgResult == DialogResult.OK)
txtDest.Text = dlgSaveFile.FileName;
//end if
}
private void btnZip_Click(object sender, EventArgs e)
{
//开始压缩
//先验证源文件名及目标文件名的正确性
if (System.IO.File.Exists(txtSource.Text) == false)
{
MessageBox.Show("源文件名指定的文件不存在");
txtSource.Focus();
return;
}//end if
if (System.IO.File.Exists(txtDest.Text) == true)
{
DialogResult tdlgResult = MessageBox.Show("指定的目标文件已存在,覆盖吗?",
"文件覆盖确认", MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1);
if (tdlgResult == DialogResult.No)
{
txtDest.Focus();
return;
}
}//endif
bool tblnResult = FileGZipCompress(txtSource.Text, txtDest.Text);
if (tblnResult == false)
MessageBox.Show("压缩出现错误!压缩失败");
//end if
}//end sub
bool FileGZipCompress(string ni_strSourceFile, string ni_strDestFile)
{
FileStream tobjSourceFileStream;
MessageBox.Show("开始对"+txtSource.Text +"进行文件压缩");
try
{
// Open the file as a FileStream object.
tobjSourceFileStream = new FileStream(ni_strSourceFile, FileMode.Open, FileAccess.Read, FileShare.Read);
byte[] taSourcebuffer = new byte[tobjSourceFileStream.Length];
// Read the file to ensure it is readable.
int count = tobjSourceFileStream.Read(taSourcebuffer, 0, taSourcebuffer.Length);
if (count != taSourcebuffer.Length)
{
tobjSourceFileStream.Close();
MessageBox.Show("压缩失败,不能读取指定的文件");
return false ;
}
tobjSourceFileStream.Close();
FileStream tobjDestFileStream = new FileStream(ni_strDestFile,FileMode.Create,FileAccess.ReadWrite );// new MemoryStream();
MemoryStream tobjMemStream = new MemoryStream();
// 使用内存流进行压缩
GZipStream compressedzipStream = new GZipStream(tobjMemStream, CompressionMode.Compress, true);
Cursor.Current = Cursors.WaitCursor;
//向压缩流写入要压缩的数据
compressedzipStream.Write(taSourcebuffer, 0, taSourcebuffer.Length);
//关闭压缩流
compressedzipStream.Close();
//此处应该写入文件头信息,在此处简单写入一个文件长度
tobjDestFileStream.Position = 0;
tobjDestFileStream.Write(BitConverter.GetBytes(taSourcebuffer.Length),0,4);//写入4字节的文件长度
//定入压缩得到的实际数据
tobjMemStream.WriteTo(tobjDestFileStream);
tobjMemStream.Close();
Cursor.Current = Cursors.Default;
MessageBox.Show("压缩完成.源文件大小为:\n" + taSourcebuffer.Length + "字节\n"
+ "压缩后大小为" + tobjDestFileStream.Length + "字节\n"
+ "压缩比为: " + (tobjDestFileStream.Length / taSourcebuffer.Length*100)+" %");
tobjDestFileStream.Close();
return true;
}
catch
{
return false;
}//end try
}//end sub
private bool FileGZipDecompress(string ni_strSourceFile, string ni_strDestFile)
{
//对指定的压缩文件进行解压缩
FileStream tobjSourceFileStream;
GZipStream tobjGzipStream = null;
MemoryStream tobjMemStream ;
try
{
Cursor.Current = Cursors.WaitCursor;
tobjSourceFileStream = new FileStream(ni_strSourceFile, FileMode.Open, FileAccess.Read, FileShare.Read);
//取得文件的原始长度
byte[] tabytFileLength=new byte[4];
tobjSourceFileStream.Read(tabytFileLength,0,4);
int tintFileLength = BitConverter.ToInt32(tabytFileLength,0);
byte[] tabyteDeCompressData=new byte[tobjSourceFileStream.Length-4];
tobjSourceFileStream.Read(tabyteDeCompressData, 0, tabyteDeCompressData.Length);
tobjMemStream = new MemoryStream(tabyteDeCompressData);
tobjGzipStream = new GZipStream(tobjMemStream, CompressionMode.Decompress);
byte[] tabytBuffer = new byte[tintFileLength];
tobjGzipStream.Read( tabytBuffer, 0, tintFileLength );
tobjGzipStream.Close();
tobjSourceFileStream.Close();
//将压缩的数据写入目标文件
FileStream tobjDestFileStream = new FileStream(ni_strDestFile, FileMode.Create, FileAccess.ReadWrite,
FileShare.None);
tobjDestFileStream.Write(tabytBuffer, 0, tabytBuffer.Length);
tobjDestFileStream.Close();
Cursor.Current = Cursors.Default;
return true;
}
catch
{
return false;
}//end try
}//end sub
private void btnUnzip_Click(object sender, EventArgs e)
{
//开始解压缩
//先验证源文件名及目标文件名的正确性
if (System.IO.File.Exists(txtSource.Text) == false)
{
MessageBox.Show("源文件名指定的文件不存在");
txtSource.Focus();
return;
}//end if
if (System.IO.File.Exists(txtDest.Text) == true)
{
DialogResult tdlgResult = MessageBox.Show("指定的目标文件已存在,覆盖吗?",
"文件覆盖确认", MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1);
if (tdlgResult == DialogResult.No)
{
txtDest.Focus();
return;
}
}//endif
MessageBox.Show("开始对\"" + txtSource.Text + "\"进行文件解压缩");
bool tblnResult = FileGZipDecompress(txtSource.Text, txtDest.Text);
if (tblnResult == false)
MessageBox.Show("解压缩出现错误!解压缩失败");
else
MessageBox.Show("解压缩成功完成");
//end if
}//end sub
}//end class
}//end namespace
你可以这儿获取相应的源程序包:/Files/DreamlikeAttic/CECompressionTest.rar
如移动设备开发感兴趣可以加入以下群24123368
入群需知:
1、不是编程开发人员请勿加入。
2、没时间讨论问题或喜欢潜水的请勿加入。
3、只想获得源程序的请勿加入
本blog文档,未经作者同意,谢绝转载。谢谢你对我的blog的访问.
联系方式: missilecat@163.com QQ:85403578

