hoodlum1980(發發)的技术BLOG

——我急切希望寻找到两个朋友:唐义锁兄弟(杭州师范学院校卫),金娜姐姐(在宁波卖地板砖)。
posts - 39, comments - 35, trackbacks - 0, articles - 1

2008年5月10日

      BalloonTip通常出现在位于屏幕右下角的Tray(成为通知栏,或系统托盘)的Icon上,比如用户插拔USB设备时的气泡提示。该函数位于Shell32中,是通过调用下面这个API函数实现的, BOOL Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA lpdata ); 该函数用于控制对TrayIcon进行控制,可以弹出BalloonTip。然后却只能局限于Tray位置。而在QQ的聊天对话框中,我们发现如果不输入内容而试图发送消息时,就会在按钮上弹出这样的Tip。为此,我在C#中写了一个类似的窗口,可以在任意位置浮出,效果如下:
      

      这是测试程序的截图。在实现时,略微参考了codeproject上的仿MSN浮出窗口的代码。其涉及的主要麻烦是,为了提供足够灵活的接口,应该如何处理窗口上各个元素布局。为了简单期间,这里仅仅提供了“箭头”位于右下角的布局方式。(很显然该箭头一共可以有8个停靠位置)。
     (1)在弹出时,不夺走其他窗口焦点。为此使用了API的ShowWindow函数: ShowWindow(this.Handle, SW_SHOWNOACTIVATE);
     (2)窗体上一共包含4项主要内容:图标,标题,内容文本,关闭按钮。用户可以配置他们,例如选择图标(可以由外部设置或者使用内置图标),是否显示关闭按钮,是否自动关闭(如果把TimeoutMilliSeconds属性设为负数则不会自动关闭,只能通过CloseButton关闭),各种颜色,字体等。另提供一个BalloonClick事件,通知外部用户点击事件。
     (3)绘制CloseButton的位图时,由于图中具有透明色,因此需要在绘制时指定透明色,相当于蒙版的作用。否则透明色会被绘制到窗体上导致窗体透明那个。
     (4)弹出该窗口,主要使用ShowAt()函数。里面需要一些参数。如果需要进一步设置其他属性,可以单独进行设置。

       源代码的下载链接: 
       http://www.cnblogs.com/Files/hoodlum1980/JDL.UILib_BalloonTip_VS7.rar

posted @ 2008-05-10 19:46 hoodlum1980 阅读(10) | 评论 (0)编辑

2008年3月4日

         编译器提示:warning treated as error,然后某个文件未生成,build中断。
         这是因为项目选项中把warning级别设置为了较高的级别导致的,某些warning被当作error,从而不能生成。
         解决方法是在解决方案窗口中选中项目,右键点击project,选择“属性”,在弹出的对话框中,选择左侧TreeView中的“Configuration Properties”->“C/C++l”->“General”节点,在右侧有“Treat Warnings As Errors”(将警告当作错误对待)选项。我们把该项该为NO即可。即把相应命令行的"/WX"改为"/W"。
         相应的编译选项如下:(参考MSDN)
         /w    禁止所有警告 
         /Wn   指定显示的最高等级警告。有效等级是0~4。0级禁止所有警告。4级显示所有警告。
         /Wall 使能所有警告。
         /WX   视所有警告为错误。
         /wln  将某个指定警告视为某个级别。第一个参数是新的级别,第二个参数是警告号码。例如/w14326 使 C4326成为1级警告。
         /wdn  禁止某特定警告。n是警告号。例如, /wd4326 禁止C4326警告。
         /wen  将某个指定警告视为错误。n是警告号。例如, /we4326 把 C4326 视为错误。
         /won  某警告仅仅报告一次。例如:wo4326使C4326仅仅报告一次。

posted @ 2008-03-04 20:08 hoodlum1980 阅读(27) | 评论 (0)编辑

2008年3月3日

     摘要: 摘要: 最近有感于部分网友对高斯模糊滤镜的研究,本文将对高斯模糊中半径值的含义以及高斯模糊模板尺寸的疑惑做出总结和解答。  阅读全文

