标题
[sdk/windows]OCM_NOTIFY 并不一定发送
clq
浏览(2) +
2008-04-18 11:26:06 发表
编辑
关键字:
[sdk/windows]OCM_NOTIFY 并不一定发送 看资料说子控件在发送 WM_NOTIFY 的时候,父窗口有可能反射相应的 OCM_NOTIFY 给子控件。但实际上这个 OCM_NOTIFY 是不可靠的,稳妥的办法还是有父窗口中接收 WM_NOTIFY 消息。
clq
可参考这个例子。 来自 http://www.cnblogs.com/DreamlikeAttic/archive/2006/08/05/468876.html 剖析Net 精简版中Treeview控件Treenode的自描绘处理 连日暴雨倾盘,我养的小猫整日卷缩在阳台的角落象只死老鼠般一动不动,而我则在数据仓库的十多个表的联系独立分析中迷惘,枯燥无味的数据绑定使用程序失去了所有的生趣。我却定做一些其它的事情来放松绷紧的猫脑。 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 posted @ 2006-08-05 21:10 拍拍猫脑 阅读(1341) | 评论 (7) | 编辑 2006年7月7日 在Pocket PC/Smartphone智能设备上编写压缩程序(特别简单,任何人都能简单使用) 想拥有一个自己的压缩算法实现很久了,但直到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 posted @ 2006-07-07 23:54 拍拍猫脑 阅读(965) | 评论 (3) | 编辑 2006年6月30日 使用完整拼音查找汉字(完整拼音,不是网上散布的首字符拼音那种方法) 注意:这绝不是网上散播的只能使用拼音首字符进行汉字查找的方案,这是一个真正的输入完整拼音得到相应汉字的解决办法。 大部分程序员眼中只有变量、函数……他们忽略生活中的一切,他们并不理解真正的优雅的程序解决方案往往来自生活! 今天群内有兄弟提问怎样使用一个完整的拼音查找到相应的汉字。这显然是网上散播的只能使用拼音首字符进行汉字查找的方案无法解决的,他们在拼命地寻找微软的API,网上现成的函数,但他们忽略了一点,其实所有的一切,都因为他们缺少一个(汉字,拼音)这样的格式的数据库。 其实取得这样一个数据库很简单。在很久以前我初学电脑,很久很久以前的事了,我那时只会玩各种不同的游戏8-)由于我不会用win98,所以我常常用鼠标点击我可以点击到的一切东西,其中适好包括一个叫“输入法生成器”的程序。更奏巧的是我当时也适好发现这个输入法生成器可以将输入法的数据库转为一个可读的TXT文件。只要取得全拼输入法的数据文件,一切都解决了。 1、首先需要一个win98 ,你们可能没有了吧,因为你们不玩游戏8(,用VMware虚拟安装啦。输入法生成器是可选安装的,如果在附件中没看到<输入法生成器> ,就使用win98 的安装程序安装它。 打开输入法生成器,选逆转换 ,打开文件c:\windows\system\winpy.mb(这是全拼输入法的数据文件),在码表原文件中写上c:\windows\desktop\winpy.txt 按逆转换 很高兴,我们得到了拼音字符的数据库文件winpy.txt。 用编辑软件打开这个文件,看到这样的格式: Description] Name=全拼 MaxCodes=12 MaxElement=1 UsedCodes=abcdefghijklmnopqrstuvwxyz WildChar=? NumRules=3 [Rule] ca4=p10+p20+p30+p40 ce2=p10+p20 ce3=p10+p20+p30 [Text] 啊a 阿a 一个汉字对一个拼音,回车换行符分开各项,将这种格式的字符串分为汉字和拼音是很容易的,拼音是字母,在unicode中不会超过255,汉字在unicode中大于255,根据这个判断来分割就行了 2、将文件的头几行说明删除后,我们得到这样格式的拼音与汉字的键对(呵a he),应为需要用拼音找汉字,我再用一个C#代码将这个文件格式变为(a he呵)拼音在前,汉字在后这样的格式以方便查找。 示例程序效果如下,两个textbox,上面一个输拼音,下面一个会显示这个拼音对应的汉字,这一刻起我才发现中华汉字是那样的博大精深,一个读音居然有这么多的同音字: 完整的C#代码/Files/DreamlikeAttic/Pinyintest.rar如下,由于是示例,我并没有使用二分查分之类的方法优化,我只是简单将数据文件以字符串的方式读到内存,并使用indexof来确定拼音的位置后取得对应的文字。并且对数据文件也进行了处理,去掉了所有的词组,在debug中可以看到PYCompact.txt这个不再包含词组拼音的数据文件。其实得到了这个数据库,你要怎么玩拼音都可以,不会数据搜索技术就自己再学习一下大学的教科书吧! public partial class Form1 : Form { string m_strPinyinLib;//保存数据文件中所有的拼音及汉字 public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { StreamReader tobjTextReader; StreamWriter tobjTextWriter; BinaryWriter tobjBinaryWriter; FileStream tobjOutPutFile; string tstrItemValue; string tstrTemp; tobjTextReader = new StreamReader(@"winpy.txt", true); tobjOutPutFile = File.Open("PYCompact.txt", FileMode.Create); tobjBinaryWriter = new BinaryWriter(tobjOutPutFile); tobjTextWriter = new StreamWriter(tobjOutPutFile, Encoding.Unicode); tstrItemValue = tobjTextReader.ReadLine(); while (tstrItemValue != null) { //只保留单字不再要库中的词组 if (tstrItemValue.ToCharArray()[1] < 255) { //将拼音放在前面 tstrTemp = tstrItemValue.Substring(1) + tstrItemValue.Substring(0, 1); tobjTextWriter.WriteLine(tstrTemp); }//end if //tobjBinaryWriter.Write( tstrItemValue = tobjTextReader.ReadLine(); }//end while tobjTextWriter.Close(); tobjBinaryWriter.Close(); tobjOutPutFile.Close(); tobjTextReader.Close(); //将拼音库的内容读到一个字符串中待用 tobjTextReader = new StreamReader(@"PYCompact.txt", true); m_strPinyinLib = tobjTextReader.ReadToEnd(); tobjTextReader.Close(); } private void textBox1_TextChanged(object sender, EventArgs e) { string tstrChineseList = ""; if (textBox1.Text != "") tstrChineseList = findChinese(textBox1.Text); textBox2.Text = tstrChineseList; }//end sub string findChinese(string ni_strPinyin) { int tintFirstFind; string tstrReturn = ""; string tstrTemp = ""; int tintloop; tintFirstFind = m_strPinyinLib.IndexOf(ni_strPinyin); while (tintFirstFind >= 0) { for (tintloop = tintFirstFind; tintloop < m_strPinyinLib.Length - 1; tintloop++) { if ((tintFirstFind - 1) > 0) { if (m_strPinyinLib.Substring(tintFirstFind - 1, 1).ToCharArray()[0] < 255 && m_strPinyinLib.Substring(tintFirstFind - 1, 1).ToCharArray()[0] != ' ') { break; //由于找到的这个拼音前面还有英文字符且不为空格,说明这个拼音可是是u查找到gu这种情况,不予理会 }//end if }//end if if ((tintFirstFind + ni_strPinyin.Length) <( m_strPinyinLib.Length - 1)) { if (m_strPinyinLib.Substring(tintFirstFind + ni_strPinyin.Length, 1).ToCharArray()[0] < 255 && m_strPinyinLib.Substring(tintFirstFind + ni_strPinyin.Length, 1).ToCharArray()[0] != ' ') { break; //由于找到的这个拼音后面还有英文字符且不为空格,说明这个拼音可是是gu查找到guang这种情况,不予理会 }//end if }//endif tstrTemp = m_strPinyinLib.Substring(tintloop, 1); if (tstrTemp.ToCharArray()[0] > 255) { //找到对应的汉字,退出 break; }//end if }//next tstrReturn += tstrTemp; tintFirstFind = m_strPinyinLib.IndexOf(ni_strPinyin, tintloop + 1); }//end while return (tstrReturn); }//end function }//end class
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.