﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-天堂的另一角-随笔分类-软件开发</title><link>http://www.cnitblog.com/addone/category/2162.html</link><description>天堂魷魚的原创技术博客。所謂兼容並包，無奇不有。</description><language>zh-cn</language><lastBuildDate>Mon, 20 Feb 2012 08:53:29 GMT</lastBuildDate><pubDate>Mon, 20 Feb 2012 08:53:29 GMT</pubDate><ttl>60</ttl><item><title>Python 2.x中使用字符串的format()方法的注意事项</title><link>http://www.cnitblog.com/addone/archive/2011/10/18/76104.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Tue, 18 Oct 2011 12:23:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2011/10/18/76104.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/76104.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2011/10/18/76104.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/76104.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/76104.html</trackback:ping><description><![CDATA[<p>Python 3中，字符串的格式化将会采用新的format()方法，以替代现行的C风格的%（百分号）操作符。例如：</p><blockquote><p>"表达式 %s 的计算结果是: %d" % ("1 + 1", 2)</p></blockquote><p>在Python 3中应写为：</p><blockquote><p>"表达式 {} 的计算结果是: {:d}".format("1 + 1", 2)</p></blockquote><p>为了实现Python 2到Python 3的平滑过渡，在Python 2.6以后的版本中，也为字符串提供了该方法并鼓励大家使用，以代替惯用的%操作符。</p><p>问题是，如果你的程序需要处理非ASCII码字符，例如中文、日文、韩文的话，那么你在使用format()方法时将会被提示以下错误：</p><blockquote><p>UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-9: ordinal not in range(128)</p></blockquote><p>原因是在Python 2.x中，字符串的默认编码是ascii码，无法直接处理中文等超出ascii码范围的文字。</p><p>解决方法是，在python的安装目录中找到sitecustomize.py文件，通常是在site-packages目录下，如果没有就自己建一个。我的python 2.7在mac下该文件的路径为</p><blockquote><p>/Library/Python/2.7/site-packages/</p></blockquote><p>然后确保文件中包含以下内容：</p><blockquote><p>import sys</p><p>sys.setdefaultencoding('utf-8')</p></blockquote><p>这样在运行程序时就可以正确处理Unicode字符串的format()方法了。但是如果程序需要部署到客户端上，那么就很难保证每台机器上都按以上方法设置了。这样该怎么办呢？</p><p>注意，<span style="color: #ff0000;">直接在程序里是无法调用setdefaultencoding()方法的</span>，因为该方法在python启动后就会被自动删除掉。如果实在需要调用的话，可以使用以下方法：</p><blockquote><p>import sys</p><p>reload(sys)</p><p>sys.setdefaultendoding('utf-8')</p></blockquote><p>即可。</p><p>&nbsp;</p><p>有不少人因此而觉得format()方法不如%操作符，其实大可不必。在Python 3中，所有的字符串将完全使用unicode编码，这个问题也就将不复存在了。以上的方法只是权宜之计，仅适用于那些喜欢尝鲜，或希望将来代码能够顺利移植到Python 3上的人。</p><p>希望这里的解答能够有所帮助。</p><img src ="http://www.cnitblog.com/addone/aggbug/76104.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2011-10-18 20:23 <a href="http://www.cnitblog.com/addone/archive/2011/10/18/76104.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>中國農曆計算的javascript實現方法</title><link>http://www.cnitblog.com/addone/archive/2009/12/30/63461.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Wed, 30 Dec 2009 03:46:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2009/12/30/63461.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/63461.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2009/12/30/63461.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/63461.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/63461.html</trackback:ping><description><![CDATA[<p>中國農曆很有意思，因為它並不是如英文名所表達的那種純月亮曆，而是結合了月曆和太陽曆（公曆）的一種曆法，實際上是一種日月混合曆，因此計算方法非常複雜。而更麻煩的是，幾乎所有的主流編程語言和函數庫中都沒有提供農曆的實現。因此，程序中需要計算農曆時，就很容易遇到各種各樣的問題。近期為了寫一個個人web日記系統，不得已學習了一番，並將研究結果發佈在此，以供討論和參考。<br /><br />當前比較廣泛應用的是一段javascript實現（參考<a href="http://jck11.pixnet.net/blog/post/3459317" target="_blank">這裡</a>），功能比較強大，支持閏月、節氣、公曆節日、農曆節日等。這段代碼的原始來源已不可考，不過大致可以判斷其最初應該是自台灣流出。估計當前網上的萬年曆系統應該有90%能夠找到其蹤影，其應用的廣泛程度可見一斑。但是，今年曾經有過立春日期的爭論，其罪魁禍首也正是這段代碼。根據這段代碼，2009年的立春是2月3日，而實際的天文觀測數據表明應該是2月4日。許多萬年曆由於使用了這套系統，導致出現了大量的不一致，並引起了人們的關注。由於實際時間只差不到1小時（2009年立春開始於2月4日凌晨0點40分左右），官方把這一問題解釋為「時差」。事實上，這是因為該代碼的節氣算法誤差過大造成的。<br /><br />所有的曆法都需要天文觀測數據加以校正，但農曆對天文數據的依賴遠比公曆（即格里高里曆）大。因此，任何農曆計算程序都需要若干數據表才有可能完成計算，代碼非常繁雜。<br /><br />首先是年基礎數據表，形式通常如下：<br /><br /></p><div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;lunarInfo</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Array(<br /></span><span style="color: #000000;">0x04bd8</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04ae0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a570</span><span style="color: #000000;">,</span><span style="color: #000000;">0x054d5</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d260</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0d950</span><span style="color: #000000;">,</span><span style="color: #000000;">0x16554</span><span style="color: #000000;">,</span><span style="color: #000000;">0x056a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x09ad0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x055d2</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x04ae0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a5b6</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a4d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d250</span><span style="color: #000000;">,</span><span style="color: #000000;">0x1d255</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0b540</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d6a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ada2</span><span style="color: #000000;">,</span><span style="color: #000000;">0x095b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x14977</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x04970</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a4b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0b4b5</span><span style="color: #000000;">,</span><span style="color: #000000;">0x06a50</span><span style="color: #000000;">,</span><span style="color: #000000;">0x06d40</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x1ab54</span><span style="color: #000000;">,</span><span style="color: #000000;">0x02b60</span><span style="color: #000000;">,</span><span style="color: #000000;">0x09570</span><span style="color: #000000;">,</span><span style="color: #000000;">0x052f2</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04970</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x06566</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d4a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ea50</span><span style="color: #000000;">,</span><span style="color: #000000;">0x06e95</span><span style="color: #000000;">,</span><span style="color: #000000;">0x05ad0</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x02b60</span><span style="color: #000000;">,</span><span style="color: #000000;">0x186e3</span><span style="color: #000000;">,</span><span style="color: #000000;">0x092e0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x1c8d7</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0c950</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0d4a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x1d8a6</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0b550</span><span style="color: #000000;">,</span><span style="color: #000000;">0x056a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x1a5b4</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x025d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x092d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d2b2</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a950</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0b557</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x06ca0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0b550</span><span style="color: #000000;">,</span><span style="color: #000000;">0x15355</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04da0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a5d0</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x14573</span><span style="color: #000000;">,</span><span style="color: #000000;">0x052d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a9a8</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0e950</span><span style="color: #000000;">,</span><span style="color: #000000;">0x06aa0</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0aea6</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ab50</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04b60</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0aae4</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a570</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x05260</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0f263</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d950</span><span style="color: #000000;">,</span><span style="color: #000000;">0x05b57</span><span style="color: #000000;">,</span><span style="color: #000000;">0x056a0</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x096d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04dd5</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04ad0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a4d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d4d4</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0d250</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d558</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0b540</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0b5a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x195a6</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x095b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x049b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a974</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a4b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0b27a</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x06a50</span><span style="color: #000000;">,</span><span style="color: #000000;">0x06d40</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0af46</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ab60</span><span style="color: #000000;">,</span><span style="color: #000000;">0x09570</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x04af5</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04970</span><span style="color: #000000;">,</span><span style="color: #000000;">0x064b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x074a3</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ea50</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x06b58</span><span style="color: #000000;">,</span><span style="color: #000000;">0x055c0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ab60</span><span style="color: #000000;">,</span><span style="color: #000000;">0x096d5</span><span style="color: #000000;">,</span><span style="color: #000000;">0x092e0</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0c960</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d954</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d4a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0da50</span><span style="color: #000000;">,</span><span style="color: #000000;">0x07552</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x056a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0abb7</span><span style="color: #000000;">,</span><span style="color: #000000;">0x025d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x092d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0cab5</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0a950</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0b4a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0baa4</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ad50</span><span style="color: #000000;">,</span><span style="color: #000000;">0x055d9</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x04ba0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a5b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x15176</span><span style="color: #000000;">,</span><span style="color: #000000;">0x052b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a930</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x07954</span><span style="color: #000000;">,</span><span style="color: #000000;">0x06aa0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ad50</span><span style="color: #000000;">,</span><span style="color: #000000;">0x05b52</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04b60</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0a6e6</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a4e0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d260</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ea65</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d530</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x05aa0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x076a3</span><span style="color: #000000;">,</span><span style="color: #000000;">0x096d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04bd7</span><span style="color: #000000;">,</span><span style="color: #000000;">0x04ad0</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0a4d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x1d0b6</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d250</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0d520</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0dd45</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0b5a0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x056d0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x055b2</span><span style="color: #000000;">,</span><span style="color: #000000;">0x049b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0a577</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">0x0a4b0</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0aa50</span><span style="color: #000000;">,</span><span style="color: #000000;">0x1b255</span><span style="color: #000000;">,</span><span style="color: #000000;">0x06d20</span><span style="color: #000000;">,</span><span style="color: #000000;">0x0ada0</span><span style="color: #000000;">);</span></div><p><br />這實際上是一份農曆月份信息表，表格里的每個元素都是一個長度為20的二進制數組（用一個5位16進制數字表示）。詳細信息可以參考<a title="這裡" href="http://blog.csdn.net/sYwb/archive/2005/04/05/337172.aspx" target="_blank">這裡</a>的說明（當然，那篇文章存在不少問題）。幾乎所有的農曆計算程序都會用到這個表，不同的只是形式和範圍。這裡附上的表格包含了從公元1900年到2049年的信息。超出這個範圍的年份自然是無法計算的。<br /><br />日期計算的代碼比較通用，如下所示：<br /><br /></p><div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000;">//</span><span style="color: #008000;">======================================&nbsp;傳回農曆&nbsp;y年的總天數</span><span style="color: #008000;"><br /></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;lYearDays(y)&nbsp;{<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;i,&nbsp;sum&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">348</span><span style="color: #000000;"><br />&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">0x8000</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">0x8</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">&gt;&gt;=</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;sum&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;(lunarInfo[y</span><span style="color: #000000;">-</span><span style="color: #000000;">1900</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;i)</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">:&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;"><br />&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">(sum</span><span style="color: #000000;">+</span><span style="color: #000000;">leapDays(y))<br />}<br /><br /></span><span style="color: #008000;">//</span><span style="color: #008000;">======================================&nbsp;傳回農曆&nbsp;y年閏月的天數</span><span style="color: #008000;"><br /></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;leapDays(y)&nbsp;{<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(leapMonth(y))&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">((lunarInfo[y</span><span style="color: #000000;">-</span><span style="color: #000000;">1900</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0x10000</span><span style="color: #000000;">)</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">30</span><span style="color: #000000;">:&nbsp;</span><span style="color: #000000;">29</span><span style="color: #000000;">)<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">(</span><span style="color: #000000;">0</span><span style="color: #000000;">)<br />}<br /><br /></span><span style="color: #008000;">//</span><span style="color: #008000;">======================================&nbsp;傳回農曆&nbsp;y年閏哪個月&nbsp;1-12&nbsp;,&nbsp;沒閏傳回&nbsp;0</span><span style="color: #008000;"><br /></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;leapMonth(y)&nbsp;{<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">(lunarInfo[y</span><span style="color: #000000;">-</span><span style="color: #000000;">1900</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0xf</span><span style="color: #000000;">)<br />}<br /><br /></span><span style="color: #008000;">//</span><span style="color: #008000;">======================================&nbsp;傳回農曆&nbsp;y年m月的總天數</span><span style="color: #008000;"><br /></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;monthDays(y,m)&nbsp;{<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">(&nbsp;(lunarInfo[y</span><span style="color: #000000;">-</span><span style="color: #000000;">1900</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">0x10000</span><span style="color: #000000;">&gt;&gt;</span><span style="color: #000000;">m))</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">30</span><span style="color: #000000;">:&nbsp;</span><span style="color: #000000;">29</span><span style="color: #000000;">&nbsp;)<br />}<br /><br /></span><span style="color: #008000;">//</span><span style="color: #008000;">======================================&nbsp;算出農曆,&nbsp;傳入日期物件,&nbsp;傳回農曆日期物件</span><span style="color: #008000;"><br />//</span><span style="color: #008000;">&nbsp;該物件屬性有&nbsp;.year&nbsp;.month&nbsp;.day&nbsp;.isLeap&nbsp;.yearCyl&nbsp;.dayCyl&nbsp;.monCyl</span><span style="color: #008000;"><br /></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;Lunar(objDate)&nbsp;{<br /><br />&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;i,&nbsp;leap</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;temp</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;"><br />&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;baseDate&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Date(</span><span style="color: #000000;">1900</span><span style="color: #000000;">,</span><span style="color: #000000;">0</span><span style="color: #000000;">,</span><span style="color: #000000;">31</span><span style="color: #000000;">)<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;offset&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(objDate&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;baseDate)</span><span style="color: #000000;">/</span><span style="color: #000000;">86400000</span><span style="color: #000000;"><br />&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.dayCyl&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;offset&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">40</span><span style="color: #000000;"><br />&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.monCyl&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">14</span><span style="color: #000000;"><br />&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">1900</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">2050</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;offset</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;temp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;lYearDays(i)<br />&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;</span><span style="color: #000000;">-=</span><span style="color: #000000;">&nbsp;temp<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.monCyl&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">12</span><span style="color: #000000;"><br />&nbsp;&nbsp;}<br />&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(offset</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">0</span><span style="color: #000000;">)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;temp;<br />&nbsp;&nbsp;&nbsp;&nbsp;i</span><span style="color: #000000;">--</span><span style="color: #000000;">;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.monCyl&nbsp;</span><span style="color: #000000;">-=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">12</span><span style="color: #000000;"><br />&nbsp;&nbsp;}<br />&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.year&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;i<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.yearCyl&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">-</span><span style="color: #000000;">1864</span><span style="color: #000000;"><br />&nbsp;<br />&nbsp;&nbsp;leap&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;leapMonth(i)&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">閏哪個月</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.isLeap&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;"><br />&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">13</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;offset</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br />&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">閏月</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(leap</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">==</span><span style="color: #000000;">(leap</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.isLeap</span><span style="color: #000000;">==</span><span style="color: #0000ff;">false</span><span style="color: #000000;">)<br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;</span><span style="color: #000000;">--</span><span style="color: #000000;">i;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.isLeap&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;&nbsp;temp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;leapDays(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.year);&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;temp&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;monthDays(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.year,&nbsp;i);&nbsp;}<br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">解除閏月</span><span style="color: #008000;"><br /></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.isLeap</span><span style="color: #000000;">==</span><span style="color: #0000ff;">true</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">==</span><span style="color: #000000;">(leap</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">))&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.isLeap&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;"><br />&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;offset&nbsp;</span><span style="color: #000000;">-=</span><span style="color: #000000;">&nbsp;temp<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.isLeap&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">)&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.monCyl&nbsp;</span><span style="color: #000000;">++</span><span style="color: #000000;"><br />&nbsp;&nbsp;}<br />&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(offset</span><span style="color: #000000;">==</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;leap</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">0</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">==</span><span style="color: #000000;">leap</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.isLeap)<br />&nbsp;&nbsp;{&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.isLeap&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;&nbsp;}<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br />&nbsp;&nbsp;{&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.isLeap&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;&nbsp;</span><span style="color: #000000;">--</span><span style="color: #000000;">i;&nbsp;</span><span style="color: #000000;">--</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.monCyl;}<br />&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(offset</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">0</span><span style="color: #000000;">){&nbsp;offset&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;temp;&nbsp;</span><span style="color: #000000;">--</span><span style="color: #000000;">i;&nbsp;</span><span style="color: #000000;">--</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.monCyl;&nbsp;}<br />&nbsp;<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.month&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;i<br />&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.day&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;offset&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;"><br />}</span></div><p><br />關於這部份的計算比較好懂，也被大多人認同，我就不多解釋了。按中國的習慣，月份需要用一個字表示（如「臘月」），日期則統一按兩個漢字表示（如「初五」），調用時還需要稍微調整。<span style="color: #ff0000;">調用代碼如下所示</span>：<br /><br /></p><div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;numString</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">十一二三四五六七八九十</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;lMString</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">正二三四五六七八九十冬臘</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br /><br /></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;getLunarDateStr(date){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;tY&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;date.getFullYear();<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;tM&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;date.getMonth();<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;tD&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;date.getDate();<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;l&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Lunar(date);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;lM&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;l.month.toFixed(</span><span style="color: #000000;">0</span><span style="color: #000000;">);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;pre&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(l.isLeap)&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;'閏'&nbsp;:&nbsp;'';<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;mStr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pre&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;lMString[lM</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">]&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;'月';<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;lD&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;l.day.toFixed(</span><span style="color: #000000;">0</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br />&nbsp;&nbsp;&nbsp;&nbsp;pre&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(lD&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;'初'&nbsp;:&nbsp;((lD&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">19</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;'十'&nbsp;:&nbsp;((lD&nbsp;</span><span style="color: #000000;">&lt;=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">29</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;'廿'&nbsp;:&nbsp;'三'));<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;dStr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pre&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;numString[lD&nbsp;</span><span style="color: #000000;">%</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">];<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;mStr&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;dStr;<br />}</span></div><p><br />接著就是重頭戲&#9472;&#9472;節氣了！！在原來的代碼中，已經是可以計算節氣了。由於節氣計算非常複雜，代碼只提供了一個函數，形式如function sTerm(year, n)，用來計算某年的第n個節氣（從0小寒算起）為幾號，這也基本被認可為節氣計算的基本形式。由於每個月份有兩個節氣，計算時需要調用兩次（n和n+1），調用代碼如下：<br /><br /></p><div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;solarTerm&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Array(</span><span style="color: #000000;">"</span><span style="color: #000000;">小寒</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">大寒</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">立春</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">雨水</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">驚蟄</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">春分</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">清明</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">"</span><span style="color: #000000;">谷雨</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">立夏</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">小滿</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">芒種</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">夏至</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">小暑</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">大暑</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">立秋</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">處暑</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">白露</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">秋分</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br /></span><span style="color: #000000;">"</span><span style="color: #000000;">寒露</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">霜降</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">立冬</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">小雪</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">大雪</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">"</span><span style="color: #000000;">冬至</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br /><br /></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;termStr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(tD&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;sTerm(tY,&nbsp;tM</span><span style="color: #000000;">*</span><span style="color: #000000;">2</span><span style="color: #000000;">))&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;solarTerm[tM</span><span style="color: #000000;">*</span><span style="color: #000000;">2</span><span style="color: #000000;">]&nbsp;:&nbsp;((tD&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;sTerm(tY,&nbsp;tM</span><span style="color: #000000;">*</span><span style="color: #000000;">2</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">))&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;solarTerm[tM</span><span style="color: #000000;">*</span><span style="color: #000000;">2</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">]&nbsp;:&nbsp;'');</span></div><p><br />然而，造成2009年立春計算問題的關鍵也就在這裡。原代碼的sTerm()實現存在一定誤差，雖然大多數時候沒有問題，但因為2009年立春正好出現在凌晨0時，這個誤差就導致了日期被錯算成2月3日。（其實也就若干小時，完全是可容許範圍的說。。。）更精確的算法需要引入另外的數據表格，這一工作主要來自台灣林洵賢先生的「農曆月曆&amp;世界時間 DHTML 程式」。相關代碼（引自<a href="http://www.ideographer.com/ideocal" target="_blank">IdeoCal</a>）如下所示：<br /><br /></p><div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;solarTermBase&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Array(</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">19</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">18</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">19</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">19</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">20</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">20</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">,</span><span style="color: #000000;">22</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">,</span><span style="color: #000000;">22</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">,</span><span style="color: #000000;">22</span><span style="color: #000000;">,</span><span style="color: #000000;">7</span><span style="color: #000000;">,</span><span style="color: #000000;">22</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">,</span><span style="color: #000000;">21</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">,</span><span style="color: #000000;">21</span><span style="color: #000000;">);<br /></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;solarTermIdx&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'</span><span style="color: #000000;">0123415341536789</span><span style="color: #000000;">:;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">9</span><span style="color: #000000;">:</span><span style="color: #000000;">=&lt;&gt;</span><span style="color: #000000;">:</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">&gt;?</span><span style="color: #000000;">012</span><span style="color: #000000;">@</span><span style="color: #000000;">015</span><span style="color: #000000;">@</span><span style="color: #000000;">015</span><span style="color: #000000;">@015AB78CDE8CD</span><span style="color: #000000;">=</span><span style="color: #000000;">1FD01GH01GH01IH01IJ0KLMN;LMBEOPDQRST0RUH0RVH0RWH0RWM0XYMNZ[MB\\]PT</span><span style="color: #000000;">^</span><span style="color: #000000;">_ST`_WH`_WH`_WM`_WM`aYMbc[Mde]Sfe]gfh_gih_Wih_WjhaWjka[jkl[jmn]ope]qph_qrh_sth_W';<br /></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;solarTermOS&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'</span><span style="color: #000000;">211122112122112121222211221122122222212222222221222122222232222222222222222233223232223232222222322222112122112121222211222122222222222222222222322222112122112121222111211122122222212221222221221122122222222222222222222223222232222232222222222222112122112121122111211122122122212221222221221122122222222222222221211122112122212221222211222122222232222232222222222222112122112121111111222222112121112121111111222222111121112121111111211122112122112121122111222212111121111121111111111122112122112121122111211122112122212221222221222211111121111121111111222111111121111111111111111122112121112121111111222111111111111111111111111122111121112121111111221122122222212221222221222111011111111111111111111122111121111121111111211122112122112121122211221111011111101111111111111112111121111121111111211122112122112221222211221111011111101111111110111111111121111111111111111122112121112121122111111011111121111111111111111011111111112111111111111011111111111111111111221111011111101110111110111011011111111111111111221111011011101110111110111011011111101111111111211111001011101110111110110011011111101111111111211111001011001010111110110011011111101111111110211111001011001010111100110011011011101110111110211111001011001010011100110011001011101110111110211111001010001010011000100011001011001010111110111111001010001010011000111111111111111111111111100011001011001010111100111111001010001010000000111111000010000010000000100011001011001010011100110011001011001110111110100011001010001010011000110011001011001010111110111100000010000000000000000011001010001010011000111100000000000000000000000011001010001010000000111000000000000000000000000011001010000010000000</span><span style="color: #000000;">';<br /><br /></span><span style="color: #008000;">//</span><span style="color: #008000;">=====&nbsp;某年的第n個節氣為幾日(從0小寒起算)</span><span style="color: #008000;"><br /></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;sTerm(y,n)&nbsp;{<br />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">(solarTermBase[n]&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;&nbsp;Math.floor(&nbsp;solarTermOS.charAt(&nbsp;(&nbsp;Math.floor(solarTermIdx.charCodeAt(y</span><span style="color: #000000;">-</span><span style="color: #000000;">1900</span><span style="color: #000000;">))&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">48</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">24</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;n&nbsp;&nbsp;)&nbsp;)&nbsp;);<br />}</span></div><p><br />這種方法大幅提昇了節氣計算的準確程度，也解決了2009年立春的問題。不過實話實說，這段代碼我是完全沒看懂的。數學白痴，殘念。。。<br /><br />最後，感謝那些研究出這套算法的人們，沒有他們的工作，我們在電腦上使用農曆（哪怕是不準確的）將非常麻煩。另外，再次感慨一下，希望我國的天文台能盡一下本分，拿出一個標準的農曆計算方案來。也希望我們的農曆能夠早日進入主流語言函數庫。</p><img src ="http://www.cnitblog.com/addone/aggbug/63461.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2009-12-30 11:46 <a href="http://www.cnitblog.com/addone/archive/2009/12/30/63461.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>淡出Linux  兼談三大主流系統的交互介面比較</title><link>http://www.cnitblog.com/addone/archive/2009/11/19/62670.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Wed, 18 Nov 2009 21:11:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2009/11/19/62670.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/62670.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2009/11/19/62670.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/62670.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/62670.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 我相信見過Mac系統的每個人都曾經為之驚歎：漂亮，優雅，舒適。無論市場地位如何變化無常，蘋果的系統總是站在時代的最先端。不但是最早引入了鼠標和被稱為WIMP的圖形界面的系統，也是最早引入完整的人機交互理念的系統。作為桌面操作系統領域的領軍者，蘋果系統是公認的“人性化”、“美觀”的代表。就連微軟賴以成名的Windows操作系統，也不得不依靠模仿蘋果系統的界面來取得桌面系統領域的一席之地及至後來居上。問題是，為何在界面的眩目程度絲毫不落下風的Linux系統並沒有獲得桌面用戶的青睞？&nbsp;&nbsp;<a href='http://www.cnitblog.com/addone/archive/2009/11/19/62670.html'>阅读全文</a><img src ="http://www.cnitblog.com/addone/aggbug/62670.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2009-11-19 05:11 <a href="http://www.cnitblog.com/addone/archive/2009/11/19/62670.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java中無恥的範型實現</title><link>http://www.cnitblog.com/addone/archive/2009/08/30/61104.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Sun, 30 Aug 2009 01:20:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2009/08/30/61104.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/61104.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2009/08/30/61104.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/61104.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/61104.html</trackback:ping><description><![CDATA[一直聽說Java中的範型實現得很糟糕，但自己雖然一直用，卻也沒覺得有何問題，感覺比起遍地氾濫的Object來說，還是要優雅多了。然而，這不過是錯覺罷了。<br><br>Anders hejlsberg 解釋過這一現象: <span style="font-style: italic; color: red;">Java的泛型最初是基於Martin Odersky和其它人一起做的稱作Pizza的一個項目的。Pizza後改名為GJ，然後成為JSR，最後以被Java語言收容而告終。這種泛型以能夠 在原有的VM（Virtual Machine，虛擬機）上運行為關鍵設計目標。也就是說，你不必修改你的VM，但它會帶來很多限制。這些限制並不會很快出現，但很快你就會說：「嗯，這 有點陌生。」</span><br><br>對於我來說，事情的起因是前陣子需要寫一個循環隊列充當Buffer用，空間是有限的，但可以無限次的循環再利用。要求資源佔用要小，性能要好。該隊列一開始就要將空間中的所有元素都初始化，所以類似刪除、空隊列判斷、隊列大小計算等常見操作都可以忽略，算是個比較好寫的數據結構。JDK中自然是沒有現成的類可用，AbstractList都顯得有些多餘，於是，我單純的創建了一個類CircularArrayList&lt;E&gt;，並指定實現接口List&lt;E&gt;。因為只需有限空間，為減小不必要的資源佔用，內部使用了普通的定長數組。注意，我按照以往的習慣，使用了範型，拉開了惡夢的序幕。<br><br>首先讓我崩潰的是這句語句：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">E[]&nbsp;elementData&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;E[capacity];</span></div>
<br>這是關於Java範型中最經典、也是最無奈的「錯誤」了。當時鬱悶的我上網一搜，發現了無數的「同道」。這種寫法，對於任何一個熟悉傳統範型的人來說，都不會覺得有何不妥吧。更雷人的是，網上查到這句語句的正確Java版寫法竟然是：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">E[]&nbsp;elementData&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(E[])&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Object[capacity];</span></div>
<br>我的天！那我要那個E是來幹嘛的？那直接用Object不就得了？當擺設啊？我不服氣，決心尋求「官方寫法」，打開我以往的最愛ArrayList&lt;E&gt;看其構造函數，赫然是：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">this</span><span style="color: #000000;">.elementData&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(E[])</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Object[initialCapacity];</span></div>
<br>我無語了。原來Java中的範型真的只是擺設。我的初始化的設想自然也完蛋了，因為你根本別想指望建立一個E的實例。以下語句在Java中也是無法編譯的：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;size;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;elementData[convert(i)]&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;E();<br>}</span></div>
<br>想知道「正確」寫法？說實話，實在太噁心了，我原本不想說的：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;init(Class</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">E</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;c)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;size;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;elementData[convert(i)]&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;c.newInstance();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div>
<br>這還是你走運的情況下。假如你的E不幸沒有缺省構造函數，你只能使用反射的方法，那個代碼更噁心，有興趣的自己看吧：<a target="_blank"  href="http://serdom.eu/ser/2007/03/25/java-generics-instantiating-objects-of-type-parameter-without-using-class-literal">http://serdom.eu/ser/2007/03/25/java-generics-instantiating-objects-of-type-parameter-without-using-class-literal</a><br><br>Anders hejlsberg 說道: <span style="color: red; font-style: italic;">當你編譯一個Java泛型類時，編譯器會將所有的類型參數替換為Object。當然，如果你嘗試建立一個List</span><int><span style="color: red; font-style: italic;">，你就需要對所有的int進行裝箱。因此，這會有很大的開銷。另外，為了讓VM高興，編譯器必須為所有的類型插入類型轉換。如果一個List是Object的，而你想將這些Object視為Customer，就必須將 Object轉換為Customer，以讓類型檢查器滿意。而它在實現這些的時候，真的只是為你插入所有這些類型轉換。因此，你只是嘗到了語法上的甜頭，卻沒有獲得任何執行效率。所以我覺得這是（泛型的）Java實現的頭號問題。</span><br><br>這就是Java為了兼容性做出的折衷：以一種近乎無恥的方式，實現了一種現代編程語言中絕無僅有的「範型」。據說Java 7中會有真正的範型，在那之前，我想我還是不要再碰這個「極品」比較好。請.Net的程序員盡情的嘲笑我吧。也許我的下一個程序會是用python寫的吧。<br><br></int> <img src ="http://www.cnitblog.com/addone/aggbug/61104.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2009-08-30 09:20 <a href="http://www.cnitblog.com/addone/archive/2009/08/30/61104.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JPSM: 用Java做的PSP存檔管理器</title><link>http://www.cnitblog.com/addone/archive/2009/04/14/56361.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Tue, 14 Apr 2009 10:58:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2009/04/14/56361.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/56361.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2009/04/14/56361.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/56361.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/56361.html</trackback:ping><description><![CDATA[<span style="color: red; font-weight: bold;">當前版本：1.1</span><br style="color: red; font-weight: bold;"><span style="color: red; font-weight: bold;">發佈日期：2009-10-27</span><br><br>在Mac下的PSP工具並不多，也感覺不是太方便，於是打算用Java做一個跨平台的存檔管理軟件。目前功能包括查看存檔信息和PSP存檔備份等。當前版本暫時沒有中文版，僅供測試使用。包含中文的國際版和比較完整的功能將會在1.2版提供，屆時也會將源代碼按GPL協議發布。<br><br>平台要求是Java 1.5以上即可。目前在Mac OSX 10.5 Intel和Windows XP上測試通過。兼容3.71 M33及5.00 M33。<br><br><img src="http://lh3.ggpht.com/_70JovzHBzDc/SubzXdKzKQI/AAAAAAAAAE8/xdFpXFRYYCI/%5BUNSET%5D.png?imgmax=800" style="max-width: 500px;"><br><br>
<h3><span style="font-weight: bold;">下載地址</span></h3>
Version 1.1 (build 27 Oct, 2009)<br><a href="http://www.cnitblog.com/Files/addone/jpsm-1.1.zip" target="_blank">平台無關壓縮檔</a><br><a href="http://www.cnitblog.com/Files/addone/jpsm_1_1.dmg.zip" target="_blank">Mac OS X 專用壓縮檔(dmg.zip)</a><br><br>如果有任何問題，請按照頁面右邊的聯系方式聯絡我。<br><br>
<h3>鏈接</h3>
PSP的SFO文檔處理方法參考以下文檔（英文）：<br><a href="http://hitmen.c02.at/files/yapspd/psp_doc/" target="_blank">yet another PlayStationPortable Documentation</a><br><br>原始發布頁（我的新站，英文）：<br><a target="_blank" href="http://addlone.blogspot.com/2009/04/jpsm-java-psp-savedata-manager.html">http://addlone.blogspot.com/2009/04/jpsm-java-psp-savedata-manager.html</a><br><br><br>   <img src ="http://www.cnitblog.com/addone/aggbug/56361.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2009-04-14 18:58 <a href="http://www.cnitblog.com/addone/archive/2009/04/14/56361.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>要高效还是要易用？——谈GUI与CLI</title><link>http://www.cnitblog.com/addone/archive/2008/01/08/38581.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Mon, 07 Jan 2008 17:24:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2008/01/08/38581.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/38581.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2008/01/08/38581.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/38581.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/38581.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 自Linux渐渐风行起来，有关图形界面（GUI，Graphical User Interface）和命令行界面（CLI，Command Line Interface）之争就一直闹个不停。看了众多评论之后，总有些郁闷之意想要发泄一下，虽然觉得有混水摸鱼的嫌疑，却还是不吐不快。&nbsp;&nbsp;<a href='http://www.cnitblog.com/addone/archive/2008/01/08/38581.html'>阅读全文</a><img src ="http://www.cnitblog.com/addone/aggbug/38581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2008-01-08 01:24 <a href="http://www.cnitblog.com/addone/archive/2008/01/08/38581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一种新的软件设计开发方法——谈UCL技术</title><link>http://www.cnitblog.com/addone/archive/2006/11/09/19006.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Thu, 09 Nov 2006 06:53:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2006/11/09/19006.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/19006.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2006/11/09/19006.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/19006.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/19006.html</trackback:ping><description><![CDATA[最近一段时间来，我都在忙于做一件&#8220;异想天开&#8221;的事情——寻找传说中的&#8220;银弹&#8221;。呵呵，听起来确实有些搞笑，但是我想我的确发现了什么。<br><hr size="2" width="100%">
<h2>引言</h2>
自Brooks预言&#8220;没有银弹&#8221;的数十年来，软件设计开发的理论和技术都有了相当大的改进，但也正如Brooks所言：没有银弹。<br>现在，我们拥有面向对象编程、UML建模、CMMI过程改进等各种理论和技术，然而所有这些充其量只能算得上铜质子弹，答案依然：没有银弹。<br><br>
<h2>通用构件库（UCL）的基本构想</h2>
我所设计的是一个叫做&#8220;通用构件库（Universal Components Library）&#8221;的框架，设计灵感源自可视化构件库VCL、MVC三层架构以及Linux下一个基于Alsa的声音合成软件，而其理论基础则是分层数据流图。<br>这个框架贯穿整个软件的设计和开发过程，试图让设计和开发连成一气。虽然并非基于面向对象设计与编程，但也不排斥面向对象编程技术。除了大幅度提高代码重用性之外，这个框架也有助于提高软件的可维护性。在基于UCL的设计和开发过程中，还可以综合运用XP开发过程及CMMI过程以进一步改善整个过程。<br><br>UCL的目标和当初VB、Delphi的目标一样，让软件开发变得就像搭积木那么简单。使用类似VCL、MFC的东西的确可以提高开发效率，但无法从根本上实现这个目标。其原因可以归结为几点：<br>
<ol>
    <li>把&#8220;搭积木&#8221;理解为对整个系统进行可视化开发，而非对系统的各个模块进行分层搭建；</li>
    <li>扩充性不足，自定义组件没有能获得和自带组件同等的地位，以至于不得不重复发明各种轮子；</li>
    <li>独立于设计过程，无法将代码和设计进行对照。</li>
</ol>
UCL是一个抽象的库，只是一个框架而已，作用是把以VCL、MFC之类的具体组件组织起来，从而真正具备&#8220;搭建&#8221;的能力。由于本身就是个完全开放的框架，因此任何组件都是平等的，大家可以随心所欲地创建各种各样的专用UCL库。UCL框架使用UCL图作为设计和代码的中间媒介，数据流图可以直接转换为UCL图，代码可以由UCL图直接生成或&#8220;搭建&#8221;。<br>由于UCL组件和代码一一对应，因此UCL图是依赖于具体库的，例如使用VCL搭建的系统和使用MFC搭建的系统，即使其功能一致，UCL图也有可能不同。也就是说，想要应用UCL技术，就必须拥有要使用的具体库所对应的UCL库，例如UCL_VCL、UCL_MFC、UCL_Swing、UCL_QT等等，这也是为了实现真正的&#8220;搭建&#8221;所付出的代价。<br><br>UCL图是UCL设计思想的核心，其灵感来源于Linux下的一个声音合成软件。该软件提供了许多种类的声音处理模块，这些模块的外部接口都很简单，大都只有输入、输出接口而已。但是只需要将各种模块用音频流连接起来，理论上却可以合成出任意的声音。面向对象技术中的问题之一就是类的接口太多且没有标准，不便于掌握。如果可以每个组件只有几个接口，并且组件的分类比较科学，那么掌握起来就简单多了。<br>除了连接关系之外，为了适应自顶向下的分层设计的需要，UCL图还支持&#8220;组合&#8221;的关系。一个组件可以由一个或多个内部组件组合而成，嵌套层次不限。这样，一个复杂系统就可能最终分解为一系列仅具有一个输入接口和一个输出接口的简单组件。<br>UCL图除了能够充当设计和开发的中间媒介之外，还有另一个重要的作用。在分解为一系列UCL组件之后，整个系统的规模和工作量就可以快捷并准确地估计出来。<br><br>可见，UCL技术的优点在于：<br>
<ol>
    <li>使得软件的规模和工作量在前期设计就可以比较准确地估计；</li>
    <li>使得设计和开发过程一气呵成；</li>
    <li>提倡面向组件开发，在不增加代码复杂性的前提下，大大提高了可重用性；</li>
    <li>使得软件更易于维护。</li>
    <li>以下将分别讨论这些问题。</li>
</ol>
<br>
<h2>UCL解决的问题：前期设计</h2>
软件的前期设计，从来不是个简单的问题。我们在获得需求说明书之后，就需要将其转变为设计蓝图。过去的数据流、事务流、控制流分析方法更适用于模块内部的分析，而对于一个庞大的系统，则往往需要使用UML进行建模。<br>无论如何，建模过程总是繁杂的，而且最糟糕的是，和传统的工程设计不同，这种繁杂的软件设计往往跟最终的软件产品根本就是天壤之别。我们最后拥有的是一大堆跟最终代码几乎完全没关系的模型以及一大堆几乎丝毫看不出设计思想的代码。因此，对于一个稍微复杂的项目，我们对其规模和工作量都是难以准确估计的。<br>即使我们使用昂贵的工具来试图同步设计和产品代码，经常也只是徒劳而已，过高的设计成本和维护成本使得这种投资毫无意义。更多的公司选择了手工作坊式的开发方式，只是在开发过程中借助XP或CMMI来扳回一点面子。在项目完成后，再根据最终产品进行建模——当然，这已经不再是设计了，只能算是&#8220;文档化&#8221;罢了。<br><br>基于UCL的设计过程，并不是面向对象的设计过程，而是基于传统的分层数据流图，也就是说，整个设计过程是自顶向下的。本来，数据流图对于系统的架构描述并不清晰。但是，分层数据流图使得这样的架构描述至少可以达到&#8220;将就能用&#8221;的程度。更重要的是，由于最底层的数据流图和UCL图可以方便地对照，由UCL图作为设计和产品代码的中间媒介，从而将设计过程和开发过程连成一气。<br>实现UCL组件和数据流处理的一一对应，更重要的意义在于使得系统的规模和工作量将变得更直观、更准确，也更易于统计，而不像过去一样只能依靠项目负责人的经验判断。<br>而在购买或自行填充了UCL库之后，通过实现UCL组件和代码的一一对应，不仅可以实现建模和实现的互相参照，开发成本也可以大大降低。<br><br>以下是一个简单系统的功能需求说明、分层数据流图以及一个对应的UCL图，仅供参考：<br><br>
<h2>UCL解决的问题：重用</h2>
重用，是件说起来容易做起来难的事情。利用面向对象技术，设计一个可重用构件的工作量大约是&#8220;一次性&#8221;构件的2~3倍。<br>这里的问题是通用性和专用构件的矛盾。人们在得到一个专用构件之后，在将其重用的过程中往往需要针对特定需求进行修改。不断的重用导致不断的修改，并催生了使这个构件日趋通用化的需求，最终专用构件变成了通用构件。但构件的通用性带来了高昂的维护成本，最终人们对其失去了兴趣，又开始重新开发专用构件。如是循环。<br>高昂的重用成本带来了昂贵的可重用构件，也就导致更多的人决定自行开发各种形态各异的轮子，最终这些轮子又陷入了成本高昂的重用泥沼中。<br><br>UCL组件和传统的构件很不相同，其特点如下：<br>
<ol>
    <li>关系简单，只有简单的&#8220;连接&#8221;和&#8220;组合&#8221;两种关系；</li>
    <li>接口简单，只具备&#8220;输入&#8221;、&#8220;输出&#8221;等几个简单的接口；</li>
    <li>处理简单，通常只执行很简单的处理，保证了低廉的开发成本和良好的可维护性，同时保证了可重用性。</li>
</ol>
通过两种简单的关系，我们就可以将各种简单的UCL组件&#8220;搭建&#8221;成具备复杂功能的复合组件，最终搭建成整个系统。也就是说，尽管UCL的设计过程是自顶向下的，但开发过程却是自底向上的，这就在保持低成本的同时兼顾了通用性，从而得以解决传统面向对象开发方法中的通用和专用的矛盾。<br><br>在具体的开发过程中，我们在得到UCL图之后，首先是实现图中的各个组件。这些组件的代码和组件一一对应，存放在代码库中，日后再次使用该组件时无需再次编写，由于组件的规模很小，可重用性就比传统的构件要高得多。<br>在所有的底层组件都有代码实现之后，借助专用的CASE工具，输入UCL图并连接代码库，即可直接生成完整的系统。<br><br>当然，以上是一个理想化的过程。其主要的一些应用问题如下（当然还有别的）：<br>
<h4>如何输入UCL图？</h4>
我的目标是设计出一个类似那个声音合成软件的画图软件，这样就能以可视化的方式来拖拉各种组件并创建连接。但是作为一种简单的替代方案，我也设计出了一种脚本语言，用文本的方式来表达UCL图中所包含的所有元素。以下是一个脚本示例：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">cnitblog</span><span style="color: #000000;">.</span><span style="color: #000000;">addone</span><span style="color: #000000;">.</span><span style="color: #000000;">AID3Tagger</span><span style="color: #000000;">.</span><span style="color: #000000;">Mp3FileListEditor<br><br>AddFileButton</span><span style="color: #000000;">:</span><span style="color: #000000;">JButton</span><span style="color: #000000;">,</span><span style="color: #000000;">title</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">添加文件</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">proc</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">OpenFileDialog</span><span style="color: #000000;">.</span><span style="color: #000000;">show;<br>OpenFileDialog</span><span style="color: #000000;">:</span><span style="color: #000000;">JFilteredFileChooser</span><span style="color: #000000;">,</span><span style="color: #000000;">multiSelection</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">true</span><span style="color: #000000;">"</span><span style="color: #000000;">/</span><span style="color: #000000;">filterString</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">.mp3|MP3音乐文件</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">show</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Mp3FileList</span><span style="color: #000000;">.</span><span style="color: #000000;">add(fileList</span><span style="color: #000000;">:</span><span style="color: #008080;">File</span><span style="color: #000000;">[]);<br><br>AddDirButton</span><span style="color: #000000;">:</span><span style="color: #000000;">JButton</span><span style="color: #000000;">,</span><span style="color: #000000;">title</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">添加文件夹</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">proc</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">OpenDirDialog</span><span style="color: #000000;">.</span><span style="color: #000000;">show;<br>OpenDirDialog</span><span style="color: #000000;">:</span><span style="color: #000000;">JFileChooser</span><span style="color: #000000;">,</span><span style="color: #000000;">selectionMode</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">directories</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">show</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">GetFilesInDirRecursively</span><span style="color: #000000;">.</span><span style="color: #000000;">proc(</span><span style="color: #008080;">dir</span><span style="color: #000000;">:</span><span style="color: #008080;">File</span><span style="color: #000000;">);<br>GetFilesInDirRecursively</span><span style="color: #000000;">&lt;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&gt;,</span><span style="color: #000000;">filterString</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">.mp3</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">proc</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">Mp3FileList</span><span style="color: #000000;">.</span><span style="color: #000000;">add(fileList</span><span style="color: #000000;">:</span><span style="color: #008080;">File</span><span style="color: #000000;">[]);<br><br>RemoveFileButton</span><span style="color: #000000;">:</span><span style="color: #000000;">JButton</span><span style="color: #000000;">,</span><span style="color: #000000;">title</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">移除文件</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;">proc</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">FileListBox</span><span style="color: #000000;">.</span><span style="color: #000000;">remove;<br>SourceEncodingBox</span><span style="color: #000000;">:</span><span style="color: #000000;">JComboBox</span><span style="color: #000000;">,</span><span style="color: #000000;">editable</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">false</span><span style="color: #000000;">"</span><span style="color: #000000;">/</span><span style="color: #000000;">data</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">GBK|UTF-8|UTF-16-BE|UTF-16-LE</span><span style="color: #000000;">"</span><span style="color: #000000;">,<br></span><span style="color: #000000;">proc</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">FileListBox</span><span style="color: #000000;">.</span><span style="color: #000000;">changeEncoding(encoding</span><span style="color: #000000;">:</span><span style="color: #0000ff;">String</span><span style="color: #000000;">);</span></div>
<br>
<h4>如何&#8220;真正地&#8221;实现UCL图到具体代码的转换？</h4>
这种转换的问题在于，对于UCL组件的属性应该如何转换？我目前的想法是，使用一个映射文件，将UCL组件和具体组件的属性映射关系保存在其中，例如：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">version</span><span style="color: #000000;">=</span><span style="color: #000000;">0.1</span><span style="color: #000000;"><br>type</span><span style="color: #000000;">=</span><span style="color: #000000;">java.swing<br><br>JButton.title</span><span style="color: #000000;">=</span><span style="color: #000000;">setText(String)<br>JFileChooser.multiSelection</span><span style="color: #000000;">=</span><span style="color: #000000;">setMultiSelectionEnabled(boolean)<br>JFileChooser.filterString</span><span style="color: #000000;">=</span><span style="color: #000000;">setFileFilter(Custom.FileFilter)<br>JFileChooser.selectionMode</span><span style="color: #000000;">=</span><span style="color: #000000;">setFileSelectionMode(Custom.FileSelectionMode)<br><br>_converter_.FileSelectionMode.source</span><span style="color: #000000;">=</span><span style="color: #000000;">String<br>_converter_.FileSelectionMode.target</span><span style="color: #000000;">=</span><span style="color: #000000;">int<br>_converter_.FileSelectionMode.rule</span><span style="color: #000000;">=</span><span style="color: #000000;">files|</span><span style="color: #000000;">0</span><span style="color: #000000;">|directories|</span><span style="color: #000000;">1</span><span style="color: #000000;">|files_and_directories|</span><span style="color: #000000;">2</span></div>
<br>另外一个可供考虑的方法是，开发UCL组件来专门对属性进行处理。这样即可在目前的UCL框架中实现，无需增加新的特性。<br><br>
<h4>如何使用UCL设计GUI界面？</h4>
不得不承认，这将是个很棘手的问题。对于java、.net来说，情况要好些，因为界面也是使用代码来构建的。但对于VB之类来说，由于界面是采用专用格式来保存，情况就麻烦得多了。而且，即使是java和.net，没有可视化的界面设计，也将是没有吸引力的解决方案。<br>我目前的想法有两个：一个是将具体的GUI组件包装为UCL组件，不过这样一来有可能会加大界面设计的工作量；一个是干脆完全将GUI部分从UCL中剔除出去，即这一部分使用传统的开发方法，但应该保证GUI组件和UCL组件能够彼此调用。<br><br>
<h2>UCL解决的问题：维护</h2>
在传统的软件开发项目中，维护成本所占的比例是很大的。这里主要指的是由需求变更、BUG修改等引起的软件修改和更新工作。对于小的修补工作来说，每次修改的成本并不高，但是在多次修改之后，原有的代码往往就变得面目全非了。这时，如果再面对一个较大的需求变更，往往我们情愿重新开发，而不愿意再继续维护这个系统。<br>造成这种问题的原因有很多，一方面是因为无法从代码中看出设计，不得不求助于文档，这对于一些缺乏文档的项目来说是致命的；另一方面是，在修改之后没有及时地同步文档和模型，这种情况在发生若干次之后，这个项目离寿终正寝也不远了。<br><br>如前所述，UCL图是设计和实现之间的一座桥梁，对于解决这类维护问题应该是很有效的。修改工作和开发时一样，都只需对图进行操作，所有的设计都可一目了然。这种方式，有利于提高维护效率和降低维护成本。<br><br>
<h2>总结和思考</h2>
由以上讨论可以看到，由于平滑连接了设计过程和实现过程，UCL技术具有许多独特的优点。作为一种全新的技术，UCL不仅仅是一个组件库的理论，更代表着全新的设计思想和开发方式。作为一个抽象的组件库，UCL更不是VCL、MFC等的替代品，而是这些具体库的包装者和使用者。<br>由这些理论可见，如果UCL技术能被证明可用于实际的商业开发中，目前的整个设计和开发方式都将发生巨大的改变。不过，由于理论是全新的，而且对开发语言具有依赖性，基于UCL的设计和开发过程更需要有一系列的CASE软件支持，这可能会带来一系列的问题，但更有可能形成一个巨大的商机。<br><br>不过很遗憾，尽管我已经在一些小软件中成功的应用了相关理论，但目前，各种应用问题还远没有得到完全解决。例如，问题1中所说的可视化设计器和脚本解析器，还都没有实现。而问题2、3的解决方法还需要进行深入讨论。这一切，都需要耗费大量的时间和精力。<br>好在，即使不能完全实现由UCL图向代码的转换，这个理论至少也能帮助我们在设计前期就对一个项目的规模和工作量进行更为准确的统计。<br><br>限于个人的时间、金钱和精力，我不得不暂时放弃UCL的相关思考。把东西扔在这里，只希望机缘巧合，居然能起抛砖引玉之效，那也不枉我连日的冥思苦想了。 <img src ="http://www.cnitblog.com/addone/aggbug/19006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2006-11-09 14:53 <a href="http://www.cnitblog.com/addone/archive/2006/11/09/19006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>发现SWT和平台确实绑定过紧</title><link>http://www.cnitblog.com/addone/archive/2006/09/07/16465.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Wed, 06 Sep 2006 17:06:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2006/09/07/16465.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/16465.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2006/09/07/16465.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/16465.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/16465.html</trackback:ping><description><![CDATA[素来就比较喜欢SWT，因为和Swing比起来，和本地程序观感一致的SWT要更亲切些，而且性能上也更有优势，加上Eclipse的声势，SWT就更显得魅力无穷了。<br /><br />不过，从Netbeans5.0发布以来，随着Netbeans的越加成熟以及Swing的性能提升，有关“Netbeans vs Eclipse”、“Swing vs SWT”之类的讨论，就变得更加激烈了。据说有不少开发团队都已经从Eclipse转向Netbeans了。<br />我好奇地试用了一下Netbeans，觉得比起当年的3.x来说，进步确实相当大。就速度来说，虽然不觉得快，但至少和Eclipse不相上下。虽然没有Eclipse那么大的声势，但Netbeans的插件阵营也在逐步丰富，俨然有后起直追之风。<br />无论如何，有竞争才会有进步，两个IDE在争斗，广大开发人员就有福啦！一家独大显然不会是太好的局面。<br /><br />抛开IDE不谈，我倒是对SWT产生了些许厌烦：它的跨平台特性非常糟糕。我对SWT的性能并不太关注，也许Linux上的SWT确实并没有做什么优化，但至少它目前的性能和观感还是能令我满意的（和Swing相比的话）。<br />然而，SWT和平台的绑定实在太过紧密了！这造成了软件跨平台发布的问题。SWT软件在发布时，除了需要包括各种class文件和必要的资源文件之外，还必须包括SWT库：一个swt.jar，外加数量不等的链接库/共享库。这个庞大的swt.jar是平台相关的，也就是说每个平台都有自己的swt.jar文件。swt.jar甚至还是版本相关的，即使是同一个平台，还存在不同版本的swt.jar，它们各自都要求链接和各自版本号一致的链接库/共享库。<br />这种令人厌烦的事情让人想起当年发布VB软件时的情景。不过，许多电脑都根本没有预装SWT的运行时文件。除了大大增加了软件的发布大小之外，这种发布方式也使得Java“一次编译，到处运行”变成了传说，而真正成为了“一次编译，到处调试”。<br /><br />我最近在尝试“移植”一个用SWT写的跳棋游戏，从Windows到Linux，再到Mac。我非常不愿意用“移植”这个词，因为这让我对Java的良好印象大打折扣。我原本的目标是对其进行改进，使其能在这三个系统上都可以直接运行，就像一般的Swing程序那样。<br />首先，我在Linux上无法运行该程序，意料之中。原程序（二进制版本）大小仅750K，Windows版本的SWT运行时文件共1.6M。在拷入了Linux版本的SWT运行时文件（共2.2M）之后，程序仍然无法运行，意料之中，当然是类路径的问题。<br />当我最终解决完这个问题之后并成功完成Linux版本的“移植”之后，我终于明白了，对于SWT程序来说，“一次编译，到处运行”几乎是不可能的。<font color="#ff0000">首先就要把各种平台的运行时文件都带上，可以想象这个软件会变得有多庞大了。然后是设置类路径，由于需要跨平台，这居然成了个大问题：你得根据当前的平台来选择对应的swt.jar。</font><br />所以，同样是Java程序，但“通用版”的SWT程序是不会有的了。<font color="#ff0000">你只能为一个Java软件分别发布Windows版本、Linux版本、Mac版本，</font>而为了保证这些版本都能正常工作，你还必须在各个平台进行测试，就像过去发布C++的项目一样。<br /><br />也许有很多人不会介意这个问题吧，例如Eclipse。但是对于更多的人来说，需要发布及维护多个平台的版本，无疑是种十分无聊的工作：这可是Java程序。<br />我想，就算跟平台绑定是种折衷，至少也该提供个便于发布各种平台版本的SWT软件的工具吧？如果我可以<font color="#008000">在Windows版本的Eclipse中选取“生成Linux平台的可执行Jar文件”</font>，即使需要带上那2.2M的庞大运行时文件，我想我也可以暂且心安理得的接受了。<br /><img src ="http://www.cnitblog.com/addone/aggbug/16465.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2006-09-07 01:06 <a href="http://www.cnitblog.com/addone/archive/2006/09/07/16465.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>XML解析器易用性测试对比</title><link>http://www.cnitblog.com/addone/archive/2006/09/02/16278.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Fri, 01 Sep 2006 17:37:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2006/09/02/16278.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/16278.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2006/09/02/16278.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/16278.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/16278.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Java+XML是个绝配，也已经渐渐成为了当今的主流技术。笔者在实际使用中却发现XML的操作着实令人头疼，涉及到的技术繁杂零乱，甚至有些令人望而生畏。好在，这只是一种错觉。XML操作并不难，关键是选择一个合适的解析器（或者是像JAXP那样的解析层）。XML的常用解析器无非两种（当然还有其他的，这里就不提了）：DOM和SAX。前者在解析时将整个XML文件的内容解析为一棵树，之后便可以按结点访问；...&nbsp;&nbsp;<a href='http://www.cnitblog.com/addone/archive/2006/09/02/16278.html'>阅读全文</a><img src ="http://www.cnitblog.com/addone/aggbug/16278.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2006-09-02 01:37 <a href="http://www.cnitblog.com/addone/archive/2006/09/02/16278.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用Pyqt在Linux下开发GUI桌面应用</title><link>http://www.cnitblog.com/addone/archive/2006/04/01/8469.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Sat, 01 Apr 2006 07:27:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2006/04/01/8469.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/8469.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2006/04/01/8469.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/8469.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/8469.html</trackback:ping><description><![CDATA[要在Linux下开发具有图形界面的桌面应用程序，我们有许多选择。当然，除了语言方面的考虑外，我们更多的是考虑窗口部件工具箱（以前称为控件库或组件库）的选择，这将在很大程度上影响我们的开发效率。<br><br>如果考虑到跨平台应用，选择Java的Swing可能非常合适。但是目前的swing尽管很强大也很灵活，我们始终还是会觉得有些不顺手：例如默认的界面不好看也不像本地程序，第三方皮肤又不好找；开发周期相对较长；执行速度相对慢些等等。<br>除了java之外，在Windows下，我们一般可以在MFC（VC）和VCL（Delphi）中作选择（当然还有别的）；在Linux下，我们可以选择QT或GTK。<br><br>QT具有相当不错的架构以及先进的事件处理机制，文档也很齐全，当然还少不了一个功能不错的可视化窗体设计器QtDesigner。著名的桌面环境KDE就是使用qt库进行开发的。<br><a target="_blank" class="" title="" href="http://www.trolltech.com/images/screenshots/qt_designer_windows.png"><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/r_qt_designer_windows.png" alt="r_qt_designer_windows.png" width="589" height="480" border="0"></a><br>GTK的架构也不错，不过界面相对而言没有qt的那么炫目。gtk当然也有自己的可视化窗体设计器glade。另一个著名的桌面环境gnome就是使用gtk库进行开发的。另外，gtk也获得了广泛的商业支持。<br><a target="_blank" class="" title="" href="http://glade.gnome.org/graphics/screenshot1.png"><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/r_glade1.png" alt="r_glade1.png" width="600" height="480" border="0"></a><br><br>就我个人而言，我更喜欢qt，桌面环境也更喜欢kde，因为界面确实很漂亮，看着养眼；执行效率也很不错。更重要的是，使用qt进行rad快速开发似乎更为方便。<br>可惜在linux下使用c++开发程序并非易事，至少你得先熟悉gnu版本的c/c++库才行。我虽然很希望能使用qt做出漂亮的gui桌面应用，但是面对c++本身的复杂以及完全陌生的函数库，我望而却步。<br>这时，我发现了python。这是一种很简单的脚本语言，其语言特性本身就十分简单易用。更惊人的是，这种语言还可以绑定到多种部件工具箱，包括GTK、QT、MFC、Swing等！而Pyqt就是python和qt部件库的结合。简单易用的python配合强大方便的qtdesigner，我找到了当年在windows下使用vb编程的感觉。<br><br>为了使用pyqt进行编程，首先是安装和配置系统环境。我的环境如下：Kubuntu Linux breezy（5.10）；python 2.4；qt 3.3；pyqt 3.14；KDE 3.5。<br>当然，这样还不够。我们当然可以使用记事本kate来编写代码，但是一款好用的IDE将能够使我们的开发工作事半功倍。我们可以选择KDevelop或者Eric。<br>KDevelop是KDE下老牌的IDE了，支持N多种语言的开发，其中也包括python，还自带了pyqt的示例程序。<br>不过，我还是选择了Eric。Eric是KDE下的python集成开发环境，本身就是用pyqt开发的（由此可以看出pyqt的强大&#8230;&#8230;）。eric同样集成了版本管理系统、项目管理、重构等功能。和kdevelop相比，eric中的源代码分类功能更方便，py脚本、qt窗体、语言包等文件是分类管理的。除了任务窗格外，eric还集成了一个python的shell控制台窗格，显得更加适合开发pyqt程序。<br><a target="_blank" class="" title="eric" href="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric.png"><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/r_eric.png" alt="r_eric.png" width="640" height="448" border="0"></a><br>
<h3>一个简单的示例</h3>
下面实验一下，使用Eric 3.7来开发一个简单的Helloworld程序。<br>我们将要使用qtdesigner设计一个窗体，上面放置一个按钮和一个label，点击按钮时显示Hello World，再次点击时则隐藏。<br><br>首先我们需要建立一个新工程。<br>打开Eric后，选择Project-&gt;New，然后是填写工程信息。在Project Name栏中填写工程名称，Prog. Language选择Python，UI Type选择QT，Project Directory中选择工程的目录，其他的几项可填可不填，点击&lt;确定&gt;即可。<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric1.png" alt="o_eric1.png" width="489" height="536" border="0"><br><br>接下来Eric会询问新工程要使用什么版本控制系统，这里我们还没用到版本控制，就选&lt;无&gt;吧。<br><img src="http://www.cnitblog.com/WebResource.axd?d=pLXXeGbWF7eXU8SMs2-GFZvUWY2JNH05dFx5YzJhGUYAYJAFEaTEq36NAhTPy7_KekvzDFwt8wvQWdByvJIGWdEq6x2KpKD80&amp;t=632780334337343750" width="1" height="1"><br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric2.png" alt="o_eric2.png" width="334" height="191" border="0"><br><br>现在要新建一个窗体。在左边的工程浏览器切换到窗体标签页，在右键菜单中选择&lt;New Form&gt;。<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric3.png" alt="o_eric3.png" width="286" height="269" border="0"><br><br>Eric会询问新窗体的类型，简单起见，我们选择&lt;Dialog&gt;，点击&lt;确定&gt;后输入新窗体的文件名HelloDialog并点击&lt;保存&gt;。<br><br>这时Eric会启动窗体设计器QTDesigner（我系统上用KDevDesigner代替了）并打开新窗体。<br>QtDesigner的使用相当简单，相信用过delphi或者vb的朋友都不会陌生。这里就不详述其用法了。<br>在窗体上加入一个PushButton和一个TextLabel，各部件属性设置如下：<br>
<table border="1">
    <tbody>
        <tr>
            <td>部件</td>
            <td>属性</td>
            <td valign="top">值<br></td>
        </tr>
        <tr>
            <td valign="top">Form<br></td>
            <td valign="top">name<br></td>
            <td valign="top">helloForm<br></td>
        </tr>
        <tr>
            <td valign="top"><br></td>
            <td valign="top">caption<br></td>
            <td valign="top">Pyqt示例<br></td>
        </tr>
        <tr>
            <td valign="top">TextLabel<br></td>
            <td valign="top">name<br></td>
            <td valign="top">helloText<br></td>
        </tr>
        <tr>
            <td valign="top"><br></td>
            <td valign="top">text<br></td>
            <td valign="top">Hello, world!<br></td>
        </tr>
        <tr>
            <td valign="top">PushButton<br></td>
            <td valign="top">name<br></td>
            <td valign="top">showHelloButton<br></td>
        </tr>
        <tr>
            <td valign="top"><br></td>
            <td valign="top">text<br></td>
            <td valign="top">打个招呼(&amp;H)<br></td>
        </tr>
    </tbody>
</table>
调整部件的位置和大小，如图所示。<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric6.png" alt="o_eric6.png" width="249" height="116" border="0"><br><br>QT库中的事件处理使用的是信号/插槽(Signal/Slot)机制，现在我们需要准备自定义的事件处理插槽。<br>在主菜单选择Edit-&gt;Slots，点击&lt;New Function&gt;来新建一个插槽函数toggleHelloTextVisibility()。<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric4.png" alt="o_eric4.png" width="608" height="405" border="0"><br><br>接着就要将按钮的点击信号连接到这个插槽上。在主菜单选择Edit-&gt;Connections，新建一个连接。<br>Sender选择showHelloButton，Signal选择clicked，Receiver选择helloForms，Slot就选择刚刚新建的插槽函数toggleHelloTextVisibility，点击&lt;确定&gt;即可。<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric10.png" alt="o_eric10.png" width="565" height="292" border="0"><br><br>好了，窗体制作完成啦，现在按Ctrl+S保存吧。<br>现在回到Eric中，我们会看到新建的窗体HelloDialog.ui已经出现在窗体标签页中了。<br>要把窗体文件编译为一个python单元，我们需要使用pyuic命令。而当未来窗体文件发生改变时，eric可以自动运行pyuic命令来更新相应的python单元。因此，我们不能直接修改生成的python单元，而需要继承它。<br>在Eric中，这一切都很简单。首先选中这个窗体，在快捷菜单中选择Compile Form，Eric会自动编译窗体，并将生成的窗体单元加入到工程中。然后我们要继承它，在快捷菜单中选择Generate Subclass，输入子类名并确定。<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric5.png" alt="o_eric5.png" width="358" height="143" border="0"><br><br>在新的子类单元中，找到插槽函数toggleHelloTextVisibility，修改如下：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;toggleHelloTextVisibility(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">(self.helloText.isVisible()):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.helloText.hide()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.helloText.show()</span></div>
<br>然后按Ctrl+S将子类保存到工程目录下，命名为HelloForm_Impl.py。<br>在工程浏览器中选择源代码（Sources）标签页，可以看到窗体单元HelloDialog.py已经在工程中了，但新的子类单元还不在其中，我们需要将其手动加入。<br>在工程浏览器的快捷菜单中选择&lt;Add source file&gt;，并选择刚才建立的子类单元HelloForm_Impl.py，确定即可。<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric7.png" alt="o_eric7.png" width="399" height="175" border="0"><br><br>下面我们还需要一个启动单元作为工程的主单元。当然，直接把这些代码放在HelloForm_Impl.py中也是可以的，不过为了清晰起见，我们最好还是另外建立一个启动单元。<br>按Ctrl+N来建立一个新文件，在其中输入以下代码：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008000;">#</span><span style="color: #008000;">!/usr/bin/env&nbsp;python</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;sys<br></span><span style="color: #0000ff;">from</span><span style="color: #000000;">&nbsp;qt&nbsp;</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">from</span><span style="color: #000000;">&nbsp;HelloForm_Impl&nbsp;</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;HelloForm_Impl<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;main(args):<br>&nbsp;&nbsp;&nbsp;&nbsp;app</span><span style="color: #000000;">=</span><span style="color: #000000;">QApplication(args)<br>&nbsp;&nbsp;&nbsp;&nbsp;window</span><span style="color: #000000;">=</span><span style="color: #000000;">HelloForm_Impl()<br>&nbsp;&nbsp;&nbsp;&nbsp;window.show()<br>&nbsp;&nbsp;&nbsp;&nbsp;app.connect(app,SIGNAL(</span><span style="color: #800000;">"</span><span style="color: #800000;">lastWindowClosed()</span><span style="color: #800000;">"</span><span style="color: #000000;">),app,SLOT(</span><span style="color: #800000;">"</span><span style="color: #800000;">quit()</span><span style="color: #800000;">"</span><span style="color: #000000;">))<br>&nbsp;&nbsp;&nbsp;&nbsp;app.exec_loop()<br>&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;</span><span style="color: #800080;">__name__</span><span style="color: #000000;">==</span><span style="color: #800000;">"</span><span style="color: #800000;">__main__</span><span style="color: #800000;">"</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;main(sys.argv)<br></span></div>
<br>以上代码创建了一个QApplication对象，并将我们的HelloForm_Impl类作为其主窗体显示，当主窗体关闭时退出程序。<br>按Ctrl+S将新文件保存为SayHello.py，然后把它加入到工程中。<br>从主菜单中选择 Project-&gt;Properties 打开工程属性对话框，将其中的主单元（Main Script）一项改为SayHello.py。<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric8.png" alt="o_eric8.png" width="475" height="33" border="0"><br><br>现在，按下Shift+F2来运行一下看看最终效果吧！点击按钮即可切换Label的显示状态。<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/o_eric9.png" alt="o_eric9.png" width="249" height="126" border="0"><br><br>
<h3>小结</h3>
呵呵，怎么样，是不是很有VB的感觉呢？从这个简单的例子就可以看出，Pyqt用于RAD开发GUI桌面应用是相当不错的，至少比Java、C++都要简单得多。除了能够使用python本身的系统函数之外，我们还可以直接调用qt的各种类，也能借助qt的信号/插槽机制轻松实现事件处理。<br>另外，我们还可以借由pyqt开发原型程序，在正式版开发时可以很轻松的将其转换为C/C++程序。<br><br>不过，由于绑定了qt库，pyqt在跨平台运行时，就要求目标平台必须安装有qt运行库。这也就是和java相比的一个不足之处了。<br><br>
<h3>参考资料</h3>
<a target="_blank" class="" title="" href="http://python.cn/">中国Python社区</a><br><a target="_blank" class="" title="" href="http://glade.gnome.org/">GTK可视化窗体设计器Glade官方网站</a><br><a target="_blank" class="" title="" href="http://www.trolltech.cn/products/qt/index.html">QT官方网站</a><br><a target="_blank" class="" title="" href="http://www.die-offenbachs.de/detlev/eric3.html">Eric Python集成开发环境官方网站</a><br><br><a target="_blank" class="" title="" href="http://cn.diveintopython.org/">《Dive Into Python》简体中文版</a><br><a target="_blank" class="" title="" href="http://www.commandprompt.com/community/pyqt/">《GUI Programming with Python: QT Edition》：Pyqt编程指南</a><br><br><br> <img src ="http://www.cnitblog.com/addone/aggbug/8469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2006-04-01 15:27 <a href="http://www.cnitblog.com/addone/archive/2006/04/01/8469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我做的一个Java日历组件</title><link>http://www.cnitblog.com/addone/archive/2006/04/01/8457.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Fri, 31 Mar 2006 18:39:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2006/04/01/8457.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/8457.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2006/04/01/8457.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/8457.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/8457.html</trackback:ping><description><![CDATA[最近用java做一个很简单的桌面应用，居然发现连一个好用的日历组件/控件都找不到，郁闷&#8230;&#8230;<br>于是自己做了一个简单的，现在放出来共享吧！<br>呃&#8230;&#8230;其实这个也不完全是自己做的，修改自一个网上下回来的日历组件（似乎是多年前开发的了），不过原版不是很好用，我进行了重构和增强，估计已经很难看出跟原版的关系了&#8230;&#8230;<br><br>这个组件以jar的形式发布，源代码也在里面。直接运行即可看到演示效果。<br>由于使用了枚举（enum），所以需要java5.0才能编译运行。<br>大家可以随便使用、修改，不过最好把修改后的源码发回来给我，谢谢啦！<br><br>以下运行截图均运行于Kubuntu Linux 5.10+JRE 5.0系统中。<br>直接运行效果：<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/r_jcalendar1.png" alt="r_jcalendar1.png" width="400" height="172" border="0"><br><br>实例效果（使用了第三方laf）：<br><img src="http://www.cnitblog.com/images/cnitblog_com/addone/2300/r_jcalendar2.png" alt="r_jcalendar2.png" width="400" height="200" border="0"><br><br><strong><font size="5"><a target="" class="" title="Java日历组件下载 build 20060401" href="http://www.cnitblog.com/Files/addone/aj_calendar_20060401.zip">点击这里下载</a></font></strong><br><br>
<h3>基本功能</h3>
可以选择日期，直接选择当天；<br>支持在改变日期时以及选择日期后的简单事件处理。<br>
<h3>编程接口</h3>
组件使用Eclipse3.1.1+JDK5.0开发并测试通过。<br>所有类放在包：addone.publics.gui.calendar中：<br>
<ul>
    <li>WeekDay类：操作周日的Enum</li>
    <li>CalendarColors类：定义了日历的外观颜色常数<br></li>
    <li>CellSelectionListener类：选中表格单元格后的侦听器</li>
    <li>CellChangeListener类：表格单元格改变后的侦听器</li>
    <li>CalendarSelectionListener类：在日历中选中日期后的侦听器</li>
    <li>CellChangeListener类：日历日期改变后的侦听器</li>
    <li>CalendarTable类：日历表格，封装了表格操作方法，继承自JTable</li>
    <li>CalendarPanel类：日历面板，封装了大部分的组件操作方法，继承自JPanel</li>
</ul>
基本用法（CalendarPanel类）：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">CalendarPanel()：构造一个以星期天为每周的第一天的日历<br>CalendarPanel(WeekDay)：构造一个以WeekDay为每周的第一天的日历<br>WeekDay&nbsp;getStartWeekDay()：返回当前日历每周的第一天<br>Calendar&nbsp;getCalendar()：返回组件内部当前的Calendar对象<br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setCalendar(Calendar&nbsp;calendar)：重新设置组件内部的calendar对象，并刷新日历<br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setToday()：日历跳转到当前日期，同时刷新日历<br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setCalendarChangeListener(CalendarChangeListener&nbsp;listener)：设置日历日期改变时的侦听器，当改变年份或月份时，以及选中日期但尚未跳转时触发<br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setCalendarSelectionListener(CalendarSelectionListener&nbsp;listener)：设置日历日期选中时的侦听器，当直接在日历中选中日期并跳转后，或者直接回到今天时触发</span></div>
<br>如果需要改变日历的外观颜色，直接修改CalendarColors类中的颜色常数即可。<br><br>
<h3>简单示例</h3>
<br>以下代码创建了一个Frame，其中放置了一个日历组件，日历设置为以星期一为每周的第一天。<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;CalendarFrame&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;JFrame&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;CalendarPanel&nbsp;myCalendar;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;CalendarFrame()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;initCalendar();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;initFrame();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pack();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;initCalendar()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myCalendar&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;CalendarPanel(WeekDay.MONDAY);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myCalendar.setCalendarSelectionListener(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;CalendarSelectionListener()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;calendarSelected(Calendar&nbsp;currentCalendar)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(currentCalendar.get(Calendar.YEAR)</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">-</span><span style="color: #000000;">"</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">(currentCalendar.get(Calendar.MONTH)</span><span style="color: #000000;">+</span><span style="color: #000000;">1</span><span style="color: #000000;">)</span><span style="color: #000000;">+</span><span style="color: #000000;">"</span><span style="color: #000000;">-</span><span style="color: #000000;">"</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">currentCalendar.get(Calendar.DATE));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;myCalendar.setCalendarChangeListener(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;CalendarChangeListener()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;calendarChanged()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">Changing<img src="http://www.cnitblog.com/Images/dot.gif"></span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;add(myCalendar);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;initFrame()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setTitle(</span><span style="color: #000000;">"</span><span style="color: #000000;">日历</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setSize(</span><span style="color: #000000;">400</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">172</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setResizable(</span><span style="color: #0000ff;">false</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div>
<br> <img src ="http://www.cnitblog.com/addone/aggbug/8457.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2006-04-01 02:39 <a href="http://www.cnitblog.com/addone/archive/2006/04/01/8457.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用CVS及其图形化客户端进行文件版本控制的操作简介</title><link>http://www.cnitblog.com/addone/archive/2006/03/19/7787.html</link><dc:creator>Addone</dc:creator><author>Addone</author><pubDate>Sun, 19 Mar 2006 15:09:00 GMT</pubDate><guid>http://www.cnitblog.com/addone/archive/2006/03/19/7787.html</guid><wfw:comment>http://www.cnitblog.com/addone/comments/7787.html</wfw:comment><comments>http://www.cnitblog.com/addone/archive/2006/03/19/7787.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/addone/comments/commentRss/7787.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/addone/services/trackbacks/7787.html</trackback:ping><description><![CDATA[旧文章，写于2004年10月13日。<br><hr size="2" width="100%"><br>在过去的开发中，尽管借助了XP方法的一些思想，但在代码、文档的版本控制方面依然相当脆弱，需要花费相当的时间来手动进行版本管理。最近在一个项目开发中，受开源项目的启发，采用了CVS来进行版本管理。<br>
CVS即Concurrent Versions System，协同版本系统，用于对源码、文档等文件进行版本控制。不少著名的开源软件都是采用这个系统进行版本管理。其具有冲突控制、EMail通知、变更日志、版本恢复等诸多实用功能。CVS采用的是C/S结构，服务器端和客户端都有Windows版和Linux版。<br>
笔者采用了Linux系统作为CVS服务器，用Cervisia（KDevelop自带）作为Linux的客户端，用WinCVS（中文版）作为Windows客户端。<br><br><br>1.CVS服务器的配置<br>
获取：在Linux下可以通过访问<a href="https://www.cvshome.org/">https://www.cvshome.org</a>来下载CVS服务器端，也可以通过APT或者APT for RPM来下载并安装CVS。<br><br>
配置：首先必须启用XINETD服务，然后在XINETD的配置中启用cvspserver这个服务。启动参数：-f --allow-root=／PATH／TO/YOUR/CVSROOT pserver。--allow-root是CVS目录，该目录必须对于登录用户有读写权限，这样在客户端就可以用此帐号登录并读写此目录。其他配置全部按照默认即可。<br>
重启机器后（在SuSE下可以直接点［ON］来启动，不需重启）CVS服务器就已经被激活了。<br><img src="http://addone.blogchina.com/addone/inc/20041013014631555683.png"><br>
2.Cervisia的配置<br>
获取：如果已经安装了KDevelop3.1，那么Cervisia2.1就已经一起安装并集成到文件管理器中了，这时在Konqueror的工具栏中可以找到［Cervisia］按钮，当本地目录存在CVS数据时，点击此按钮即可转变为CVS视图。<br><br>
配置仓库：在菜单中选择［仓库］-&gt;［仓库］，点［添加］，在［仓库］中填入：pserver:/$user@$host:/$path，其中$user指要登录的用户名；$host指服务器的地址，用域名或IP均可；$path指cvsroot目录位置，应该与第一步指定的路径一致。点［确定］完成仓库创建。<br><br>
登录：选中刚才创建的仓库，点［登录］并输入密码，若输入正确，则系统会自动登录到CVS服务器上，并且将密码保存到当前用户的配置目录下，将来如果没有改动，就不再需要输入密码了，这点应该注意一下。<br><br>
打开CVS文件夹：所谓CVS文件夹，是指从CVS检出到本地的工作文件夹，其中的每个目录都会有一个CVS子目录，那是用于版本管理的。从菜单-&gt;［文件］-&gt;［打开沙箱］中选择一个CVS文件夹，则主视图中就会列出该文件夹中所有文件的版本状态。<br><br>
基本操作：建议打开文件状态的自动更新功能。方法：［设置］-&gt;［配置Cervisia］，然后如下图设置。<br><img src="http://addone.blogchina.com/addone/inc/20041013014543108749.png"><br>
根据文件的状态来选择各项操作，如果是［Up to date］，则说明已是最新版本；若是［需要更新］，则说明服务器的版本较新，需要用［更新］功能；若是［已更改］，说明本地文件版本较新，需要［提交］。<br><img src="http://addone.blogchina.com/addone/inc/2004101301455435688.png"><br>
3.WinCVS的配置<br>
与Cervisia大同小异，这里就不再赘述了。值得一提的是，配置里提到的HOME目录，指的就是用来保存WinCVS配置及CVS用户密码的目录，一般用［我的文档］即可。<br><br>
流程概述：<br>
首先由任一客户端建立工程，然后用［导入］功能导入到CVS仓库中。其他客户端用［检出］功能来检出仓库中的模块到本地的工作目录。<br><br>
任何用户修改了源代码后，用［添加］、［提交］或［删除］功能来进行源码修改。<br>
如果发生冲突（即同一版本号的文件有两个人提交，但是内容不同），则用［比较］及［解决冲突］功能来解决冲突。<br><img src="http://addone.blogchina.com/addone/inc/20041013014622835313.png"><br>
其他用户可以用［更新］功能来获取最新的源码，用［浏览日志］功能查看版本历史及图形。<br><img src="http://addone.blogchina.com/addone/inc/20041013014602490312.png"><br>
可以配置CVS的Trigger，以实现EMail的自动寄送。也可以通过配置CVS客户端为自动更新文件状态，这样即可及时知道源码的当前状况而不需首先使用［更新］。<br><br>
除了CVS之外，其他著名的版本控制系统还有微软的VSS（Visual Source Safe）和号称CVS接班者的SVN(SubVersion)等等。VSS在企业开发中也具有相当不错的效果，而SVN相比CVS则确实有了功能上的改进。有关这些版本控制系统的比较，可以参考<a href="http://better-scm.berlios.de/comparison/comparison.html"> 这里的文章 </a>。<br><br>
软件下载地址：<br>
CVS：<a href="https://ccvs.cvshome.org/">https://ccvs.cvshome.org/</a><br>
Cervisia：<a href="http://www.kde.org/apps/cervisia/">http://www.kde.org/apps/cervisia/</a><br>
WinCVS：<a href="http://www.8848software.com/wincvs/"> 中文版 </a><a href="http://publishblog.blogchina.com/control/blog/www.wincvs.org"> 英文原版 </a><br> <img src ="http://www.cnitblog.com/addone/aggbug/7787.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/addone/" target="_blank">Addone</a> 2006-03-19 23:09 <a href="http://www.cnitblog.com/addone/archive/2006/03/19/7787.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>