posted @ 2008-03-03 11:44 hoodlum1980 阅读(267) | 评论 (0)编辑

     摘要: 在上一篇文章中,我们介绍了开发Photoshop滤镜插件最基本的一些概念和基础。Ps为了满足插件的应用需求,同时也给插件提供了大量的回调函数(或服务)。例如,滤镜可以在一次调用后,保存最近一次用户设置的参数,并应用到下次调用或显示UI。这就是通过Ps的回调函数完成的。这一篇文章我们将讲解最重要的一些Ps回调函数。了解本文之后,我们将能够使用回调函数,完成例如存储我们的滤镜参数等必要的工作。本篇文章将比第一篇复杂和深入的多,但同时从这篇文章我们也可以一窥PS内部的秘密:缜密的系统设计,完善的接口以及复杂的工作机制。  阅读全文

posted @ 2008-03-03 00:43 hoodlum1980 阅读(80) | 评论 (1)编辑

2008年2月29日

     摘要: 在flyweight模式,指的是具有大量的轻量级对象,我们为这些对象建立一个实体对象,其他则为“虚像”或者称为对该实体的一种“引用”。在我从前的项目中,电力系统的矢量图中,有大量设备,同种类型设备采用一种符号绘制,称为图元。这里就属于一中flyweight模式应用。......  阅读全文

posted @ 2008-02-29 00:02 hoodlum1980 阅读(53) | 评论 (0)编辑

2008年2月28日

     摘要: Photoshop是数字图像处理的杰出软件。他允许第三方以插件形式扩展功能。本文讲解用户最为熟悉的Photoshop滤镜插件的开发,以一个水滴效果滤镜为实例,主要介绍滤镜插件的开发流程,讨论了一些比较重要的相关技术细节问题。  阅读全文

posted @ 2008-02-28 17:17 hoodlum1980 阅读(1826) | 评论 (7)编辑

      题目链接:http://acm.zju.edu.cn/show_problem.php?pid=1146
      这是一道用于把数字显示成LCD样子的题目,输入每一行有两个整数,第一个整数n表示笔画大小,第二个是需要显示成LCD样子的数字。这道题没有什么太难的,但是却让我在输出格式上卡住了,始终是Presentation Error,让我百思不得其解。后来我才发现原来是因为题目叙述的不够精确,使我没有准确理解输出格式的要求,导致我每一行都多输出了一个结尾空格。找到问题后,当然立刻就AC了。代码也不具备什么含量。
      由于没有什么难度的地方,并且我也加了一点点注释,所以就没什么可做更多叙述的了。这只是一道比较简单的题目,但是输出格式一定要正确理解。
ZOL 1146 CODE

 /*--------------------------------------------------
打印后正确的输出格式应该类似下面这样:(@表示行尾)
 -       -   -       - @
| |   |   |   | | | |  @
         -   -   -   - @
| |   | |     |   |   |@
 -       -   -       - @
----------------------------------------------------
*/

posted @ 2008-02-28 04:43 hoodlum1980 阅读(46) | 评论 (0)编辑

2008年2月26日

这道题目:http://acm.zju.edu.cn/show_problem.php?pid=1113 的大意如下:根据公式
e=1/0!+1/1!+1/2!+1/3!+...+1/n!
计算e。要求输出需要的小数位数(9位)。
题目很直观,最直观的想法可能是一个计算n!的函数,然后一个从0到n的循环,累加所有的小数。不过这样做显然会有很多冗余计算。为了避免这种情况,显然,
假设a[n]表示1/n!,e[n]表示e,则
a[n+1]=a[n]/(n+1);
e[n+1]=e[n]+a[n+1];
根据这个等式,我们可以写出解答方法。由于题目中要求小数精度,也许随着计算机位数的增长,double能够满足精度。但是在16位的TC下似乎是无法满足的,所以考虑用大数方法处理小数。即使用一个数组a[]表示小数部分。(这里假设小数具有0.********的形式),按照这个处理方法的惯例,我们规定,
a[0]表示小数的数据位数,a[i] (i>0)中存放第i位小数的数字。例如PI 3.1415926,它的小数部分可以用下面的数组表示:
{7,1,4,1,5,9,2,6,0,0,0,........};
那么这个小数就可以表示成
      a[1]*10^(-1)+a[2]*10^(-2)+...+a[n]*10^(-n)
