2007年07月06日

最近用ReportLab(http://www.reportlab.org)的PDF工具箱做了一个电子投保单生成程序。可以根据用户填写的数据,或直接从作业系统中存储的数据直接生成PDF格式的电子表单。在使用ReportLab的过程中,发现其缺少排版和布局的功能。结合使用Java Swing(http://java.sun.com/docs/books/tutorial/uiswing/)的经验为其添加了布局管理器的功能,可以根据组件(标签和勾选框)的大小和间距自动计算出相应的坐标,而不用人为为每个组件指定坐标。

ReportLab 的应用实例在这里 http://www.reportlab.org/contribs.html
ReportLab 的商业站点在这里 http://www.reportlab.com

例 1:用BoxLayout 使两个标签垂直排列

    ct = Container ()
    ct.setLayout (BoxLayout (ct, BoxLayout.Y_AXIS))
    ct.setBorder (b2) lbl1 = Label (u"太平人寿保险有限公司", s1)
    lbl2 = Label (u"公司", s2)
    ct.add (lbl1)
    ct.add (lbl2)

 例 2:用GridLayout 排列多列标签

    ct = Container ()
    ct.setLayout (GridLayout (cols=2, vgap=5, hgap=10))
    ct.setBorder (b2)

    lbl1 = Label (u"组织代码:", s1)
    lbl2 = Label (u"123456", s2)
    lbl3 = Label (u"代理人姓名:", s1)
    lbl4 = Label (u"张三", s2)
    lbl5 = Label (u"代理人代码:", s1)
    lbl6 = Label (u"123456", s2)
    lbl7 = Label (u"暂收收据号:", s1)
    lbl8 = Label (u"123456", s2)
    lbl9 = Label (u"投保日期:", s1)
    lbl10 = Label (u"2006年6月5日", s2)

    ct.add (lbl9); ct.add (lbl10)
    ct.add (lbl7); ct.add (lbl8)
    ct.add (lbl5); ct.add (lbl6)
    ct.add (lbl3); ct.add (lbl4)
    ct.add (lbl1); ct.add (lbl2)

下图为各种布局管理器组合使用的效果:

下面是生成的电子保单细部,虚线框和蓝线框是为调试方便而画出来的,在生产环境中会将其隐去。其中带虚线框的为容器,带蓝色框的为图形组件。

 

使用 Django (http://www.djangoproject.com/)和 MySQL(http://www.mysql.com/) 开发的Web应用来输入业务数据。输入完整的数据后,点击 “生成PDF” 链接,程序会使用用户输入的数据实时生成PDF投保单:

 

最后生成的PDF投保单如下:

 

2007年06月25日

最近做一个软件使用了MySQL数据库,并使用utf8编码来存储数据。期间遇到了一些问题,经过半天的努力找到了一个比较好的解法,觉得有必要写一下。

1. utf8 编码并不是unicode编码
unicode 使用一个16bits的整数来表示一个字符;utf8 则是和Latin-1/ISO-8859-1完全兼容的一种编码,它使用3bytes来表示一个汉字。例如,’宋江’的unicode编码为 ‘\u5b8b\u6c5f’ <type ‘unicode’>;而它的utf8编码为’\xe5\xae\x8b\xe6\xb1\x9f’ <type ’str’>

2.设置MySQL数据库使用unicode
确保你的MySQL配置文件my.ini的[client]和[mysqld]部分都设置utf8卫默认字符集
[client]
default-character-set = utf8
[mysqld]
default-character-set = utf8

使用 ’status’ 命令检查设置是否已生效

mysql>status
————–
mysql  Ver 14.7 Distrib 4.1.20, for Win32 (ia32)
Connection id:          45
Current database:       credit
Current user:           root@localhost
SSL:                    Not in use
Using delimiter:        ;
Server version:         4.1.20-community-nt
Protocol version:       10
Connection:             localhost via TCP/IP
Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    latin1
Conn.  characterset:    latin1
TCP port:               3306
Uptime:                 2 hours 13 min 1 sec

Threads: 2  Questions: 256  Slow queries: 0  Opens: 21  Flush tables: 1  Open ta
bles: 0  Queries per second avg: 0.032
————–

你可以看到下面两行是作用于服务器的
Server characterset:    utf8
Db     characterset:    utf8

而下面两行是作用于客户端连接的
Client characterset:    latin1
Conn.  characterset:    latin1

你可以在mysql 命令行下运行 set names utf8 将其设置为 utf8 编码。

3.修理 MySQLdb
最大的问题存在于 MySQLdb 库中,简而言之是 conn.character_set_name() 的行为不可预测。
在 cursors.py execute 方法中会对被执行的sql使用conn.character_set_name()进行编码。
设想一下,如果我们从浏览器提交上来的数据是Unicode编码的,而conn.character_set_name()返回 ‘utf8′ 那么MySQLdb会将Unicode数据正确的转换为utf8数据,那是再好不过了。而实际上如果我们传入unicode对象,conn.character_set_name() 会返回’Latin-1′,而如果我们传入 str 对象conn.character_set_name()会返回’ascii’。这就是问题的根源。

较好的解决方法是:
1.将浏览器提交上来的数据解码为unicode对象
2.覆盖 conn.character_set_name() 方法让它总是返回 ‘utf8′

第1步就不说了,关键是第2部,代码如下:
conn = getConnection ()
def character_set_name (*args, **kwargs): return ‘utf8′
import new
conn.character_set_name = new.instancemethod (character_set_name, conn, conn.__class__)
print conn.character_set_name()
>>>’utf8′

看起来和Delphi的Delegate 方式比较象吧?

2006年08月31日

自动搜索,绘制最短路径沿线的地名的注记。下图显示了从张江高科技园到上海火车站路径沿线附近的地名。


2006年08月23日

This electronic map is used to search the shortest path between two sites in a Chinese city.

How to use it?

1. Select the map of your city from the dropdown list.
2. Input the site name of your current location in text box "当前所在地". You can input just part of the name, the application will search the database for the site name on key press basis. Just like Google suggests.  The alternatives are list below the text box, you can click on the site in the list to fill it in the text box. see Figure 1.
3. Input the site you want to go in the text box "目的地"  as in step 2.
4. Then click the button "计算路径", the application will generate and send you a map(a JPEG image) on you input. See Figure 2.

Figure 1 Input/find the source and target site name


Figure 2 Generate Map on your input

2006年02月20日

毕业典礼上的演讲大都轻松愉快,而且容易被遗忘。然而,史蒂夫·乔布斯(Steve
Jobs)2005年6 月在斯坦福大学的演讲在经过了一个夏天之后依然为人所提及。这位苹果电脑公司(Apple
Computer)和皮克斯动画公司(Pixar Animation
Studios)首席执行官在演讲中谈到了他生活中的三次体验,这三次体验不仅在斯坦福大学的毕业生、也在硅谷乃至其他地方的技术同行中引起了巨大反响。
他们将他的演讲登在互联网上,在博客上展开讨论,通过电子邮件互相发送,在全球传阅。  
 
 

    很荣幸和大家一道参加这所世界上最好的一座大学的毕业典礼。我大学没毕业,说实话,这是我第一次离大学毕业典礼这么近。今天我想给大家讲三个我自己的故事,不讲别的,也不讲大道理,就讲三个故事。
    第一个故事讲的是点与点之间的关系。我在里德学院(Reed  College)只读了六个月就退学了,此后便在学校里旁听,又过了大约一年半,我彻底离开。那么,我为什么退学呢?
    
这得从我出生前讲起。我的生母是一名年轻的未婚在校研究生,她决定将我送给别人收养。她非常希望收养我的是有大学学历的人,所以把一切都安排好了,我一出
生就交给一对律师夫妇收养。没想到我落地的霎那间,那对夫妇却决定收养一名女孩。就这样,我的养父母─当时他们还在登记册上排队等著呢─半夜三更接到一个
电话: 
    “我们这儿有一个没人要的男婴,你们要么?”“当然要”他们回答。但是,我的生母后来发现我的养母不是大学毕业生,我的养父甚至连中学都没有毕业,所以她拒绝在最后的收养文件上签字。不过,没过几个月她就心软了,因为我的养父母许诺日后一定送我上大学。
    17 
年后,我真的进了大学。当时我很天真,选了一所学费几乎和斯坦福大学一样昂贵的学校,当工人的养父母倾其所有的积蓄为我支付了大学学费。读了六个月后,我
却看不出上学有什么意义。我既不知道自己这一生想干什么,也不知道大学是否能够帮我弄明白自己想干什么。这时,我就要花光父母一辈子节省下来的钱了。所
以,我决定退学,并且坚信日后会证明我这样做是对的。当年做出这个决定时心里直打鼓,但现在回想起来,这还真是我有生以来做出的最好的决定之一。从退学那
一刻起,我就可以不再选那些我毫无兴趣的必修课,开始旁听一些看上去有意思的课。 
    那些日子一点儿都不浪漫。我没有宿舍,只能睡在朋友房
间的地板上。我去退还可乐瓶,用那五分钱的押金来买吃的。每个星期天晚上我都要走七英里,到城那头的黑尔-科里施纳礼拜堂去,吃每周才能享用一次的美餐。
我喜欢这样。我凭著好奇心和直觉所干的这些事情,有许多后来都证明是无价之宝。我给大家举个例子:

    当时,里德学院的书法课
大概是全国最好的。校园里所有的公告栏和每个抽屉标签上的字都写得非常漂亮。当时我已经退学,不用正常上课,所以我决定选一门书法课,学学怎么写好字。我
学习写带短截线和不带短截线的印刷字体,根据不同字母组合调整其间距,以及怎样把版式调整得好上加好。这门课太棒了,既有历史价值,又有艺术造诣,这一点
科学就做不到,而我觉得它妙不可言。
    当时我并不指望书法在以后的生活中能有什么实用价值。但是,十年之后,我们在设计第一台
Macintosh计算机时,它一下子浮现在我眼前。于是,我们把这些东西全都设计进了计算机中。这是第一台有这么漂亮的文字版式的计算机。要不是我当初
在大学里偶然选了这么一门课,Macintosh 计算机绝不会有那么多种印刷字体或间距安排合理的字号。要不是 Windows
照搬了Macintosh,个人电脑可能不会有这些字体和字号。要不是退了学,我决不会碰巧选了这门书法课,个人电脑也可能不会有现在这些漂亮的版式了。
当然,我在大学里不可能从这一点上看到它与将来的关系。十年之后再回头看,两者之间的关系就非常、非常清楚了。 
    你们同样不可能从现在这个点上看到将来;只有回头看时,才会发现它们之间的关系。所以,要相信这些点迟早会连接到一起。你们必须信赖某些东西─直觉、归宿、生命,还有业力,等等。这样做从来没有让我的希望落空过,而且还彻底改变了我的生活。
    
我的第二个故事是关于好恶与得失。幸运的是,我在很小的时候就发现自己喜欢做什么。我在 20 岁时和沃兹(Woz,苹果公司创始人之一 Wozon 
的昵称─译注)在我父母的车库里办起了苹果公司。我们干得很卖力,十年后,苹果公司就从车库里我们两个人发展成为一个拥有20 亿元资产、4,000
名员工的大企业。那时,我们刚刚推出了我们最好的产品─
Macintosh 电脑─那是在第 9 年,我刚满 30
岁。可后来,我被解雇了。你怎么会被自己办的公司解雇呢?是这样,随著苹果公司越做越大,我们聘了一位我认为非常有才华的人与我一道管理公司。在开始的一
年多里,一切都很顺利。可是,随后我俩对公司前景的看法开始出现分歧,最后我俩反目了。这时,董事会站在了他那一边,所以在30岁那年,我离开了公司,而
且这件事闹得满城风雨。我成年后的整个生活重心都没有了,这使我心力交瘁。
    
一连几个月,我真的不知道应该怎么办。我感到自己给老一代的创业者丢了脸─因为我扔掉了交到自己手里的接力棒。我去见了戴维•帕卡德(David
Packard,惠普公司创始人之一─译注)和鲍勃•诺伊斯(BobNoyce,英特尔公司创建者之一─译注),想为把事情搞得这么糟糕说声道歉。这次失
败弄得沸沸扬扬的,我甚至想过逃离硅谷。但是,渐渐地,我开始有了一个想法─我仍然热爱我过去做的一切。在苹果公司发生的这些风波丝毫没有改变这一点。我
虽然被拒之门外,但我仍然深爱我的事业。于是,我决定从头开始。
    虽然当时我并没有意识到,但事实证明,被苹果公司炒鱿鱼是我一生中碰到的最好的事情。尽管前景未卜,但从头开始的轻松感取代了保持成功的沉重感。这使我进入了一生中最富有创造力的时期之一。 
    
在此后的五年里,我开了一家名叫
NeXT的公司和一家叫皮克斯的公司,我还爱上一位了不起的女人,后来娶了她。皮克斯公司推出了世界上第一部用电脑制作的动画片《玩具总动员》(Toy
Story),它现在是全球最成功的动画制作室。世道轮回,苹果公司买下 NeXT 后,我又回到了苹果公司,我们在 NeXT
公司开发的技术成了苹果公司这次重新崛起的核心。我和劳伦娜(Laurene)也建立了美满的家庭。
    我确信,如果不是被苹果公司解雇,这
一切决不可能发生。这是一剂苦药,可我认为苦药利于病。有时生活会当头给你一棒,但不要灰心。我坚信让我一往无前的唯一力量就是我热爱我所做的一切。所
以,一定得知道自己喜欢什么,选择爱人时如此,选择工作时同样如此。工作将是生活中的一大部分,让自己真正满意的唯一办法,是做自己认为是有意义的工作;
做有意义的工作的唯一办法,是热爱自己的工作。你们如果还没有发现自己喜欢什么,那就不断地去寻找,不要急于做出决定。就像一切要凭著感觉去做的事情一
样,一旦找到了自己喜欢的事,感觉就会告诉你。就像任何一种美妙的东西,历久弥新。所以说,要不断地寻找,直到找到自己喜欢的东西。不要半途而废。 
    
我的第三个故事与死亡有关。17岁那年,我读到过这样一段话,大意是:“如果把每一天都当作生命的最后一天,总有一天你会如愿以偿。”我记住了这句话,从
那时起,33年过去了,我每天早晨都对著镜子自问:“假如今天是生命的最后一天,我还会去做今天要做的事吗?”如果一连许多天我的回答都是“不”,我知道
自己应该有所改变了。
    让我能够做出人生重大抉择的最主要办法是,记住生命随时都有可能结束。因为几乎所有的东西─所有对自身之外的希求、
所有的尊严、所有对困窘和失败的恐惧─在死亡来临时都将不复存在,只剩下真正重要的东西。记住自己随时都会死去,这是我所知道的防止患得患失的最好方法。
你已经一无所有了,还有什么理由不跟著自己的感觉走呢。
    大约一年前,我被诊断患了癌症。那天早上七点半,我做了一次扫描检查,结果清楚地
表明我的胰腺上长了一个瘤子,可那时我连胰腺是什么还不知道呢!医生告诉我说,几乎可以确诊这是一种无法治愈的恶性肿瘤,我最多还能活3 到 6
个月。医生建议我回去把一切都安排好,其实这是在暗示“准备后事”。也就是说,把今后十年要跟孩子们说的事情在这几个月内嘱咐完;也就是说,把一切都安排
妥当,尽可能不给家人留麻烦;也就是说,去跟大家诀别。
    那一整天里,我的脑子一直没离开这个诊断。到了晚上,我做了一次组织切片检查,他
们把一个内窥镜通过喉咙穿过我的胃进入肠子,用针头在胰腺的瘤子上取了一些细胞组织。当时我用了麻醉剂,陪在一旁的妻子后来告诉我,医生在显微镜里看了细
胞之后叫了起来,原来这是一种少见的可以通过外科手术治愈的恶性肿瘤。我做了手术,现在好了。
    这是我和死神离得最近的一次,我希望也是今
后几十年里最近的一次。有了这次经历之后,现在我可以更加实在地和你们谈论死亡,而不是纯粹纸上谈兵,那就是:谁都不愿意死。就是那些想进天堂的人也不愿
意死后再进。然而,死亡是我们共同的归宿,没人能摆脱。我们注定会死,因为死亡很可能是生命最好的一项发明。它推进生命的变迁,旧的不去,新的不来。现
在,你们就是新的,但在不久的将来,你们也会逐渐成为旧的,也会被淘汰。对不起,话说得太过分了,不过这是千真万确的。
    你们的时间都有
限,所以不要按照别人的意愿去活,这是浪费时间。不要囿于成见,那是在按照别人设想的结果而活。不要让别人观点的聒噪声淹没自己的心声。最主要的是,要有
跟著自己感觉和直觉走的勇气。无论如何,感觉和直觉早就知道你到底想成为什么样的人,其他都是次要的。
    我年轻时有一本非常好的刊物,叫
《全球概览》(The Whole Earth Catalog),这是我那代人的宝书之一,创办人名叫斯图尔特•布兰德(Stewart
Brand),就住在离这儿不远的门洛帕克市。他用诗一般的语言把刊物办得生动活泼。那是 20
世纪60年代末,还没有个人电脑和桌面印刷系统,全靠打字机、剪刀和宝丽莱照相机(Polaroid)。它就像一种纸质的Google,却比
Google 早问世了 35 年。这份刊物太完美了,查阅手段齐备、构思不凡。
    斯图尔特和他的同事们出了好几期《全球概览》,到最后办不下去时,他们出了最后一期。那是 20 世纪70年代中期,我也就是你们现在的年纪。最后一期的封底上是一张清晨乡间小路的照片,就是那种爱冒险的人等在那儿搭便车的那种小路。照片下面写道: 
    好学若饥、谦卑若愚。那是他们停刊前的告别辞。求知若渴,大智若愚。这也是我一直想做到的。眼下正值诸位大学毕业、开始新生活之际,我同样愿大家:   好学若饥、谦卑若愚。
    谢谢大家。
    

转自《财富》中文版 译者: 于少蔚

2006年02月12日

最明显的区别是:DIV是块元素,SPAN是内嵌元素。块元素相当于内嵌元素在前后各加一个<br>换行。其实,块元素和行内元素也不是一成不变的,只要给块元素定义display:inline,块元素就成了内嵌元素,同样地,给内嵌元素定义了display: block就成了块元素了。
具体步骤:

<style>
div,span{border:1px solid #f00;margin:2}
</style>
<div>div1</div><div>div2</div>
<span>span1</span><span>span2</span>
<br>
<div style="display:inline">div3</div>
<div style="display:inline">div4</div>
<span style="display:block">span3</span>
<span style="display:block">span4</span>

特别提示
本例代码运行效果(点运行代码)所示,为了更能说明问题,这里给块元素和内嵌元素都加了1像素宽的红色实线边框,从图中可以看到, DIV默认为块元素,定义display属性值为inline后以内嵌元素显示,而SPAN默认为内嵌元素,定义display属性值为block后则以块元素显示。
特别说明


http://www.dnxh.cn/blog/article.asp?id=113

2006年01月28日

今天,国外著名网站 (http://sourceforge.net) 被封掉。需要继续访问者请进入http://translate.google.com/translate_t,在Translate a web page栏里输入 http://sourceforge.net,然后回车即可。

2006年01月26日
package threading;

public class Foo {
private final SyncQueue fQueue = new SyncQueue();

synchronized public Object get() {
fQueue.dequeue(); // this call will block if fQueue is empty.
// Since put(o) is also synchronized, you have no
// chance to make a call to enqueue(o).
// So, any thread call to get or put will block
// forever.
}

synchronized public void put(Object o) {
return fQueue.enqueue(o);
}

}



package threading;

public class Foo {
private int a, b;
private Object aLock = new int[0]; // lock for a
private Object bLock = new int[0]; // lock for b

public void bar() {
synchronized( aLock ) {
synchronized( bLock ) {
a = 1;
b = 1;
}
}
}

public void tar() {
synchronized( bLock ) {
synchronized( aLock ) {
a = 2;
b = 2;
}
}
}
}

Deadlock occurs when one thread aquired aLock and try to acquire bLock in bar() method, another thread calling tar() method acquired bLock and try to acquire aLock.


package threading;

public class Foo extends Thread {
private int a = 0, b = 0;

synchronized public void run() {
while( true ) {
System.out.println("a=" + a "; b=" + b);
sleep(100);
}
}

synchronized public void modify( int value ) {
a = value;
b = value;
}

public void static main(String[] args) {
new Foo().start();
}
}

Since run() is synchronized , after the Foo starts the monitor are locked, any other thread make call to modify will wait forever to acquire the lock on the monitor.