由于
      a * 10^(-i) + (10*b + c) * 10^(-(i+1)) = (a+b) * 10^(-i) + c * 10 ^(-(i+1))
所以,相邻位之间以此规则进位或者退位以及规整。
根据上面的迭代式子,我们看到至少两种小数运算,一个是小数除以整数,一个是两个小数相加。在这个题目中实际上精度不高,因此对代码执行效率的要求可以降低,但是为了通用,我还是保持该算法的惯用风格。
下面,给出一个小数除以一个整数的代码,由于一个已经规整过的小数这样运算的时候,不可能出现大于10的结果,所以这时我们无需对结果进行规整处理。
一个小数除以一个整数
由于结果需要四舍五入,所以实际上我给出了一些冗余位,以保持四舍五入时候的结果正确。
下面是两个小数相加的运算代码,即a=a+b,结果是a被改变为两者的和,b不发生变化。在a的基础上改动,可以使我们节省空间。相对而言,大数相加减的代码是最为简单直观的。
两个小数相加
注意,两个小数相加以后,可能产生结果在某些位大于10,因此这时需要一次规整运算。
最后,我们还需要对数组进行一次扫描,输出四舍五入后的结果:由于我们的目的是计算e,因此整数部分是确定的“2.”。
输出四舍五入后的结果值
最后我们给出迭代部分的代码,由于使用迭代式,因此下一步的计算建立在前一步的计算结果的基础上,这样就避免了冗余计算。
迭代E的结果

当我们想要输出80位小数时,结果如下(显然可以直接运算的内部数据类型是无法达到这样精度的):
2.71828182845904523536028747135266249775724709369995957496696762772407663035354759

posted @ 2008-02-26 23:43 hoodlum1980 阅读(45) | 评论 (0)编辑

2008年2月25日

首先我们来看一下这个问题的提出,来自于一个网友的提问:
http://bbs.bccn.net/thread-200774-1-1.html
----------------------------------------------------------------------------------------------------------

求教大家,简单问题,但为什么是这样的结果?(vc6.0)

很简单的程序
void main()
{
     int i=8;
     printf("%d,%d,%d,%d\n", ++i, --i, i++, i--);
}
但是结果为(8 7 8 8)无论是从左到右顺序求值还是从右到左顺序求值都不应该是这个结果吧?
我觉得从左到右应该是(9 8 8 9 )从右到左是(8 7 7 8),
是我的错还是编译器的原因?如果是从右到左顺序求值,为什么结果不是(8 7 7 8)而是(8 7 8 8)
请大家指点一下!
[ 本帖最后由 默默无纹 于 2008-2-24 21:04 编辑 ]
-----------------------------------------------------------------------------------------------------------
在这里我使用了VS.NET2005编译的结果是:8,8,7,8
用TC2.0编译的结果是:8,7,7,8
VC6.0我没有安装,所以没有试过,也没办法分析。
这里我们可以看到,由不同的编译器产生了不同结果,可见这个问题是依赖编译器的理解和实现的。换句话说,对于i++和++i的处理本来就是非常具有歧义的,当然在自己应用中我相信也不会有任何程序员写出这样歧义的代码。但是作为一个问题,我们有必要分析一下不同编译器究竟如何理解i++和++i操作符的。
      我们在学习C的时候,应该已经大概知道了i++和++i两者的区别,即“++”符号在i之前还是之后,决定了i自增操作和他的语句的执行顺序的关系。即i++,理解为i在其语句中取原始值,++i在其语句中取自增后的新值。这一点是毫无疑义的。但是问题在于,网友的问题中又涉及到了i++,++i在作为参数时候的处理,所以这时候我们就会感到困惑,i++和++i在作为参数的时候,和进入堆栈的顺序之间有何关系呢?根据前面的实验,可见TC2.0和VS.net2005的处理不同,可见两者对其处理不同,那么造成这种不同的结果的原因是什么呢?我们从代码上无法看到差异,因此我们必须看汇编语言才能知晓,编译器到底把我们的代码翻译成了什么墨阳。下面我采用IDA反汇编编译器把生成的.exe文件:由于程序很小,所以我们很容易找到相应的汇编代码(TC2.0的程序中有很多中断的相关代码,更加难以找到),结果如下:
VS.NET 2005的代码

可见,++i和--i执行的时候直接改变了i的值,而i++和i--必须在所在的这个语句执行后才能改变i的值,所以i++作为参数时,实际上是这样的过程,
       printf("%d",i++);
相当于下面的语句:
       int temp=i;
       i=(i+1);
       printf("%d",temp);

因此上面的代码可以翻译为:
      int i=8;
      printf("%d,%d,%d,%d",++i,--i,i++,i--);

因此可以翻译为下面的等效代码:
i=8;
temp0=i; //temp0=8;
i--;     //7
temp1=i; //temp1=7
i++;     //8
--i;     //7
++i;     //i=8
printf("%d,%d,%d,%d",i,i,temp1,temp0);   
所以打印结果是8,8,7,8

---------------------------------------------------------------------------------------------------------
我们再看在TC2.0下的反汇编代码:
TC2.0下面的反汇编代码

可见,上面的行为可以翻译为下面的等效代码(TC2.0):
i=8;
temp0=i;        //这时8已经入栈,实际上通过ax寄存器直接压栈里了~~~,不存在temp0)
i--;                //i=7
temp1=i;        //这时7已经入栈,实际上通过ax寄存器直接压栈里了~~~,不存在temp1)
i++;               //i=8
--i;                 //i=7     
temp2=i;        //7已经入栈
++i;               //i=8
temp3=i;        //8已经入栈
printf("%d,%d,%d,%d",temp3,temp2,temp1,temp0);

输出结果是:8,7,7,8

----------------------------------------------------------------------------------------------------------------------
下面我们将总结和分析两种编译器的处理之间有何不同:@@@@@@

请注意两者的区别主要是,他们是一边处理自增自减并一边随时入栈,还是先处理完所有自增自减之后再最后统一一次性的入栈。
(1)在TC下面属于前者,每执行一个语句,就把i通过ax寄存器马上入栈了,所以参数入栈和i++等语句是交叉交替性进行的。这里的i++和++i的主要区别在于压栈是在i自增之前还是之后。
i++相当于:先入栈,再自增。
++i相当于,先自增,再入栈。
所以我们看到下面的参数:从右到左:
i--: 入栈8,i=7
i++:入栈7,i=8
--i:i=7,入栈7
++i:i=8,入栈8
所以导致栈里面的参数是8,7,7,8,所以打印结果是8,7,7,8.

(2)在上面的VC.net2005中属于后者,是先为i++和i--保存值,然后执行完所有的自增和自减,最后一次性的把所有参数入栈。在这里i++和++i的区别
主要是是否把i的值保存到另一个位置:而且最大不同点在于这里不马上入栈,而是等所有参数处理后统一入栈。
i++:先缓存i的原始值,然后i自增。最后入栈时,用i的原始值入栈。
++i:i自增,不缓存i的原始值。最后入栈时,是更新后的i。
所以我们看到在VC2005.NET中的顺序是:
i--: 缓存8,i=7
i++:缓存7,i=8
--i:i=7
++i:i=8
参数一次性依次入栈:第一个缓存值8,第二个缓存值7,i的当前值8,i的当前值8。
所以这时候栈的数据是:8,8,7,8.(从左到右)。
所以打印结果是:8,8,7,8.




posted @ 2008-02-25 06:18 hoodlum1980 阅读(49) | 评论 (0)编辑

     摘要:

本文回顾讲述了在DOS下显示汉字的技术。在TC2.0下的图形模式,实现从汉字库中读取字模,并绘制汉字的过程,以及如何在字库文件中定位的问题。

  阅读全文

posted @ 2008-02-25 00:31 hoodlum1980 阅读(131) | 评论 (0)编辑