61阅读

81道变态逻辑题-日本81道变态逻辑题,答出越多越变态31-40

发布时间:2018-01-01 所属栏目:pki ca

一 : 日本81道变态逻辑题,答出越多越变态31-40

31、井
有一天,因为觉得妹妹的哭声非常的吵耳所以把她杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却消失了
5年后,因为一点小争执所以把朋友杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却消失了
10年后,因为被一个在酒醉后不小心令她怀孕的女人缠上所以把她杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却消失了
15年后,因为上司的责骂所以把他杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却消失了
20年后,因为厌倦照顾那个行动不便的母亲所以把她杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却没有消失
第三天、第四天,之后每一天都去看...
尸体都没有消失


瑜小七楼号: 75# 时间:2011-11-18 17:08
31、因为母亲疼爱儿子
所以把所有的尸体都处理掉了
可是... 却处理不了自己的尸体

瑜小七楼号: 76# 时间:2011-11-18 17:08
32、一家三口
有一家三口刚搬进他们的新家
虽然有些老旧,不过能够找到如此便宜的平房十分难得啊!
一直以来都住在空间狭小的公寓
如今甚至还有个小庭院,能搬到这里真的是太好了!
一家人就这样在新家开始生活
大约一个月后
有一天夜晚,妻子又开始说出
「我觉得这房子有问题!」这样的话
这不是第一次了!
「一定又是你想太多了吧?
虽然这间房子很便宜,但并不表示....」
丈夫还未说完,就发现妻子的脸色不太对劲
妻子脸色铁青望向窗外的庭院
只见男孩很开心的在庭院里玩着
丈夫也看了看窗外
「你到底怎麽啦!根本没什麽特别的吧?」丈夫说。

瑜小七楼号: 77# 时间:2011-11-18 17:08
32、文章开始只说是一家三口,但没有说明家庭成员是哪些人
事实上夫妇两人并没有孩子,妻子能看到的男孩丈夫却看不到
这表示....

二 : 81道变态逻辑题-转

太变态了,很刺激。[www.61k.com]
1、年龄
我搭上了一列特快车,大概在还差10分就午夜12点的时候,在中途站有一名男子也上了列车,他在车门关闭后,像是突然回复意识一般,开始左右环视着周遭乘客的脸。
“恕我愚昧,请问您今年28岁吗?”他如此的向我问道,“是的,不过您怎么知道呢?”
我如此反问他,但被他无视,只是自顾自的和别人说话。
“您今年45岁吧?”
“是没错。”
“您是62岁吗?”
“你怎么知道的?”
一直和看似不相识的乘客群重复着诸如此类的对话,看来这名男子,似乎有着只要看着别人的脸就能知道其年龄的特殊能力。
此时到下个停车站还有15分钟左右的时间,全车箱包括我在内的乘客都对这名男子投以好奇的注目眼光,一直到他问到最后一名女士。
“您是50岁吗?”
“是的,不过还有五分钟就51岁了!”那名女士如此微笑的回答道。

1、答:那名男子所有的能力不是看到对方年龄,而是寿命。该女士5分钟后便51岁,而距离下一站还有15分钟,意味着接下来5分钟之内全车的人都会死于重大列车事故。

2、外遇者
有个之前一起工作的前任工作伙伴最近转职到我的所属职场工作,因为彼此都是已婚男人,从以前就常一起出去游玩或喝酒谈天,于是便约他去附近的茶馆叙叙旧。
我问他:“最近在干嘛,在赚什么黑心钱啊?”他闻言笑了笑,开始畅谈他过去的经历。
大概在一年多前他邂逅了一名小他十岁的女子,在耶诞节假期他22、23、24、25都是在她公寓家里度过的。当然连续4天不回家的结果,使得他自己家人闹到
差点没报警,再说他也深觉得对不起自己的小学女儿。于是在25日的晚上七点他坚决要回家去,结果那女人却哭叫着恳求他别走。
最后两人大吵一架,他也因此不顾一切的留下她直接进入11楼的电梯下到1楼离开。
“真没想到……”他又是笑了笑,说道:“等我走出公寓大门,她竟然已经在外头等我了……”

2、答:她直接从11楼跳下去,死在他眼前。

3、巴士
一对夫妇带着小孩,搭乘着往乡下的观光巴士准备回妻子的乡下老家游玩,当巴士开到山区路段间时,因为他们的小孩直吵着肚子饿,于是央不过孩子的夫妇只好请司机让他们中途下车,先在附近找了间快餐店解决一餐。
当他们酒足饭饱后,餐厅的电视播放出一则新闻快报,报导指出就在刚才有一辆在某山区行驶的乡间游览车,刚好被山上的落石击中而造成全车人员死亡无一幸存的惨剧,仔细一看,那就是他们刚才搭的巴士!
看着这则新闻,妻子喃喃的说到:“要是刚才我们当前没有下车就好了……”
听她如此一说,丈夫怒道上:“说什么傻话,要是我们当前没下车……”
语音未落,他也懂了妻子言中之意,“啊啊,是啊,要是我们当前没下车就……”

3、答:如果他们一家当时没下车,那么巴士便不会停下来耽误一些时间,也就不会刚好被落石砸中。

4、婴儿
在某妇产科医院有一名妇人生下了一个宝宝,当天半夜护士去婴儿房巡视情况,意外发现该婴儿已经全身冰冷无呼吸,死亡了。
知道此事后的院方决定隐瞒此事,用一个也才刚出生没几天的孤儿婴儿取代那名死婴。在生产时那名产妇并无意识,也还没见过自己的亲生孩子,因此理论上以还看不出特征的婴孩取代是万无一失的。
隔天,院方安排该产妇见到那名代替的婴儿,但她一看就发狂般的大喊:“这不是我的宝宝!”

4、答:那名产妇亲手杀死了自己的孩子。

5、流浪汉
我是个常搭纽约地铁的通勤族,每天早上通勤时都会在地铁内看到一个口中不知喃喃念着什么的流浪汉。因为好奇,我偷偷的靠在距离他很近的墙壁上偷听到了他言语的内容。
有个欧巴桑从他眼前通过,流浪汉悄声说道:“猪!”
这是什么啊?单纯把对方比喻成动物的坏话吗?
接下来经过的是一名寻常的上班族男士,“人!”他又这么说。
嗯,的确是个怎么看都是普通人的家伙没错啦。
隔几天自己闲着没事,又到地铁站去偷听那个流浪汉的碎碎念内容,他眼前经过了一位消瘦落魄的男人,“牛!”他这么说。
牛?怎么看都是像只消瘦的鸟吧?
接下来是个超肥胖的男人从他眼前经过,他说:“蔬菜!”
菜?不是应该是猪吗?
回家后,我仔细思考了其中的逻辑关系,或许他说的是那个人的前世,或者他将转世投胎变的东西?但之后几天我再度观察他的言行,总觉得要说是好像也不是。
终于有一天我按捺不住好奇心,直接去跟那流浪汉询问他的能力到底是什么,也向他请求获得他的能力的方法。流浪汉看了我坚决的眼神后,没说什么,只是把他的手掌放在我的头上。
从隔天起,那名流浪汉变从地铁从此消失了。
他是神吗?
还是仙人?
总而言之,我终于知道那项能力是什么,因为我已经得到那项能力,取代了那名流浪汉了。

5、答:那名流浪汉的能力是看出“某人上一个吃的东西”,开始是不是对某人说过“人”呢?

6、回家(原文第一人称为女性)
今天在公司又被上司给骂了,就是那个连在公司女同事之间风评也差到爆的老秃驴。
“唉唉,该不会最近老觉得有人追踪我的犯人也是那老贼秃吧?”我一面这样想着,一面抵达家门口。
虽然说是家,但其实也是个只有两个房间的老旧公寓,就只有起居室厨房和寝室,也只有起居室才有窗户,虽说是真的很便宜啦。
打开门锁进了房间,吓了一大跳,起居室的衣橱被翻乱了!
想起来了,今早吃完早餐出门时忘了锁门,就这样去上班……
啊啊……窗户都有锁上,也就是说一定是从玄关侵入的!
感觉好差劲!真让人不爽!好想去死!
算了,今天已经这么累了,晚饭也别吃了,明天再报警吧!
我再次确定玄关已经锁上,往寝室走去。

6、答:文中所述主角回家时,家门是锁上的,但早上又没锁,这显示,侵入者此时就在家中。

7、家族
“唉,还没好吗?”我面向背对着我的老婆这么问,为什么女人在准备的时候都要花这么久时间?
“快好了,不必那么急嘛,你看看你,一副焦躁不安的样子,小翔,别再乱动了喔。”
她说得没错,我天生就这副急性子,没办法。
我从西装口袋取出香烟,点上火。
“突然回去他们那,公公和婆婆不知道会不会吓一跳呢?”
“哪会,看到孙子都这么大了,他们一定笑得合不拢嘴!”我看着一旁睡熟的儿子翔,如此回答她。
“久等啰,好了,啊……”
“嗯,怎么了?”
“老公,你这里啦!”
老婆指着我的脖子,我伸手一摸,“啊!忘了!”
“老公真是的,不但焦躁还冒失,过来我帮你。”
“老公,我爱你。”老婆一边帮我整理着脖子周围。
“干嘛突然讲这个?”
“有什么关系呢?我们当前是夫妇嘛!”老婆她往下逃避我的视线,似乎在害羞着。
“嗯,我也爱你。”不知道已经有几年没讲得这么露骨了。
虽然有点害羞,但感觉倒也不坏,我握着老婆的手。
“那么走吧!”
“嗯!”

7、答:一开始“还在乱动”的孩子下一幕已睡熟,是因被老婆强灌了过量安眠药,老婆提醒主角忘了和整理主角脖子周围的是上吊的绳子,这是一个一家携子自杀的主观叙事。

8、掉下
在末班电车上睡着的我醒过来的时候,发现有个陌生的女孩将头靠在我的肩膀上沉睡着。
她留着黑色长发,给人感觉还挺可爱的,而且也不像贞子那种阴森的黑长发,算得上个美人。
我并不排斥现在这种状态,再说距离我要下车的站还有段时间,所以就暂时维持这样吧。
又过了几个车站,终于全车厢只剩下我跟这名女孩,她要在哪一站下车?应该先把她叫醒吗?
我一边这么盘算,一边不自觉的准备挪动身体。
“不要动……”头靠在我肩上的女孩闭着眼睛,轻轻的说。
“我还想再这样下去一下……”她这么说。
虽然这样的话对初次见面的男人说感觉很微妙,但我也没不解风情到会在这种情况问她理由的程度,也就这样让她靠着了。
不过,再怎么说我要下车的站也快到了,有点让人担心,总之先问问她吧。
“呃,你要下去的站是哪一站呢?”
“我掉下去的站?”她回问。
“不是,是你要下车的站,哪一站?”
“下车的站就是掉下去的站。”她吐出了这段意义不明的回答。然后似乎是看我满脸问号的样子,又回道:“你下车的站,就是我掉下去的站。”
难不成……她想自杀?
想在我下车的那一站跳下月台自杀!
一察觉这个可能的我,立刻试着告诉她,“不能掉下去!”
“你下车的话,我就会掉下去。”她回答。
这虽然是某种程度的威胁,但首要是不让她自杀,没办法。“好,我不下车了。”我只好这样回答她。
她立即露出愉悦的笑容:“谢谢你,就这么约定了喔,不过,要是违反约定,那你也会一起下去喔!”
听她这么一说,我不禁感到背后一阵凉意,不过现在当务之急是使她镇定下来,所以我就:“嗯,说好了!”
就在此时,电车剧烈的摇晃了一下。
在那瞬间,我终于完全理解了她那看似完全无法理解的言行了。
但已经迟了,她掉下去,而我也跟着掉下去了。

8、答:将头靠在主角肩上的那个女“人”的头,是断掉的。

9、在非洲的摄影记事
那是我在非洲拍摄风景时发生的事,我当时用望远镜看到很远的一边的大树(不是猴面包树,普通的树木而已),有十个当地人待在那上头,望着下方。
我跟着看那下面,那下方有群狮子悠哉的待着,它们附近还掉落有一顶帽子。我再看看树上,那群人也都戴着跟那顶同样款式的帽子。
“哈哈,真倒楣的家伙,帽子刚好掉在狮群附近,这下子捡不回来了。”我笑了笑,把望远镜转到别的方向。

9、答:也“都”戴着同样的帽子,表示没一个人帽子掉下去,也就是说原本掉下去的那名帽子的原主,已经被狮子吃掉了。

10、忍耐赛
我平日每天都会上澡堂去,而在洗完澡前进去三温暖好好流个汗更是例行公事。
在我刚进三温暖房才一分钟左右,有个男人也跟着进来,一较高下看看谁待比较久吧,在这男人出去之前我绝不出去,这也是我特有的习惯。
10分钟过了,对方是个看起来起码超过一百公斤的胖子。
15分钟过了,明明汗流得跟瀑布一样还不放弃,挺能撑的嘛,死胖子!
18分钟过了,终于那个胖子移动了身体,他摇摇晃晃的站起来,像是随时会不支倒地一般蹒跚的向三温暖房外走去。
赢啦!我情不自禁的在三温暖房内摆出胜利姿势!
………………………………..
当我恢复意识后,发现自己在一个陌生的房间内,有个老阿伯正瞅着我,那老阿伯就是澡堂的收费台服务的人。
他开口对我说:“我去检查的时候发现你就在三温暖外,靠着门坐倒着,已经丧失意识了!”
看来我是中暑了,好像有点逞强过头了吧。
阿伯继续感叹道:“把你扛到这里来可真累了我这身老骨头,下次多注意点啊!”
我向老伯再三道谢才回家,好好喝个啤酒就休息吧。

10、答:本篇文的分隔线前后,叙事主角是不同的。前段是一开始的主角,后段是那个胖子。胖子出去后便不支靠着门昏过去,使得前段主角根本出不来,而澡堂的老阿伯也只有发现中暑的胖子,也就是说前段主角此时还在三温暖房内。

11、弟弟
我曾经有个弟弟,虽然过往的记忆已经很模糊,但是我印象最深刻的就是跟弟弟分享爸爸给我的糖柑仔时,那份快乐的回忆。
只是好景不常,弟弟出生没几个月就死了,只是到现在还活在每一个家人的心中。

11、答:没有刚出生几个月就能吃糖球的婴儿,真正杀害了弟弟的就是当时年幼无知(或有知)的主角。

12、日记
1904年8月,我在家中发现了一本可疑的日记。
先说明下,我家是6年前结婚的妻子挑屋并购入的中古住宅,不过我妻子已经在前年和两个女儿一同在船难中丧生,两个女儿虽然在其两日后被冲上不同的两个海岸边,但还是没被救活。
前几天,因为要改造妻子的房间故请了木工师傅来,结果他交给我一本说是在妻子房间天花板内发现的日记本。
那本日记确实是妻子的笔迹没错,翻开看了看:
7
/ 15:从今天开始我就要老公你一起生活了。(那天是我跟妻子的结婚纪念日啊。)
9 / 21:这是因为你才有了现在的我。
12 /
9:尽管如此,我还是不会离开老公你的。
2 / 23:就快了喔!
2 /
29:你能够明白了吗?
当下我立即感到无比惊惧,立刻搬家到很远的地方去了。

12、答:注意文中日记最后一篇日期,说明了该文是在闰年所写,但是主角跟妻子结婚6年(1898-1904)间,只有1904年是闰年,这表示原本应该已经跟女儿在前年死亡的妻子,其实到现在还一直在主角家中(不论死活)。
注:闰年的公式是:年份非整百时,西元年份是4的倍数为闰年;年份逢整百时,西元年份是400的倍数为闰年,西元年份是100的倍数,则不闰(恢复平年)。故1900年并非闰年。
此外,虽然原文注解中没写,但其更深的寓意应该是妻女的船难由主角所策划(为了保险金之类的),但可能只有女儿罹难,生存但面目全非的妻子(也可能没生存)悄悄回来隐居家中,准备向主角复仇(日记第二篇开始)。

13、由美?
从学校回到家的我到厨房去倒了杯麦茶,边喝边想着在榻榻米地板下方的储纳空间中藏着母亲尸体的事。
在当时,我看到爸爸从隔壁房间出来,对我说:“由美?你妈妈她有了别的男人,想要抛弃你离开这个家,所以我跟她大吵了一架,失手杀了她……”说完已是潸潸泪下。
我并没有去**那检举爸爸的打算,而打算就这样跟爸爸相依为命。
正打算回房换个衣服,却在房间内发现撕成三片写有东西的笔记本碎片,是妈妈的笔迹,我试着将碎片上的字句拼凑起来。
“由美?快逃吧,爸爸,丧失理智了。”
如果是你的话,是会相信爸爸,还是妈妈呢?

13、答:由美本身是多重人格病患,妈妈为她的另外人格所杀,那张纸条是妈妈写给爸爸的,拼法应该是:“快逃吧,爸爸,由美?丧失理智了。”纸条中和爸爸称呼由美后的问号,表示不确定为由美的固有人格所加。 (上面的语序和题里的不一样,是日语语序?题设有问题?)
注:日本有未成年小孩的家庭,通常妈妈称呼丈夫的方式跟孩子一样。

14、梦境
我是个参悟了梦境之道的男人,拥有在自己的睡梦中完全自由行动且心想事成的特殊能力,因此我每晚的梦对我来说是个完全自由的乐园,唯一美中不足的是,我在其中会丧失五感中的嗅觉和味觉。
对于这样的我来说,每天一早起来就把还没忘记的梦境内容,记在我的“梦之笔记本”逐渐成了例行公事。
每当阅读之总会让我重温那无比的快乐,每当我跟睡在我一旁的弟弟谈到我的梦,以及给他看我的梦之笔记时,他总会羡慕万分。此时我总会告诉他:“那是你修行还不够哈!”
为了快速记录梦境,今晚也是一样瞒着弟弟把笔记本和钢笔放枕头边,躺进了被窝。
等我回过神来发现自己正身处战场,四处都是此起彼落的枪炮和子弹擦过的声响。“呵呵,来个这种梦也不坏,大开杀戒吧!”我捡起了散落脚边的枪枝,开始对准目标狂射一气。
但意外的是,感觉实在不太爽快,于是我集中精神,开始想起下一个梦境。
眼看着我的枪逐渐由内而外变化成日本刀,感觉十分称手,立刻举刀向眼前的敌人劈砍过去。
感觉太爽啦!想不到劈人是这么有快感的事,我忘情的挥砍着,直到把敌人刺得像个蜂窝,眼看他悲鸣着弥漫着浓烈血腥倒下身子,我仍毫不在意的继续劈刺。
不久我终于感到充分的满足,好了,差不多可以离开梦境醒过来了,得赶快把这事记在我的梦之笔记才行呢。

14、答:一开始便表示在梦中是没有嗅觉味觉的,那么为何能感受到“弥漫着的浓烈血腥”?显然起因是主角把梦境和梦游症错乱掉,糊里糊涂的刺杀了睡在他一旁的人(弟弟)。

15、诅咒
我终于从某处获得了传说中的“诅咒真书”。
翻开来,里头开头第一句话就是:“若按照本书中所记载的步骤实施,便可成功的咒杀你所希望的对象,但是若步骤有出一点错,
那么这个咒杀令便会反噬到施咒者身上!即便如此你仍要继续吗?”
废话!
就是因为我有个绝对饶恕不得的仇人,所以才费尽千辛万苦拿到这本诅咒真书的,我开始阅读并实行其书上的指令:
“1、请先闭上你的眼睛,专心回想你想要咒杀的对象的脸。”
那家伙的脸……我想忘也忘不了的,立刻闭上眼回想他的面容特征,再来是什么呢?
“2、接着请仔细的想像该如何咒杀他的方式。”
我立刻把脑海中所有能想到的痛苦死法都回想一遍,再来呢?
“3、最后更新请睁开眼睛。”

15、答:从第一个步骤到第三个步骤间,并没有第二个“睁开眼睛”的说明,也就是说得闭眼后直接实行步骤一和二后,才能睁开眼,主角已经在步骤二之前错误的先实行步骤三了(他睁开眼睛看书上的步骤了)。

16、日记
在某个午后
许多小鸟出没的森林中,一个小女孩飞也似地走着
「妈妈,你在哪里啊?」
小女孩大声的叫着,但是却没有回应
在这之中,少女不知不觉来到一间房子前
「妈妈,你在这里吧?」
小女孩若有所知的打开房子的大门一看
赫然发现房子里面什么都没有,只有一本日记
5月16日
明天是很快乐的圣诞节,会收到很多礼物
一定是个快乐的一天
5月17日
圣诞老公公没来
圣诞老公公没来
圣诞老公公没来
5月18日
昨天真的很快乐
因为从圣诞老公公那里拿到了一份礼物
不过,好奇怪喔。这份礼物要放在哪里才好呢?
9月33日
时钟的指针慢慢的、慢慢的接近了
12月65日
今天,终于能够去外面了
而且外面的人好多喔
数不尽、简直是数不尽的异常的锁
但是每个人的脸色看起来都显得很奇怪
这是为什么呢?
小女孩看到这里突然把日记盖上,因为她发现了一件事……
是的,小女孩她终于发现……

16.答:一个女孩[妈妈]年纪很少就已经被[男人,妈妈的经手人]禁锢在森林内那间什麼都没有的[房子]里, 她从来未接触过房子内的世界,
与世隔绝(很多鸟栖息)
她一直被那男人强迫进行**, 那男人会带给她一定数量的补给物资,而她亦从性爱中得到快乐,
所以她其实心里很期待那男人的来临。
奇怪日子在日记上出现, 是因为她根本不知道历法这东西, 日子都只是那男人每次来到房子口述给她的,
而奇怪的日子就是因为那男人不是常来, 有时隔了很久也没来, 她於是只管一天一天的把日子加上去, 但不知道要进月....可是日子这概念,
那男人是有需要给她知道的, 下述她慢慢到了青春期, 那男人发现她开始来经了, 为了不想她怀孕, 於是那男人骗她, M come 当天是"圣诞节(红色)",
圣诞老公公(那男人)会来探她, 并带来礼物(如糖果, 男人的**), 而每28天就是一次"圣诞节"(正常之月经周期),
目的是方便男人自己在"安全期"进行**,然而, 女孩误会了每28天就必然是"圣诞节", 而根本不知"圣诞节"是由她来经所触发,
实际的来经日子也是不固定的....在受她"误报圣诞节"的影响, 再加上男人单纯用日子去推测经期, 她受孕机会亦慢慢增加....
5月16日,
那男人来了(或者5月16日之前那男人来了, 16日是自己加上来的), 目的是**
5月17日(她自行+1), 她心中的"圣诞节", 但那男人没来,
而M也没来, 因为她怀孕了
5月18日(自行+2), 男人没来, 她感受到男人的**留在她的体内,
然而她不知怎处理(礼物放在那里好呢)。
9月33日, 9月男人曾经来过, 她自行加了n天, 才会出现33日, 她开始感受到肚内的生命, 身体开始变化,
生产时间也开始接近了。
12月65日, 12月那男人曾来过, 只是男人知道她怀孕而事情已到了无法处理的状况, 那男人决定不再回去房子,
等她跟肚内的生命(文中的女孩)白白饿死在房子内, 而那男人已经没来最少一个月....在物资不足的情况下, 食物快耗尽(或已耗尽), 妈妈知道要想方法离开,
以保护肚内的生命, 终於在12月过了65天的这天, 她成功逃出房子, 她走进了城市, 人们看见她只十二三岁, 却大覑肚子, 而且身体虚弱苍白,
自然感到怪异了(数不尽的人, 面色却很奇怪)。
最后母女获救, 女儿长大开始懂事, 母亲把她的日记放回房子内, 带女儿来到森林, 引她进入房子阅读日记,
让女儿自己明白真相....(这结局可解释无故日记出现在空空的房子)。

17、逃
不会读书、也无法与人交谈。
这样的我、对谁来说都是不需要的。
在家中作为父亲的出气筒。对我的施暴更变本加厉。
真的很令人悲伤。
「我以为逃的掉的」
想逃离家、马上遭遇的。是比以往更加倍的殴打。
真的很讨厌无知的我。
怀孕中的母亲、跟姐姐有说有笑的准备晚餐。
这样辛苦的日子、今天是最后了吧。
意识慢慢模糊不清了。
这样应该会、照我期望的。大家、跟我…
阿阿、去死吧。照我期望的!
数月后
「是很健康的男孩呢!」
叔叔这样说了。
我并不是悲伤、却大声哭了起来。
睁开眼睛、有对男女看着我。
不知为什么很怀念的人。
男人用很温柔的声音说。
「你觉得逃的掉吗」

17、前半,“我”自杀了。但是又被转生到妈妈肚子里的婴儿身上去了.

18、杀人的哥哥
哥哥突然发狂了,接着杀了全家人。
但是这样的哥哥也立刻遭到逮捕,处以死刑了。
其中妹妹幸运的活了下来,整件事也因为过度的惊吓而丧失记忆。
失去了父母亲,没了记忆,行尸走肉般活下来的妹妹,有一天,遇上了一名占卜师。
于是开始占卜起自己的过去。
「为什么哥哥会突然发狂呢?」
「不,你的哥哥相当的冷静喔。」
「那为什么哥哥要杀了全家人。」
「不,你哥哥只杀了一个人。」
突然,妹妹一切都想起来了,开始啜泣。

18、哥哥顶罪,杀死父母的是妹妹。

19、宅配员
我和宅配员间的对话
「不好意思,我想请问这包裹的地址...」宅配员说
「喔喔,这个的话在B栋一楼喔。」我说
「谢谢你。」宅配员说
关上了门。
话说我的房间是C栋3楼呢。

19、送件的不会特地跑到三楼去问地址,之所以会问“我”是因为发件人就是“我”,明明就这么近为什么要用快件呢……

20、圣诞老公公
哇~谢谢爸爸"
"阿!!不是爸爸,是圣诞老公公给的,对吧
妈妈??"
"喝喝~~一定是这样的"
圣诞老公公
我最喜欢圣诞老公公了
我呀
如果长大的话也要成为圣诞老公公
今天我要一直玩
一直玩刚拿到的新玩具
"喀咚"
嗳,什么声音...
爸爸是圣诞老公公
妈妈是圣诞老公公
那圣诞老公公是谁...

我也是圣诞老公公
阿哈哈哈

20、女孩在窗外看到的是杀人犯,血衣=圣诞老人的红衣 而且她的父母与自己也全部被杀

21、女朋友
在成为大学生之后
终于展开了期待已久的独居生活
虽然只是很普通的公寓
但始终算是只属于我自己的城堡
但是其中有件事让我很在意
刚搬进来的时候地产经理跟我说过我的隔壁是有人住的
可是3个月以来我却从未见过我的邻居
这令我感到有点奇怪......
而更奇怪的是每天的深夜时分
隔壁总会传来一些有点压抑的女性笑声
且总是准时在凌晨3点钟传来
该不会是隔壁住了什么怪怪的女人吧?
有天我因为身体不适早退回家
刚好在窗户看到地产经理在带新客户看房子
我就走去问他关于邻居的事情
「嗯,你的邻居是跟你同龄的男孩子呢,而且好像是跟你同一所大学的,他现在应该在家吧」
我想了想后觉得应该去打个招呼
「你好......
我是住隔壁的......」
「嗯,有什么事吗?」(终于见到了!) 开门的是一个普通的男子
「没什么... 只是听地产经理说我们是上同一所大学的...
而且我们好像没见过面,所以想过来打个招呼」
「啊... 原来你也是XX大学的学生! 请多多指教!
因为我要去居酒屋打工的关系,所以常常都很晚才回家呢!」(原来如此!)
然后我们就开始闲聊......
「对了...
我经常会听到女生的声音......」
「喔,我的女朋友和我一起在居酒屋打工,有时下班后她会来我这里」(真的吗!!好羡慕啊!!!)
「嗯...
那么也请代我向你女朋友打个招呼」
「嗯! 有空的话也带你的女朋友一起过来喝喝酒吧!」(可恶!!我根本没有女朋友啊!!!!!)

21、故事开始时"我"说过每天深夜3点都会准时听到女性的声音
但是他的邻居却说他的女朋友只是有时候会来
所以"我"听到的女性声音和邻居女朋友的声音是不同的
另外邻居说"有空的话也带你的女朋友一起过来喝喝酒吧!"
为什麽邻居会认为"我"有女朋友呢?
理由是邻居也听到隔壁深夜发出的那女性声音
"我"与邻居之间那狭窄的墙壁中究竟有甚麽东西呢? (墙中女)

22、双胞胎姊妹
有一对双胞胎姊妹被绑架了
两姊妹的双眼和嘴巴都被犯人用胶带封住
犯人在姐姐的耳边低声说
「如果你尝试抵抗或者逃跑我就会杀掉你的妹妹」
然后犯人在妹妹的耳边低声说
「如果你尝试抵抗或者逃跑我就会杀掉你的姐姐」

22、为什麽犯人会懂得分辨双胞胎姊妹中谁是姐姐与谁是妹妹呢?
绑架犯是双胞胎的熟人

23、出勤的酒店
因为出勤的关系我与同事租住了一间酒店的房间
当时同事还有事要办今晚不会回来
因为我很胆小所以早早就上床睡觉
但是在深夜的时候我却听到「咯咯」的敲门声
「是酒店的职员吗?」我叫道却没人回应
我看着房门感到非常害怕
那个敲门声一直从深夜持续到黎明才停止
然后我立刻就去退房了
之后我和出勤回来的同事说起敲门声的事
「果然发生了呢」他这样说
他说这间酒店以前发生过火灾
有个人因为逃走不及被困在那个房间里
到现在还是找不到他的尸体或残骸
啊啊...
还好我可以打开那个房门呢......

23、鬼敲门,还是从里面,他就是那个被烧死的。

24、耳机
刚刚,那个价值8000元的耳机突然坏了
是因为我不断用最大音量听音乐的关系吧?
突然「啪嚓」一声就坏了
我生气地把它掷到那个价值4万元的电视上
然后立刻就后悔了
心想「不会就这样坏了吧」的我一边打开电视的电源
影像方面是没有问题可是却没有声音了
太差劲了
连4万元的电视都坏了
话说回来今天外面也出奇地安静呢
还是出去散步转换一下心情吧

24、真正坏掉的 是"我"的听力......

25、洗脸
差不多到了要出门的时间
看了一下时钟
已经快要黄昏了!
我却连脸都还没洗呢!
虽然觉得很麻烦但还是没有办法啊......
我打开洗脸盆的水龙头用清水把脸沾湿
然后把洗面奶倒在掌心
双手磨擦让它起泡
之后在两颊打圈按摩把洗面奶涂满脸上
排水管里一直传来「咕噜咕噜」的流水声
是时候把泡沫洗干净了
我用手去寻找水源
咦?在哪?为什么我的手碰不到任何水呢?
这时泡沫却流进我的眼睛
让我不能直接用双眼去找
水龙头...
水龙头在哪啊?
啊啊...
终于摸到水龙头了
我把水龙头打开让它流出清水
然后用水把脸上的泡沫洗干净
用毛巾把脸擦干
再把水龙头关掉
啊...
怎么感觉厕所的镜子看起来有点恐怖呢......
接着
我连胡子也还没剃
就从家里逃走似的跑出来了

25、"我"在整个洗脸的过程中
除了最后洗完脸之外
都没主动关过水龙头
在"我"满脸是泡的时候
究竟是谁把水龙头关掉了呢? ....水管里流出的血而不是水。

26、照片
在我生日的那一天
我在自己家里举办了一个派对
最后在大家的合照照片上
却拍到了奇怪的东西
在我们背后的衣柜里
有一个我从未见过
皮肤苍白、双眼通红的女人探出头来
朝我们的方向凝视着
我觉得有点不安
所以把照片拿去给一位灵能者鉴定
「这张照片并没有任何的灵气,所以并不是灵异照片」他这样说
啊啊...
还以为是灵异照片真是吓了我一跳呢...

26、既然确定不是灵异照片 那照片中柜子里是僵尸

27、无解难题
这是在某个小镇发生的事情。
有个男人在某个房间里被监禁了。
男人睁开双眼,听见了声音。
「给我从那个纸箱中找出两面相同的硬币」
眼前有一个很大的箱子,打开来看,里面有很多的硬币。
「如果找到两面相同的,用桌上的相机拍下那枚硬币。在找到以前不放你走。照片用那边的传真机发送。」
当然传真机除了被设定了的号码之外都无法传送。
男子在纸箱中全力的找寻。
然后找到了两面相同的铜板。
用要相机拍下照片用传真机送出的时候男人发觉了。

27、一个铜板不管怎麽用相机拍,都不可能同时拍到两面
意思就是说这个歹徒,打从开始就是想要把男子关到死

28、看星星
今晚的星空真是漂亮啊,让喜爱观星的我越看越有精神。
啊!忘了自我介绍,我是一个天文爱好者,回来乡下照顾父母。
乡下光害少,到了晚上田园小径鲜少有人经过,是观星的好地点。
放下手中的望远镜略作休息,咦?左边原本的绕手绳什麽时候被扯掉了?
「少年仔!价逆瓦(这麽晚)抵看星星喔。」一位粗壮男子突然出声,害我吓一跳。
定了一下神,看看眼前的男子叼烟穿着草鞋,可能是附近的农夫吧。
「少年仔,要烟吗?」面对着男子的烟盒,我手痒的讨了一根。
点火、吸烟,我跟男子聊了起来:「乡下真是平静啊!」
男子以清晰的语调说:「唉,哪里平静啊。最近在沟渠里捞到一具尸体,一位少年,手里还牢牢抓着一条带子,对了,你晚上看星星要小心点,千万不要掉到沟渠里了喔!」
我吐了一口烟,微笑的向男子道谢。
男子指了指我的望远镜,以眼神示意,我会意的把望远镜递给他。
他仔细看了望远镜,又笑笑的把望远镜还给我。
「你赶快回去睡吧!」男子踩熄还有二分之一的烟蒂,微笑的向我挥手道别。
疲累的我打了个哈欠,是啊,是该回去睡了。
已经,一辈子都没办法从这房间里出去。

28、 沟渠里的尸体是主角杀的,主角与少年起了冲突,打斗中少年扯下望远镜上的绳子。

29、蜡烛
湖上泛舟,说不定能邂逅一段意想不到的情缘。
女孩泛舟,到了湖中心船突然翻覆,一个男孩奋不顾身的跳下去救了她。
女孩很感激男孩,碰巧那天是女孩生日,女孩便邀请男孩与她一起过生日。
女孩跟男孩在餐厅吃饭,面对着生日蛋糕,女孩为了感谢男孩,让男孩吹熄蜡烛。
男孩鼓起勇气向女孩告白,女孩摇摇头:「你很勇敢,但是我比较喜欢聪明的人。」
男孩笑着跟女孩说:「你知道为什麽船会翻吗?」
女孩睁大了眼睛:「原来是你做的?」
男孩得意的笑了:「这样子我就证明自己的聪明了,可以当你的男朋友了吧?」

29、知道女孩为什麽让男孩吹熄蜡烛吗?因为女孩早就没气了。

30、汤姆与圣诞老人
汤姆很期待来自圣诞老人送来的圣诞礼物。
在汤姆早上起床之后,他看到圣诞树下放着三只礼物盒。
汤姆注意到圣诞老人正在窗户外面偷看着他,圣诞老人虽然对着他露出牙齿笑着,却一直注视着他。而汤姆虽然觉得有点不高兴,却也一边露出牙齿对着他笑着,一边来到礼物盒的旁边。
汤姆拿起了第一个礼物盒,此时圣诞老人笑得更开心了。
从第一个礼物盒里面,汤姆拿出了一条长裤。虽然汤姆觉得有点失望,但是还是继续打开第二个礼物盒。
这时候圣诞老人开始抱着肚子笑起来了。第二个礼物盒里面,汤姆从里头取出一颗足球。
汤姆渐渐地觉得不开心了,甚至有种被激怒的感觉。
最后,汤姆总算把第三个礼物箱,也就是最大的礼物盒打开了。
这时最大的礼物箱里面跑出了一台脚踏车,在脚踏车出来的同时,圣诞老人终于忍不住在外面的雪地上打滚并哈哈大笑。
而汤姆也终于忍耐不住,在圣诞树旁开始号啕大哭。

30、因为汤姆根本没有脚。

31、井
有一天,因为觉得妹妹的哭声非常的吵耳所以把她杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却消失了
5年后,因为一点小争执所以把朋友杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却消失了
10年后,因为被一个在酒醉后不小心令她怀孕的女人缠上所以把她杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却消失了
15年后,因为上司的责骂所以把他杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却消失了
20年后,因为厌倦照顾那个行动不便的母亲所以把她杀了
然后把尸体丢到屋外的井里
第二天再去看的时候,尸体却没有消失
第三天、第四天,之后每一天都去看...
尸体都没有消失
这个记得以前是作为一个感人故事看的= =||

31、因为母亲疼爱儿子
所以把所有的尸体都处理掉了
可是... 却处理不了自己的尸体

32、一家三口
有一家三口刚搬进他们的新家
虽然有些老旧,不过能够找到如此便宜的平房十分难得啊!
一直以来都住在空间狭小的公寓
如今甚至还有个小庭院,能搬到这里真的是太好了!
一家人就这样在新家开始生活
大约一个月后
有一天夜晚,妻子又开始说出
「我觉得这房子有问题!」这样的话
这不是第一次了!
「一定又是你想太多了吧?
虽然这间房子很便宜,但并不表示....」
丈夫还未说完,就发现妻子的脸色不太对劲
妻子脸色铁青望向窗外的庭院
只见男孩很开心的在庭院里玩着
丈夫也看了看窗外
「你到底怎麽啦!根本没什麽特别的吧?」丈夫说。

32、文章开始只说是一家三口,但没有说明家庭成员是哪些人
事实上夫妇两人并没有孩子,妻子能看到的男孩丈夫却看不到
这表示....
这表示啥??求解= =

33、超能力
某天,有一个住在地方的六岁小女童行踪不明。
不管怎麽找都找不到,**在各地配置临检也是始终都没找到。
P0LICE也放弃了。
一个月后,不肯放弃的父母重金请了在美国的有名透视能力者。
马上的双亲就要求透视女儿的下落。
透视能力者开始了透视。
好像明白了什麽的透视能力者说了一句
「这孩子很有精神」
这句话让父母非常的高兴。
「在这孩子的周围看到了许多豪华的家具,能清楚明白是在一个富裕的家里面」
虽然对这句话多少有点疑问感但还是很高兴。
然后母亲紧接着深入重点
「女儿现在在哪里?」激动的口调问
透视能力者说了一句
「你的女儿现在在世界各地」

33、小女孩早已死去,活着的是他的被切下贩售的器官

34、红色的房间
某地的女性确定考上了在东京的大学,以后要一个人住在东京。
在某公寓开始生活,意外的发现房间墙壁有一个小洞。
这个小孔似乎可以看穿到隔壁的房间,试着偷偷看了一下。
小孔的另一边是深红色的。
隔壁的房间会不会是贴了红色的海报呢,抱持这样想法的女大学生隔天隔天天也是这样偷看那个小孔。
不管怎麽看都一直是红红的,对隔壁的房间很在意的女大学生询问了公寓的房东。
「我隔壁的房间住着什麽样的人呢?」
房东回答
「你隔壁的房间住着一个感染眼疾的人喔」

34、当女大学生偶尔偷看的时候,看到的是隔壁正在偷窥她的红色眼睛

35、图书室
某个女孩子在地下室的图书室里费尽心力找到了她喜爱的书。
发现到那孩子的老师,在关上门之后就回去了。
今天是结业式,明天开始就是暑假。
门要从外面才能被打开,没有钥匙的话就没有办法出去。
那孩子用一种''因为有最喜欢的书陪伴,一点都不可怕''的心态
每天都写下了日记
暑假结束后老师前往地下室图书馆,发觉女孩已经死了。
读女孩所写下来的日记
「我一点都不觉得恐怖,因为有书陪伴着我。」
「不过只有一点真的很可怕,那个从钥匙孔看过来的眼睛真的很可怕...」

35、女孩一开始以为自己是被误锁,觉得只要等巡察的人看到她在里面就得救了。
而老师一直以为女孩是幽灵,把女孩反锁在图书馆后,每天只敢在钥匙孔偷看。
女孩看到钥匙孔中的恐惧的瞳孔,以为老师是变态把自己反锁在里面(或者以为外面是怪物),打消了求救的念头,故做坚强写下最后的日记。

36、红衣女
我住八楼
工作很忙碌,总是要弄到深夜才回去
觉得这短暂阵雨把肩膀弄湿的感觉还蛮舒服的
只不过,总是应该要明亮的电梯厅里却看到讨厌的昏暗
昏暗的理由马上就明白了
有一支萤光灯电线短路了
也不是只有今天才这样,这里的管理人员办事很没效率
电梯在一楼停下后,门打开让我吃了一惊
里面有人...背对着门一动也不动的站着
红色的蝴蝶结以及红色的连衣裙的高个女性
我在进去之前迟疑了一下,但又觉得要是不搭乘的话也很奇怪,就这样进去了
我背对着那个女人按下八楼的按钮
此时发现,这个女人没有按下她要去的楼层,我想大概是按失败了吧
真不想按下自己住的楼层
盯着楼层灯示,心想电梯的速度实在很慢
女人一直面向后方都没有动
到了八楼走出电梯,身后的女人也依然没变,始终面向着后方
回到房间里面稍微冷静下来冲了个澡
喝罐啤酒,想喝第二罐的时候发现冰箱已经空了
附近有一间便利商店。穿上拖鞋按下电梯按钮
门打开,那个女人还在里面
跟刚刚的情况一样,一直背向后面不动
这次我没有坐上电梯

36、那个红衣女在电梯上吊了 电梯在一楼的时候光线暗 男主把那女人上吊用的红绳看成发带了

37、越战
越战结束后返国的前夜,青年士兵打电话回家
「明天就能回去了,我想带个无依无靠的战友回去,能让他跟我们一起住在家里吗」
听到儿子能够回来的消息非常高兴的双亲,「当然没问题!」喜极而泣的回答
「但是,有件事情得要先讲,他在作战中误踩地雷,失去了一只手和一条腿,但即使如此我还是想带他回家」
听到这句话,双亲沉默下来
「如果只是几天的话还没关系,照顾残障者很辛苦的,在家里的期间,一起去找那位朋友的居所吧。你和我们都各自有自己的人生,要牺牲自己照顾那位朋友一辈子是不可能的」
儿子听完之后不发一语挂上电话
隔天,P0LICE打来了一通电话
退役士兵的父母被告知自己儿子从屋顶跳落坠死的消息
双亲看着尸体说不出话来,崩溃大哭

37、作战中失去手脚的是他们的儿子

38、山中小屋
某个雪山里吹起了暴风雪,四人不幸遇难了。
要是就这样下去的话一定会死,就在大家这麽想的时候,在前面看到了一间小屋。
近乎昏厥的四人在进到小屋后被雪崩吞噬了
虽然房子的主体健在,但是里面并没有电器设备和暖房设施,有的只有紧急用的食粮
如果睡着的话一定会冻死。只要撑到早上的话...
此时领队提桉玩个游戏
「四人全员在小屋里的四个角落分别坐着,由我开始每五分钟往左边走,到下一个角落后把人叫起来重复刚刚的动作」
隔天早上,救难队找到了山中小屋。累坏了的四人露出笑容。
救难队员「亏你们居然全员没事啊」

38、这游戏四个人玩不了,有东西混进去了

39.灵异照片
某天跟朋友两个人聊天说着说着,就突然提到很久没去拍灵异照片了。
附近的山路里发生惨案的民宅现在还保存着。两个人晚上就前去了。
经过了玄关
客厅 浴室 厕所 厨房到了父亲的房间 走上楼梯往二楼去。
然后是小孩的房间 阳台 妈妈的房间 再回到一楼 两个人都走过一遍才离开
然后到了今天
看了洗出来的相片后我们都吓了一跳
什么也没照到。
我们当然是普通地拍
但是灵体之类的东西都没照到
「??不奇怪吗?」
「大概是已经成佛了吧」
「果然是这样啊 那样的话那里已经拍不到灵异照片了」
「不一定唷
我们去的路上不是有一家满孤立的民宅吗 下次去那里吧」
「喔喔! 真的吗? 那里也是废墟?」
「怎么可能 有人住着啦 今天晚上就去吧」
「OK
我知道了 今天我准备好就去吧」
真是期待啊 很久没体验了所以很兴奋呢

39、他们先杀人……再去拍照

40.星星天使
少女的面前出现了一位星星天使
"我可以实现你的任何一个愿望"
星星天使这么说。
少女哭着回答他
"请你让我的家人消失吧!那种家人
我一点也不想要!!"
第二天 少女醒来后走到一楼 像往常一样妈妈跟爸爸还有哥哥都在
少女后悔了。
那个夜晚
星星天使再次出现在少女面前
"还合你的意吗"
少女说"请你把我昨天的愿望消去吧"
"曾经实现的愿望是不能消去的喔"
少女哭泣了。

40、跟以前那个“婴儿喊谁谁死,喊爸爸结果隔壁叔叔死了”的笑话一样,哪些根本不是她真正的亲人,她真正的亲人无意间被她自己许愿害死了

41.脑死
确认脑死后的两个礼拜,他的皮肤连接了无数的接管,靠着人工呼吸器及点滴维持生命。
不过这也只是昨天的事了,他现在已经死了.
”非常抱歉。我已经尽力了...”医生用非常悲伤的表情这么说着。
当我抱着他的尸体时,非常地轻,他一定很痛苦吧。
不过,已经不用再痛苦了吧?因为已经解脱了。
”...不需要给我治疗费用”
发现到绝对不算是富裕的我的状况,真是个多么善良的医生啊。
”看着遗体很难受吧”医生盖上了白布。
”一切的回忆就跟他一起烧掉忘却吧”
这句话让我重振了起来
谢谢你,医生。

41、医生把病人全身的器官卖了,所以不用付钱

42.友人
友人「真的很抱歉」
我「喂
住手啊!」
友人「妹妹...我妹妹生病了....我需要钱」
我「你没事吧? 冷静下来」
友人「...谢谢...」
我「我这里有10万元
可以的话就借给你吧」
友人「真的很谢谢你...那个...怎么说呢」
我「我的晚餐还有剩
不介意的话就吃吧」
友人「谢谢...」
我「在说什么啊
我们不是好朋友吗?」
友人「其实我差点就想自杀了...多亏你」
我「别在意」
友人「这么晚真是抱歉啊」

42、一开始不懂,结果最后一句用那句结尾怪怪的……原来文章语序是倒过来的……

43.我跟太太
大概两年前,有个住在附近镇上的女孩跟我搭讪。
虽然是高中的同学个性也很好不过长相不是我的菜,我都优柔寡断的拒绝跟她交往。
那段时间我的工作也很不顺,坏事接二连三我的母亲也死于事故了。
我一点也不想被同情,所以完全没跟别人讲这件事一个人独自沉寂着。
母亲死去的那晚,那个女生打电话来。
"你的母亲似乎过世了..."
"...."
"虽然我之前也都没提过,我的母亲也过世了...就在昨天。从家里的楼梯上跌下来..."
"咦?"
"我们都一样呢"
...我似乎感觉被这句话救赎了
我觉得她一定能了解我
不需要被同情的心情
只是想要有人能依赖
被压抑的心情一次释放了出来,我大哭了一场。
连我的这种丑态她也愿意一起哭,不知不觉我就爱上她了。
这就是我跟太太相识的过程。

43、太太杀了妈妈

44.助理工程师
包柏?史密斯是我的助理工程师。他总是
专注在自己的份内的工作。另一方面包柏的同事
整天都沉浸在聊天打屁当中。浪费在公司的时间。包柏他
都很积极地在帮忙同事的工作。要是没有他的帮忙
工作绝对无法如期完成。不只如此,包柏他
在到休息时间之前,都埋在工作之中,其他的家伙
都在偷懒一直休息。包柏他对于职务与专门领域的知识
非常的丰富,但对这件事充满自傲的行为他
完全不会,如果包柏不在这个公司的话
工作就会停滞不前。如果改善对他的待遇
对公司是非常有益的。承前,请立即将包柏
提拔为我们公司的干部,请依此提案
处理
进行。
project leader上

44、断句换行很奇怪,到了后面完全不通了。其实是一个类似密码的方式,单数行看………其实这是一个杀人通知

45.忧郁的声音
有一个女性,因为感情的问题患上了忧郁症
在听信友人建议下,找上了某间医院赫赫有名的心理医生
女性在医生的心防突破下,告诉医生自己其实是因为男友的压迫,才会让自己心理闹出病来
「偷偷告诉你,只要握着我的手,我就能够听见你内心的声音」医生用认真关怀的表情对着女性说
女性虽抱持着疑虑,却也试着照着医生的指示握住他的手
医生在触碰到双手后不到一分钟,就沉重的表情注视女性说
「你若是继续和他在一起,一定会出事情的,请下定决心离开他吧」
过了两年后,这位女性在某一天自杀死身亡
女性的妹妹认为自己姊姊的死因不单纯,为了挖掘真相而找寻姊姊的主治医师
而医师在两年前早已经退休,搬到加拿大的别墅里过退休生活,妹妹登门表达自身来意
「医生请你告诉我,姊姊自杀的原因是什么!?」
妹妹握着医生的手,深切的期望医生能给她答案
「很抱歉,其实我并没有偷听内心声音的能力」医生心虚的回答
妹妹低下头用很难过的表情说「这样的话,姊姊到底是为了什么而死的...」

45、就是妹妹杀死了姐姐,为了试探医生是否知道真相,医生听到妹妹的心声,所以才心虚的回答说他没那个能力
【这个答案我很不解,果然是变态的思维方式么

46.小明和大明
小华前些日子生病住院了,好友小明跟大明决定去医院探望他
跟护士问到哪间病房后,得知小华住在私人高级病房
(病房前)
小明
: 「他把门锁上了..」
大明
:「那就敲门呀,笨喔」
(敲门)
过了10来秒,门才渐渐打开,小明跟大明则迫不及待的走进去看小华了
提着水果篮,发现小华坐在床上看着天花板发呆,于是小明跟大明就跟他打闹瞎起哄~
小华
: 「谢谢你们来探望我,我很开心...」
小明跟大明 :「朋友一场,哪需要那么客气~~」

46、要么房里有其他人,要么小华已经是鬼魂了

47.在雨中清洗双手
放学时候又下大雨了,我临时躲到一栋民宅的屋檐底下,虽然说是别人**,但现在这种时候,顾不得会不会麻烦别人了。我打开手机,屏幕一片漆黑。可恶!出门时明明阳光普照,就没带伞,手机也忘了充电,不能叫爸妈来载,真是失策。
「小弟弟,没带伞吗?」
过了大概几十分钟吧,背后的铁门打开,一个高瘦男人笑着对我问道。
是这间房子的住户吧?看着男人脸上的笑容,我尴尬的点点头。男人长得还不错,有混血儿的感觉,却无法明说是哪国血统。笑起来有浅浅的酒窝,头发旁分微卷,除了衣服有点不合身,过短且维宽之外,算是个帅哥。
「要不要进来躲雨?」他看着我说,微笑不减。雨声正大,看来短时间是不可能停了,「不会麻烦吗?」我问,虽然已经确定对方的答案,但该有的礼貌还是要有。
「不会,我也刚下班,就遇到这大雨。我知道这种感觉,没带伞很讨厌对吧。」他对我眨眨眼睛,表示心照不宣。我也对他微笑,点头:「谢谢哥哥。」
他把铁门打开,指引我走进。房子外观与一般民宅无二致,进去之后是个车库,一辆干净整洁的白色车子。伞桶在门右边,塞的满满的伞桶上方有一把突兀蓝色折迭伞;半开的鞋柜在门左边,里面各式鞋款也塞得满满的。
我正凝神思考,突然听到钥匙的声音,我回神,屋主,他钥匙掉到地上,他正弯腰捡起,笑着喃喃对我说了一句:「对不起,一个人住刚搬家还不太熟悉环境。」
我点头,看他继续从钥匙串里找出和大门钥匙孔相合的钥匙,笑着说:「我想还是不要打扰好了,请问可以借我一把伞吗?我自己走回家就好了。」
「不麻烦,进来坐坐。外面与那么大就算撑伞也会湿透的。」
他持续挽留我,我委婉而坚决地拒绝了。他最后终于点头,看了一眼伞桶,拿了最上面那把折迭伞,蓝色的。
「就这把吧,也不用还了,就是把伞而已。」他笑。
我愣了一秒,略为迟疑地伸出手,接下雨伞。刚刚避雨时,雨水打湿的裤管,让寒意往上窜至胸口。
「恩,谢谢哥哥。」我费力地开口,克制逃跑的恐惧,维持正常步调,走出铁门,把伞打开,凝在伞面尚未干透的雨水向外撒出。走出这栋房子,隐隐感觉他的笑
容在我背后,像把刀抵在喉咙。转过街角,我多走一段路,然后丢掉雨伞,在雨中不停奔跑,快跑回家,一边在雨中清洗双手。好在,逃出来了。

47、疑点:一个人住,确有塞的满满的伞和各式鞋款,蓝色的伞尚未干透的雨水也证明男人刚刚在说谎,说明这男人不是屋子的主人。那么原来屋子的人都哪去了呢……

48.铁板
外出散步的时候
"呀________________!!!!"的一声
突然听到一名女性的尖叫
我急忙的跑向那个方向
只发现一名女性坐倒在
长2公尺x宽2公尺x高50公分的铁板前面,动也不动
上前向询问发生什么事
但女性好像受惊吓的说不出话来...
很快的穿著工作服的人才急忙出来解释
说铁板是在大楼施工时,不小心掉落的
幸好没有人因此受伤
女性饱受惊吓的搂抱着腰的样子
那掉落在鲜红的磁砖上的漆黑的铁板真叫人毛骨悚然...
在太阳下山前,再次的跑回发生意外的地方
那个铁板还在原来的位置
看来是因为太重了而没有办法处理
由于刚刚的意外
所以周围都有警备人员的样子
先前的女性也在场,再次试着向她打了招呼
"刚才真是惊险呢"
根据那名女子的回答
让我决定把警备人员给找过来...

48、当时这个女人带着她的孩子 现在她的孩子正在铁板下面

49.四楼的少女
租屋处前是一排半荒废少有住户的楼房
由于楼房前的小路很少有人会走
虽然会比较快,但仍是绕外面的大路前往学校
这天因为睡过头,便走了小路的快捷方式
经过其中一栋楼房时
恰巧抬头从四楼的窗户看见房间内有一位少女
刚好少女也转过身来看向我这
四目相交了,长的很漂亮呢
她带着忧郁的眼神印在我心里
从这天起上学都走小路
每当我经过楼房望向四楼时
少女也都会正好从房里看向我
彼此一见钟情了吗?
电视播报着某富家女遭绑票的新闻
该不会是她?
难不成她是被困在那,希望我能发现去救她吗?
难怪每次都能看到她在,而且总是一脸忧郁
心急的我立刻冲往那栋楼房想要救人
一进门却是很久没有人居住的样子
冲向四楼房间的我,在打开房门后
便再也无法离开了。

49、不用说了,女鬼。看到另一个解释是这女的其实上吊了,但是上吊了还能砖头……这个更毛骨悚然……

50.「杀人影片」
各位朋友,你听说过「杀人影片」这种东西吗?
那是一种在片里加入大量虐杀剧情,只有熟人才知道的地下影片。
有人说,这种影片甚至是凶手自己拍摄的真实杀人事件。
某天和我一起喝酒的朋友,说他手上有这类怪异影带
就好像老饕会拼死去吃河豚和毒蝎这样的珍馐
自认胆子颇大又充满好奇心的我,依旧希望能看到这样的东西
于是他约我在山上的隐蔽小屋,让我观看这样稀奇的影带
兴奋不已的我照约定准时的到了小屋
朋友却迟到了三十分钟,朋友脸红的笑着说
「抱歉、抱歉~因为我家的老三突然发烧了」
朋友放了期待的影片,背景充满令人鼻酸的哭闹和颤抖的笑声
是一个大约十岁的小孩,被凶手一刀一刀切割成碎片的悲惨故事
因为剧情实在是太过惨烈,我看到一半就后悔的把电视关掉
正所谓好奇心会杀死一只猫,提出想看影片的我真是罪该万死
看完后,我用着非常大声的声音像朋友不满的问说
「这种影片你居然看的下去,你不是自己也有孩子吗?」
面对着我那愤慨的问题,朋友漫不经心的回答了一句话
「对啊,有两个啊。但是,那又怎么样?」
听到朋友这句冷酷的话的我,脸色惨白的跌坐在一旁的沙发上。

50、影片中的就是老三,剩下2个

51.
这三个人总是一起行动。
在家附近一起、学校也一起、班级也在一起、休息时间也一起、回去之后也一起玩。
有一天,在住家附近的空地玩棒球游戏。球飞到那个容易发飙的老头家里(玻璃碎掉的声音!!)
这三个人,为了要派谁去捡回球而吵了一架,接着听到老头发飙怒吼的声音。
三人之后就各自分散开来了。
那天之后,他们三个人一直都没回家。

51. 三人一起去拿球,被老头杀死分尸。

52.
飞机内乘坐着一对看似夫妻的男女,手中还抱着一个婴儿,
但是这个婴儿的脸色看起来不太好,而且也没在机上哭过。
空姐觉得婴儿太安静了,反而担心了起来,就前去询问那对夫妇,婴儿的身体是不是不舒服。
但只得到了”没事,谢谢你。”这样的答复。
之后这两人在海关被逮捕了。

52。婴儿内脏被取掉,装上毒品。

53.
三天前我收到一封恐吓信
虽然字迹故意歪歪扭扭的但我马上就发现这封信来自我最好的朋友....
我们从小一起长大,而且现在在同一个位置上工作
怎麽也想不通他为何要这样做
而今天正是收到信的三天后也就是信上预告的....
看着他拿着绳子在我背后走来走去我怎样也无法专心工作
"..........
还是报个警比较安心吧" 我一边小心不要被朋友怀疑,一边拿出手机
按下手机求救电话
"1.....1......2........
咦!!??怎麽了......怎麽打不通!!!!"
焦急的我这时才突然想到.......
朋友昨天深夜说要帮我把手机升级所以借走一阵子........
他一定是把SIM卡拿出来了!!!!!
所以现在一大早就不能打了!!!!
原来是有阴谋的!!!!!
那麽....我只好在他杀了我前先动手为强了
有那封信作证,这是自我防卫,不是我的错!!
在他手中的绳圈落下之前我拿起了一旁的刀.......

53。没有SIM卡112还是能打的。主角有幻想症,杀死了无辜的朋友。

54.
我有天去入了某宗教的朋友的家里吃饭,晚餐的菜色是烤肉,
但朋友一直不告诉我那肉到底是哪种动物的肉...我还在想是不是人的肉呢。
而在吃下去后才发现『什麽嘛~果然不是人肉!』而吃完了。
结果,至今没明白
那到底是什麽肉呢?

54。主角知道人肉甚么味道。

55.
我在某个网站遇到了那个女生。
然后某天我们互相约出来见面,可能是我稍微迟到了吧,她看到我后一脸讶异。
不知她是紧张还是沉默寡言,她非常少说话。甚至连眼神都不敢对过来。
总之我们在看完电影吃完饭后就回她家了。
她看起来有很多烦恼,所以我就了送她一份礼物,她看起来很高兴,就回送了我一份拼图。
我刚好是一个喜欢破坏组好的拼图的怪人。第二天我就拿了其中一片回家了。
从以前到现在我交往过的女生也都喜欢拼图,而且也会送我一份当礼物。
但我有都只拿其中一片回家,其他都忘掉的怪癖。

55。网站是自/杀者和自/杀网站,少女想自/杀找上男子,男子杀掉少女后分尸,把其中一块拿回家收藏。

56.
最近,我的童年朋友自杀了。
我看着关于她的报导,左手腕流出大量的鲜血,
失血过多死亡。
小时候和他的关系很好,有一次,她的宠物狗不见了 和她一起找到日落。
幸亏最后找到了。 她的亲戚很早就死光了,
小学的时候,父母就离婚,所以她有个只有小学程度的继母。
她父亲非常犹豫,不过发现她原本的母亲外遇。
这些都是我和她父亲闲聊,她父亲酒喝多了才脱口而出的
今天来,是因为她的后母打电话给我,说什麽日记什麽的,总之要我过去一趟。
我匆匆忙忙的过去,没有在意太多。
到达她家时,她后母一脸哀伤的和我打招呼,
后母先请我喝茶,之后叫我稍待一个人进了房间。
我闲着没事,到了好友的房间看看,
一开门,血红色的地毯,告诉我她房间改变多大。
摁?有本日记放在桌上
我翻了翻,提到的都是好友心爱的事物。
里面有我呢,呵呵。
里面也提到了她和父亲打棒球的往事,父亲对付她的左打总很伤脑筋。
等等,怎麽回事?
我突然有点昏眩? 等等.....!!!

56.左打厉害=左撇子,左撇子割腕应该割右手,进门继母给了主角一杯茶。

57.
这个世界上是有恶魔的,为什麽呢?
这是我年轻时候的事情了-
回想当时,我的儿子被酒驾又肇事逃逸的人给撞死了。
虽然知道凶手是谁,但因为没有证据只能看着这家伙从容离开法院。
妻子在生下儿子后病逝,现在唯一的亲人也突然离我远去…
遭逢如此人生剧变的我,却意外在旧书摊拿到了一本古老的书。
这是一本可以招唤恶魔的书,恶魔可以达成人的一切愿望然而相对的,招唤恶魔的人在之后也必须付出恶魔所需要的报酬。
铁齿的我虽然不相信这件事情,但为了帮唯一的亲人伸冤雪恨我只有照着书上的方式一步一步的进行,想不到恶魔真的出现了
从魔界苏醒的恶魔问我
”小小的人儿啊,你有什麽想要的愿望吗?”
收起意外成功的震惊心情,我鼓起勇气非常愤慨的对恶魔说
“我、我无论如何都不能原谅那个杀害我儿子的凶手,我要他死!”
恶魔微笑的说着”没问题,但是你必须付出的报酬是-死亡!”
生命虽然可贵…但是只要能让这家伙死,我的生命根本不值一提
于是我决定接受了这极高的报酬,和恶魔订下了不该订下的契约
三天后,我无意间在报纸上看到肇事逃逸的凶手意外身故。不自觉想起和恶魔的契约,于是静静的等待恶魔把我带走的那天
但是几个月后我依旧平安的活着-奇怪?难道恶魔骗了我吗?
于是我照着书上的方式再次招唤恶魔,恶魔出现在我的面前。
恶魔对着我说”小人儿啊,你的愿望看来已经达成了呢”
“请等一下,您说我要付出生命作为报酬,但为什麽我还活着?”
相对着提出问题的我,恶魔却漫不经心的笑着回答了我
“不,我的确已经收到『死亡』作为报酬了…那麽,永别了!”
恶魔就这麽消失,留下一脸疑惑的我-现在想想,报酬还真是高呢。

57.这个人永远不会死了,即使世界毁灭,孤独比死亡更可怕。

58.
我在外面交了女朋友
老婆最近好像也开始发觉了...
每次回家就会开始问说
''今天去了哪里","跟谁一起去"...等等
相反的女朋友每天都会传简讯鼓励我就像是绿洲一般的存在
但是今天女朋友并没有传简讯来
我一整天抱着沉重的心情回到了家
宠物约翰不同以往的很快的出来迎接我老婆也很识相的今天没有再罗罗嗦嗦了
喝喝
看来是不需要外遇关系了
最后传给女朋友的简讯只有简短的"再见了"三个字
我彷佛还能听见女朋友手机接收到简讯的铃声

58.老婆杀了女友喂狗。

59.
”今天喝的可真有点太多。”
由纱摇晃的身子踩着七吋的高跟鞋,不稳地走进住处公寓的大厅。
她昏昏沉沉地拍打着电梯呼叫钮,可指示灯却怎麽都暗着。
”去你的,这电梯现在是在给我脸色看吗?”
由纱不满地踹了电梯门一脚,向大厅四处张望着想叫管理员帮忙,但今晚大厅空无一人。她看了看门口摆的时钟破口大骂。
”都两点半了。唉呀怎麽搞的,管理员不在警卫室去哪里泡茶聊天了吗?”
眼见别无他法由纱只好走向电梯旁阴暗的逃生走道,望着一阶阶的楼梯忍不住又是一声暗骂。蒙上一层薄灰的楼梯间里灯光明灭不定。
”哪里跑出来的冒失鬼!”
踩着高跟鞋的由纱被一个急着下楼的身影给撞个正着,跌坐在一楼的逃生出口前,她转头只见一个身材高癯的背影推开逃生门飞也似的跑走了。
隔天上午门铃不断响着,原想假装不在由纱顶只好顶着宿醉应了门。
一个黝黑的中年警官拿着笔记本站定在门口。
”我们是京都警视厅的人员,昨夜这里有一名女性住户遭到杀害,请问一下你昨夜有注意到任何可疑的人事物吗?”
由纱揉了揉绞痛着的太阳穴,心理想着:昨天喝那麽醉,神智都不清醒了。要说关于那个人的事情吗?”
真不好意思,我昨天喝了酒,什麽都不记得。”
只见中年警官神色一黯。”那就没办法了,因为你们公寓昨天监视系统出了问题,桉发当时警卫才正在处理,没有任何有关的画面可以搜索呢。这样子打扰了,你一定还在宿醉吧?真不好意思。”
由纱关上了门便也不以为意自顾自地去睡了。
大约是四五天过后。又有警官上门来打探桉情。
”那个,小jie,关于前阵子公寓里发生的事件,你真的一点印象也没有吗?”
这次是个年轻帅气的警官呢!由纱心里窃喜。
”不好意思,我那天喝的太醉真的什麽都不记得。既然一开始就没有吐露,感觉也没有特别重要,也不用再提出来了吧?
”好吧,先谢谢你了。如果有想起任何小细节,麻烦一定要和我说。你也知道没有线索的话我们很难办桉的,上头又有压力一直压着。”
小小寒暄两句后警官便走了。
后来警官大概一个月后又来询问由纱,她依旧回答不记得。
过了三四个月了吧,由纱几乎都快忘记受害的那个住户的长相了,警官又再次上门询问由纱。
”真抱歉,我真的真的什麽都不记得了。”好不容易打发掉了警官,她锁上了门,却冷不防的好像想起了什麽,拿起手机马上报案。

59.杀/人犯就是老是来问的年轻警官。

60.
某天我从他那里收到了有影片附件的E-mail。
想看看是什麽
结果内容是他在自杀。
将头颈挂在绳子上痛苦地挣扎后他死去了。
在这里影像就结束了。

60.自/杀不能开关摄像机,是他杀。

61.
这是一个真实的故事,希望大家以严肃的心态对待!
从前从前很久以前 大概是三年前
我母亲买了一对陶瓷娃娃 那是女儿节要给我姐拿出来摆设用的
我阿嬷的阿嬷的阿嬷客兄 从小就告诉我
当你把陶瓷娃娃收起来的时候
千万不要把她收在阴暗的角落 或是没人理会的柜子里面
总而言之就是不要不理他 不在乎他
不然家里一定会发生一些事情
虽然我是个铁齿不信邪的人 但是总会在朋友耳中听到一些
什麽娃娃好寂寞 你把他丢了 他还会回到你身边
又或着是 娃娃躲在柜子里头冷冷清清澹澹今后都不管得哭啼
我也是有点怕怕的
随着时间飞逝 我破了处男了
姐姐也嫁人了
但是因为某些原因 他带着他的女儿搬回家里头住 再过几天又是女儿节
侄女吵闹着要对陶瓷娃娃
看来是对妈妈买的旧陶瓷娃娃不感兴趣
当然姐姐也是个爱小孩的人 理所当然去**公司买了对陶瓷娃娃
还随机附赠十八段变速录音功能
我侄女这个小王八蛋 立刻就喜新厌旧的把陶瓷娃娃收到柜子里头的最深处 好似不会再拿出来似的
当天晚上
月亮不是很圆 而隔壁员外那条狗阿福也没有吹高雷 我侄女晚上睡觉的时候 一直听到有人在哭
她很害怕 她抓着我还有我姐姐到处去找那个哭声
而每当接近那个哭声一大步 我背嵴就越凉一大半
渐渐的 我发现哭声来自于那个柜子 而且好似来自于深埋于里头的陶瓷娃娃
我们都很害怕
很想把他丢掉 想把他丢到景美溪里或是铜锣湾
但又很害怕 娃娃回来报仇
经过我们的讨论
我们决定把她上网拍卖掉
一对陶瓷娃娃售价三千元** 望有缘人带走
没想到这拍卖一登 马上就有买家标价 当天我就把陶瓷娃娃寄出去
也确认了买家收到这对陶瓷娃娃
过了两天 又是个狗揽的吹高雷的夜晚 我们一样睡得很熟 很熟
但三更半夜的时候 我接到一通电话
是一个小女孩
他说他在车站等我 要我赶快去接他 我当然不理他 因为心里毛毛的
我电话挂掉之后 我们全家人的电话都在同一时间响了起来
全部都是同一个号码
我姐接了起来 小女孩说 请我们快点去接他 他在车站与小男孩 好冷 好孤单
心里真的很害怕 但又怕不去车站
万一她们来找我们 那才真的恐布
我把我爷爷的八卦镜带了出去 跟我姐姐还有侄女到了木栅捷运车站
那时天还没亮 夜都还是黑的 捷运站门口
我远远的看就知道 陶瓷娃娃在那里
我念了大概十次阿弥陀佛 也拜了耶稣玉皇大帝三四次 我凭着 我过人的勇气 把陶瓷娃娃又带了回家
这次
我请了隔壁佬王扮成道士来作法 请她们不要再纠缠我们
这次 我一样用拍卖的方式 以售价三千圆把他标售出去 这次
也顺利寄了出去
但是恐怖的事
那天晚上我又接到了同样的电话
这下我真的不知道该怎麽办了...
我只好鼓起同样的勇气 到了车站
又再次把陶瓷娃娃接了回家
但是我心想真的不是办法我也没钱去请真正的道士来作法
我去提款机看看我剩多少钱《余额
6,000》
我只剩下卖两次陶瓷娃娃的六千圆恩和宫里的道士说要一万二才肯来作法
在我筹不出钱的急迫下我只好硬着头皮
又在把陶瓷娃娃卖出去
两次这样一共有一万二 这时我突然惊觉这不是一个赚钱的好方式吗?
之后
我不断的一直把他用拍卖或是其他的方式把陶瓷娃娃卖掉反正当天晚上我再去车站接她们就好
久而久之陶瓷娃娃也会认路了也会自己走回家
但是她们太矮还是要我们帮他开门
所以我做了一个小门
而在拍卖的途中
我也试着让她们看着
如何使用拍卖最后她们也会自己在我们睡着的时候
利用电脑把自己拍卖出去
经过这样的反覆三千圆三千圆这样子的积沙成塔
我也存到了人生的第一栋房子
我也开始不愁吃穿
直到最近
我发现
自己已经成了台湾首富了....

61.买娃娃的都死了,所以主角成了首富。

62.
6月的尾声、一位住在公寓的大学生、以腐败尸体的状态被发现了。
叫来了他的哥哥胜巳,确认身份之后,播放了电话留言。
3月14日-母亲
往事、中间就切断了。
3月16日-友人 旅行的邀请。
3月21日-父亲 祖父想和你见面。
4月25日-友人
去大学露脸一下吧。
5月1日-母亲
联络胜巳吧。
到此就结束了
「你父母怎麼都在两点以后才打来呢...」
员警向胜巳嘀咕著
「我的父母、在我们很小时就死了???」

62.
3月14日,主角的已经死去的母亲打来了电话,和他聊以前的事情,他感到很害怕,所以没等听完就挂断了
3月16日,朋友邀请他去旅游,应当是去了,不然朋友不会再过一个月才发觉他不见了
3月21日,死去的父亲说死去的祖父想见他,很显然主角要挂了,但应当不是马上就死了,死亡日期推断是不久后的3月月末
4月25日,主角死亡接近25天后朋友发觉主角很久不来上课了
5月 1日,母亲让死去的主角联系哥哥,显然是哥哥也要完蛋了
6月的月末,也就是开头提到的当前时间,主角也是月末死去的,说明哥哥马上要领便当了

63.电梯
这是一个男子住在14楼的故事。
他在半夜回到家,按了14楼的电梯,电梯门关后就启动向上。
突然,8楼按键的灯亮起…
『啊~应该是8楼有人要坐电梯吧…』但突然他开始连按了345楼的按键!
电梯停在3楼门开后,他就立刻冲出电梯,奔下楼后就一直在附近的便利商店待到早上……

63. 两种情况
①传统电梯:有人在8楼按电梯,电梯里面是不会显示的,电梯里面混进不好的东西了
②新型电梯:电梯在上楼途中,如果有人在8楼按电梯,而且电梯里面有显示的话,这说明8楼的人要上楼,而不是下楼,但是公寓楼为什么会有人从自己住的楼层坐电梯上楼呢?肯定是有人要杀他

64."她的微笑"
又见到她了,
每天早上我总是会打开窗户看着她走在这条上学必经的路口,
可爱的脸孔,以及跟邻居打招呼的亲切笑容,
总是让我忍不住按下快门,
阿...她正在对我微笑
!!
『喀嚓』!
而我,却从此以后再也没有勇气拿起那台相机..

64. 女孩因为抬头看主角,过路口的时候没有注意结果被车撞死了,主角的相机正好记录了这一刻

65."我在看着你"
优子在最近一直收到隐藏号码的奇怪的简讯,
简讯的内容大致相同,
"再过4215分,我会送你一个惊喜,我一直在看着你..."
优子本以为是垃圾简讯,便不理会她,
在一次上课的时间,与邻桌的女同学互相聊天,聊到此事,
女同学A开玩笑的说,应该是哪个男生喜欢你,最后会给你什么惊喜吧!
女同学B接着说,应该是台上讲课那个蠢班导喜欢你吧!
优子大声的说,你们别闹了拉!我才不想跟那种土书呆子扯上关系呐!
三个人笑着笑着这件事情又暂时被A女忘记了,
但是这封简讯却没有停下来,持续的发送到女学生的手机,
一直到有一天女学生在学校的厕所的时候,收到了简讯,又把手机拿出来看,
从昨天的132封到今天的217封未读简讯,而最新的一封内容如下,
"在过3分41秒,呵呵,我迫不及待看见你的反应了..我知道你就在厕所里..."
优子看到这封简讯吓了一大跳,立刻要冲回教室,
但是门却被从外面用什么东西给抵住了,打不开,
慌乱之中,打给两个同学,都没人接听,她不知道要打给谁求助,
于是就打给最有可能会在学校的老师,就在女学生拨出后,
崩溃大哭的往天花板看接着就死去了…

65. 老师因为长期被学生羞辱所以起了杀心,女学生被困在厕所给老师打电话,然而老师就在厕所隔间上面拿着ab两个人的头。

66.花语
一个男孩陈尸在家里,心脏被利器贯穿
身上放著一根酢酱草的茎,四片叶子则散落在男孩身旁
现场没有打斗痕迹,也没有采集到可疑的指纹
据调查,有三位嫌疑人:
男孩有女朋友名叫小婉,女朋友父亲是黑道老大,不准他们来往
男孩有个哥哥大志,最近男孩父亲过世,关於遗产问题有些纠纷
还有男孩的青梅竹马小玲,好像很不满男孩交新的女朋友
问题:凶手是谁?之后会做出什麼行动?

66. 凶手是争遗产的大志,幸运草如果有四片叶子,第四片叶子代表财富,男孩临死之前把四片叶子全部拔掉,以此指认凶手

67.美术教室
有一天我一个人被分配到打扫美术教室。
教室里有一幅看起来很贵的画,画的是一个美女的肖像。
有点立体的材质,看起来栩栩如生。
但她的眼睛大到好像一直在瞪我,我觉得有点诡异就赶快扫完回家了。
第二天到学校却引起了骚动。
昨天那幅看起来很贵的画不见了!!
『原来如此,所以你打扫的时候画还在罗?』
『对啊~老师,那幅画是不是很贵啊?』
『那幅《沉睡的女孩》是一位我认识的画家,画自己女儿睡觉时的样子而已,没有什麼特别价值啦!』
『原来如此…』
结果最后那幅画还是没有找到,但不可思议的是,也没有小偷进入的痕迹……

67. 沉睡的女孩怎么会睁着眼睛呢,主角当时看到的是一动不动的小偷。

68.监视录像机
学校附近的购物中心最近传出,有一个小女孩在厕所被**的消息
女孩被凌辱到子宫破裂,店家为了商誉因此用钱把事情压下来
考虑到学生的心情和安全,学校的家长会长特别向店长用电话询问
「事情已经在学生间传开了…请问真的有这种事情吗?还是只是谣言?」
店长非常直接回答说「根本就没有这种事情,您别听人家乱讲啦!」
「我们从开店时就在店里的每间厕所都装了监视器,我已经用我的双眼
一间一间的确认过了,这些事情都是空穴来风,请您千万不要担心!」
得知是谣言后,会长非常有礼貌的向店长道歉并承诺向学生们说明
但在挂下电话后,会长的脸瞬间从满足的微笑转为惊悚的惨白…

68. 店长就是凶手,只有性变态才会在每间厕所里都安装监视器

69.《妻子的爱》
终於跟爱情长跑数年的女友结婚,没有比这更令人高兴的事了
对方是很会吃醋的女孩,看到我跟其他女孩子说话就会不高兴
不过,我从来没有劈腿过,她也告诉我今生只爱我一人
我们就是在这样的互相信赖之下,决定一起迈向人生的下一步
在举行过庄严的结婚典礼后,我们独力贷款买下了独栋的透天厝
开始携手度过只有两人的甜蜜生活,妻子早上在玄关送我出门上班
晚上做好热腾腾的饭菜等我回来,我真是世界上最幸福的男人啊!
在我们一同生活几年之后,我和妻子终於有了两人的爱的结晶
得知这个天大的喜讯之后,妻子对新生命的降临非常期待
我更是每天都高兴的睡不著觉,只要一有和妻子独处的时间
就隔的妻子逐渐隆起的肚子,仔细听著家族新成员的心跳声
时间过的真快啊-转眼间,妻子已经怀孕七个月了…
听医生说孩子的性别是女孩,她将来一定会和妻子一样漂亮吧!
正当我这麼想著的时候,医院突然却传来妻子不幸流产的消息
这时我立刻向长官临时请了假,飞也似的奔向妻子所在的妇产科
向妇产科的医生得知这件事情是事实时,我的心整个都碎了
但是我依旧强忍住失去孩子的痛苦,到病房探望身体衰弱的妻子
因为流产而导致身心俱疲的妻子,双眼眺望著向窗外观望的我
在这之中,我因为难过而不自觉的说出了「失去她真是可惜!」
妻子有气无力的说出「你说的没错」,不过更让我惊讶的是
妻子依旧坚强的说「但是你千万不要担心,因为我们会再有孩子」
「相信我,我会连那个孩子的份…生下一个强壮英俊的男孩子的!」
听了妻子对我的承诺…我想,我们的爱一定可以战胜所有困难的!

69. 妻子因为嫉妒女儿所以主动流产

70.讨厌的主管
在我们工作的这个部门里面,有个全公司公认最讨厌的主管
不但对部属严苛,也是超厚脂肪、硬片眼镜及拼命掩饰稀疏的发稍
女友说,他根本是集秃、肥、瞎三大克星於一身的顾人怨欧吉桑
於是我和几个不满主管的同事,开始暗地里诅咒主管的行为
先由女友以「拔白头发」的名义,拔下了主管头上的一根头发
然后再由我把头发交给精通旁门左道的朋友,在半夜丑时三刻
把主管头发放到写有他生辰八字的草人,用最毒辣的咒语整他
听那位朋友说…这次施法过程是他学法术以来,最成功的一次-
而当草人上的头发变成白色,就是该死的主管一命呜呼的那一天
但是一连过了好几年,主管依旧无时无刻严苛的挑著我们的毛病
而草人上的头发也一直没有变白,这到底是哪里出了问题了呢?

70. 主管带的是假发

71.《感情深厚的一家人》 在我所住著的公寓隔壁,有著外传感情相当深厚的一家人
但是即便感情深厚,夫妇某天却因为一点小事情而大吵了起来
女儿受不了父母吵架,硬生生在两老面前飞也似的离开这个家
他们向窗外一看心里非常震惊,两老因为失去女儿而深感后悔
夫妻两人都当下决定,一定要和女儿一起携手走完人生的旅途
我觉得这一家人真是如外传般的,感情深厚到无法将其分开呢

71. 女儿跳楼了,她的父母也一并跳楼

72.躲藏 "听说这一家有七个孩子的啊?怎么只有六只?是我记错了吗?"
我躲在这小小的空间看着杀害了我六个兄弟的凶手自言自语的找着
要忍耐,绝对不能出声
等妈妈回来才能告诉他发生了什么事
说不定还可以救其他人
当时我就说过了要再多确认
老大他们就是不听
打开门后
伴随着古老的发条式大钟的报时声响了3响
掀起了恐怖的杀戮剧目
那时灵机一动躲进钟内真是幸运
我偷偷的看了看他
他似乎也担心妈妈回来
一边看着表一边四处找着我的身影
我看了看表,差不多找了快一个小时,他应该快放弃了吧?
不然...没救的就可能是我了

72. 一小时后落地钟报时的时候,因为共振腔内装了一个人,声音会很小而且走调,到时候会被凶手发现

73.真纪的日记 8月13日 晴
今天跟妈妈一起去买东西。
妈妈买了梅干。
8月14日 晴
爸爸跟妈妈是红色的、只有真纪是蓝色的。
耶?爸爸跟妈妈都睡着了,那真纪也一起睡了。
8月15日 晴
大家到底在说些甚么?
真纪听不懂,一点也听不懂。
8月16日 阴
为什么,为什么。
今天是真纪的生日耶,太过分了。
难道爸爸妈妈都忘记真纪的生日了吗?
8月16日 晴
真纪有点搞错了。
真纪的生日是今天喔。

日记到这边就结束了。
真纪是一个还在念小学的小女孩。
那么,这个日记写的内容,到底是甚么呢?

73. 小女孩写的是去美国旅游的日记梅干用来防止晕机爸爸和妈妈的登机牌是红色的,小女孩因为是未成年人所以登机牌是蓝色的(上面还会写Need Company),上飞机以后大家都睡觉了由日本飞往美国的太平洋航线中途会跨越本初子午线,所以有两个16日

74.自杀案

国中的同学三天前去世了,死因据说是自杀,原因不明。
虽然不是说与他很熟,
但从以前就听说他与家人感情不是很好。
加上他又喜欢研究黑魔术等等之类怪异的东西,会发生这样的事情,
说真的,其实真的不是很意外。
但不管怎麼说,身为同学不去上个香实在是说不过去。
於是当天傍晚便与友人一同去他的家。
在上完香之后,一向好奇心重的友人提议去出事的房间探险。
「...不好吧,总觉得挺不舒服的,而且也没理由啊。」我试图阻止他的行为。
友人眨眨眼,示意我不必担心。
「伯母~不好意思,我之前有借一本书给XX,
里面好像夹著我的证件,可以麻烦你让我进去他的房间里找找吗?」
用这麼烂的理由....居然可以蒙骗过关,
不知是友人的演技太高明,还是这家人防备心太浅?
总之,我们顺利的进入了房间。
「果然很诡异。」友人说
房间里满满的巫毒道具,连墙壁四周都漆成让人看了不舒服的黑色,
电视机上还摆著插满针的人偶与魔法阵。
最让人印象深刻的,是进门就看到,写在门后,大大的红字
<REDRUM>
「...红兰姆?这是酒名吗?」友人好奇的摸了摸门上的字
「还有一点铁锈味耶,搞不好是人血喔~」
「好了啦!快点回去了!!」
我有点生气,作势要拖他离开这个诡异的房间。
关上门时,透过房内的镜子,看到了令人毛骨悚然的景象。

74. REDRUM在镜子里看就是MURDER,谋杀,这是死者临死前用血写下的真相,真正的凶手是他母亲

75.证词 一名女子的男性友人,突然闯进女子家中挟持女子,现在正在审判中。
「记得是八点左右吧... ...刚好月底,结果家里的电灯突然就这样熄掉了。原先我以为是坏了,但是发现连走廊都熄灯就知道是停电了,原本打算走出去弄变压器的我突然看见门口有一个人,接着二话不说就冲过来抓了我的手臂往外面冲。他手上有一把拔钉器我也不敢挣扎。
幸好当时我男友跟我约好八点要出去吃饭,就在那时候赶到并夺下那人的武器,这时候我才发现那个人就是我的好友... ...」

女子的证词说完,法官立刻叫人把她的男友也逮捕。

75. 晚上八点时天已经完全黑了,在断电的时候不可能很轻易的在黑暗中确认身份,女主遇袭的时候也没有挣扎或者尖叫,而男友一上来就对他看到的第一个人,也就是女主的朋友进行了袭击,说明他本来要袭击的目标是女主,停电就是他制造的,而女主的朋友其实是听到了风声前来保护女主的

76.没开着灯的建筑物 某个地方发生了大地震
当作临时避难所的小学挤满了人,想睡觉却觉得吵闹而且闷热无法入睡
想说出去吹个凉结果发现了一栋没开着灯的建筑物
里面很凉爽而且很安静所以有很多人躺在那边
就决定睡这里了!
过了不久却发现了不太对劲的地方,太安静了…
我冲出了那栋建筑物

76. 活人躺着的地方是不可能凉爽的,那栋建筑物其实是临时停尸房

77.完美的雕像 我们两个人都是大学的学生,美术班的同学,同时也是很要好的朋友。
但是不知道为什么,自从学校要进行美术展览的时候,她就突然失去了联系。
一直到美术展的前几天,我接到了她打来的电话。
「对不起了,缘,看来我没办法完成美术展览要用的雕像...」
「什么?怎么了?」
「还剩下手跟脸颊的部分,就拜托你了。」
电话挂断了。
美术展的前一天,我接到了P0LICE打来的电话,通知的是她的死亡。
她已经死了快两个礼拜了。不可能啊?前几天我才接到电话!
跟着案发到了现场,尸体倒在地上,死法是因为肚子内的脏器全部被掏空,凶手非常的狠毒,她的胸口到腹部的肌肉跟骨头都被挖掉了。
房间的一角,摆着一个雕像,仔细一看是放在美术教室的那个雕像,头有着人的形状,但是是全白的,两肩没有手,反而肚子上的石头有被割开的痕迹,做成了盖子。
基于好奇心,我趁P0LICE不注意的时候,掀开了雕像的肚子。
但我马上感到了恐惧,立刻丢下盖子,转身走离她的房间。

77. 朋友是在用自己切掉的的身体各个器官来完成雕像,而手和头是不能切掉的(切掉了就没办法继续做雕像了)

78.试胆 我和友人A及B三人,半夜到几年前曾发生残杀案件的房子试胆。
「喂、听说不是残杀吗?怨念应该很重吧好恐怖」
「是啊,听说很悲惨。不但乱刀砍死,还被分尸...而且凶手还没被抓到呢」
「但是A啊,你平常不是常自夸幽灵之类的你根本不怕吗?」
...边聊著这些,边拿著手电筒四处探视。
意外仍保持乾净的厨房、还有散乱著坐垫应该是客厅的房间,以及佛坛门敞开的佛堂......
感觉看了就不舒服,且并未实际体验到什麼灵异现象,於是大家就离开了房屋。
「喂,我没看到什麼幽灵之类的东西,你看到了吗?」
「没啊,我也什~麼都没看到,你看到了吗?」
「我也完全没看到喔。」
「我也是,什麼也没看到喔」
结果似乎什麼也没发生的样子。
稍微有点失望,不过总算安心了。

78. 仔细看对话,一共三个人,有四个人表示自己什么都没看到,有不好的东西混进去了

79.早该修理绳子 某天,我和朋友一起去山上露营
因为在山路走了太久的我,头变的昏昏沉沉的。
在回营区的帐篷的时候,路上经过一条很长的吊桥
吊桥下是水流非常湍急的溪谷,要是掉下去不死也半条命
虽然如此,但是我因为身上的疲劳而没有注意太多
结果走到中间,一块木板突然断掉而坠落到吊桥下
而吊桥下面正好有铺设安全的网子,让我捡回了一条命。
听到我的悲鸣的朋友立刻来到吊桥,把我拉上岸边
惊慌失措的我说着「我以为我死定了」,朋友却漫不经心的回答
「只要没事那就好,真是的!早该叫他们把绳子给修好的…」

79. 说朋友是凶手,割绳子的观点,是错的
①男主掉下去的时候是朋友把他拉上来的,想杀他的话不去救不就好了
②绳子断了的话整个桥都塌了,朋友救主角的时候怎么可能看不到只不过是木板断了
事实是木板都会老化到断裂的桥,绳子肯定更不结实,而朋友居然知道绳子有问题还不去修,幸亏是主角独自过桥,如果是两人同时过的话桥就塌了

80.不存在的姊姊 我认为,这个世界是有鬼的
因为在我小的时候,曾经和我的双胞胎姊姊一起生活
由于家里非常贫穷,所以姊姊和我穿着一样的衣服
但是有一天,我的姊姊却突然不见了
也就在姊姊不见的这天,爸爸和妈妈说中了乐透头彩。
而我问妈妈说「姊姊呢?怎么不见了!」
妈妈却笑着说我在做白日梦,他们一直以来只有我一个女儿。
我想,一定是我太穷了,才会整天幻想自己有一个姊姊吧。
现在我过着很幸福的生活,但是听说家里的钱好像快花完了。
姊姊啊,不管你存不存在…请你保佑我们再中一次乐透吧~

80. 妹妹被卖掉了,事实上单纯卖孩子的话不可能得到和中了彩票头奖一样多的钱,妹妹是被活体摘取器官了………………姐姐也快了…………

81.逃狱计划

小明因为杀人而被判了无期徒刑,关进了世上最森严的监狱,
唯一逃出的方式,就是买通监狱的人员,协助他逃狱,
于是他买通了即将退休的狱医,与狱医准备逃狱的计划,
狱医说:「后天晚上,我会安排一具尸体下葬,棺木会放在太平间中,
你就趁没人注意的时候溜进太平间,躲在棺木里,P0LICE一早会抬着棺木去下葬,
等到P0LICE走了以后,我会去把棺木给挖出来,这样你就可以逃离这里了,
只是要辛苦你跟尸体待一晚.....」
这真是一个天衣无缝的计划,小明暗自高兴的这样想着……
到了约定的那天晚上,小明溜进了太平间,果然看到了一口棺木,
于是他急急忙忙的躲了进去,虽然很害怕身旁的尸体,
但想到明天就可以获得自由,也就克服了恐惧躲了进去……
一早,P0LICE们果然抬着棺木下葬了,透过棺木,小明听到厚厚的黄土,
逐渐覆盖在棺木上,小明躲在棺木里不敢出声,P0LICE走了之后,
小明在棺木里暗自窃喜着,等待狱医的到来,
时间慢慢的过去,坟墓上却一点动静也没有,
小明不禁开始紧张起来,狱医呢?!不会是拿了我的钱却不来救我吧………
紧张的小明,已经顾不得对尸体的恐惧了,拿起了预先准备的打火机,
想要在棺木找到东西逃出去,可是,当他看清楚身旁的尸体,那张恐怖的脸孔,
却不禁嘶喊出最凄厉的叫声~~~
但,深埋在土里的棺木所发出的惨叫,地面上却是一点声音都听不见……

81. 死的人就是医生,小明被活埋了

三 : CA专题81

-- ★CA专题★

CursorAdapter 起步 1

CursorAdapter 类是 VFP 8/9 中最重要的新功能之一,因为它提供了一种简单易用、接口统一的访问远程数据源方式。在这个月的文章里,Dung Hennig 将向你展示 CursorAdapter 及它的工作方式。下个月,我们将再学习一些高级的用法。

正文:

越来越多的 VFP 程序员开始把他们的数据储存到象 SQL Server 或者 Oracle 这样的 VFP 表以外的数据仓库中去了。有许多原因导致了这种情况,包括 VFP 表的脆弱性(不管是想象中的还是确实如此)、安全性、数据库的容量、以及通用性的标准等等。MicroSoft 已经在每一个版本中都使得访问非VFP数据更加的简单,为了鼓励这种风气,它甚至在 VFP 7 光盘中自带了 MSDE(Microsoft Data Engine,SQL Server 的一个免费、简装版)。

不过,访问一个后台数据库从来就比使用 VFP 表要麻烦一些,而你可以使用的机制则多得吓人:

×× 远程视图,它基于 ODBC 连接;

×× SQL Passthrough (SPT) 函数,例如 SQLCONNECT()、SQLEXEC() 和 SQLDISCONNECT(),它们也基于 ODBC 连接;

×× ActiveX Data Objects ,简称 ADO,它提供了一个对各种数据库引擎的 OLE Provider 的一个面对对象访问方式;

×× XML,它是一个轻量级的、平台无关的数据传输机制。

如果你曾经用这些机制上工作过,有一件事情你可能已经注意到了:它们中的每一种都各不相同。这样的话,你就必须一个个的学过来,还要把一个已有的应用程序从一种机制转换到另一种机制,这可不是一件简单的工作。

由于有了一个新的基础类 CursorAdapter,在 VFP 8 中访问远程数据要比过去的版本中简单的多。以我之见,CursorAdapter 是 VFP 8 最重要的新功能之一。我认为它最棒的地方是: ×× 使用 ODBC、ADO、XML 变得非常容易,即时你不熟悉这些技术。

×× 不管你选择了哪种远程数据源机制,它都提供一种统一的访问接口。

×× 从一种机制转换到另一种机制变得非常的轻松。

这里是上面的最后一个观点的例子。假设你有一个使用 CursorAdapter 通过 ODBC 来访问 SQL Server 数据的应用程序,由于某些原因你想要改成使用 ADO 了。对于这种情况,你只需要改动 CursorAdapter 的 DataSourceType 属性、并改变对后台数据库的连接,就全部完成了。你的应用程序中的其它部分不需要知道也不需要关心这些事情;它们看到的只是同一个 Cursor 而不管使用了哪一种机制。

属性

我们先从查看 CursorAdapter 的属性、事件和方法开始来学习它。这里不会讨论所有的属性,只谈一下最重要的那些。

DataSourceType

**************

这个属性是最重要的:它决定了这个类的表现,以及要在其它一些属性中要怎么设置。可用的选项有“Native”——意思是使用 VFP 表——或者是 "ODBC"、"ADO" 或 "XML" ,表示你要选用的访问远程数据源的方式。

DataSource

***********

这是访问数据的手段。当 DataSourceType 被设置成“Native”或者“XML”的时候,VFP会忽略这个属性的设置。对于ODBC,请把这个属性设置为一个有效的 ODBC 连接句柄(这意味着你要自己管理连接了)。在ADO的情况下,DataSource 必须是一个 ADO RecordSet,而且它的 ActiveConnection 对象必须被设置为一个打开的 ADO Connection 对象(你又要自己管理这些了)。

UseDEDataSource

****************

如果这个属性被设置成了 .T.(默认是 .F.),你可以不管它的 DataSourceType 和 DataSource 属性,因为 CursorAdapter 将使用 DataEnvironment 的属性来代替( VFP 8 给 DataEnvironment 也增加了 DataSourceType 和 DataSource 属性)。举例来说,当你想让在一个数据环境中的所有 CursorAdapters 斗使用同一个 ODBC 连接的时候,就可以把它设置为 .T.。

SelectCmd

**********

除了 XML 的情况以外,这是一个用来取得数据的 SQL Select 命令。在 XML 的情况下,它可以或者是一个能够被转换为一个 Cursor 的有效 XML 字符串(使用内部的 XMLTOCURSOR() 调用),或者是一个能够返回一个有效的 XML 字符串的表达式。 CursorSchema

************

这个属性里保存的是 Cursor 的数据结构,格式就像你在用 CREATE CURSOR 命令的时候用的那样。这是一个例子:CUST_ID C(6), COMPANY C(30), CONTACT C(30), CITY C(25)。尽管不设置这个属性而让 CursorAdapter 在自己建立 Cursor 去决定这个结构也是可以的,不过如果你自己输入的话,它会工作的更好。如果 CursorSchema 是空的或者不正确,那么当你打开一个表单的数据环境的时候,就会要么弹出一个错误,要么就不能通过从 CursorAdapter 中拖放字段到表单上来建立控件。幸运的是,VFP 自带的 CursorAdapter 生成器可以为你填充这个属性。

AllowDelete、AllowInsert、AllowUpdate 和 SendUpdates

****************************************************

这些属性的默认值是 .T.,它们决定了是否可以删除、插入和更新和改动是否要被发送到数据源。

KeyFieldList、 Tables、 UpdatableFieldList、和 UpdateNameList

*************************************************************

这些属性的用途跟 CURSORSETPROP() 中用到的那些参数的用途是一样的,如果你想让 VFP 自动将对 Cursor 的改动提交到数据源,这些属性就是必须的。

×× KeyFieldList 是一个用逗号分隔的字段列表(不带别名),这些字段组成 Cursor 的主关键字。Tables 是一个用逗号分隔的表名列表。

×× UpdatableFieldList 是一个用逗号分隔的可以被更新的字段名列表(不带别名)。

×× UpdateNameList 是一个用逗号分隔的列表,它用来让 Cursor 中的字段名与在表中的字段名相匹配。UpdateNameList 的格式就像 这样:CURSORFIELDNAME1 TABLE.FIELDNAME1、CURSORFIELDNAME2 TABLE.FIELDNAME2 等等。注意:如果 UpdatableFieldList 不包含表的主键字段的名称(比如说你不想让用户可以更新这个字段),

在 UpdateNameList 还是必须要有这个字段,否则就不能更新。

Cmd、*CmdDataSource 和 *CmdDataSourceType

*****************************************

如果你想指定让 VFP 怎样去删除、插入和更新数据源中的记录,你可以给这些属性设置相应的值——注意,* 的位置是 Delete、Insert 或者 Update。

CursorFill(UseCursorSchema, NoData, Options, Source)

****************************************************

这个方法建立 Cursor,并用来自数据源的数据填充这个 Cursor(你也可以给 NoData 参数传递一个 .T.以建立一个空的 Cursor),给第一个参数传递 .T. 来使用定义在 CursorSchema 中的游标数据结构,或者传递 .F. 来根据数据源中的结构建立一个相应的结构。MULTILOCKS 必须被设置成 ON,否则这个方法将执行失败。如果 CursorFill 由于某些原因执行失败,它不会发生一个错误而是返回 .F.,不过你还是可以用 AERROR() 来检查发生了什么错误(准备苦苦挖掘吧!通常你得到的错误信息都不足以告诉你究竟问题在哪里)。 CursorRefresh()

***************

这个方法类似于 Requery() 函数:它刷新 Cursor 的内容。

Before*() 和 After*()

*********************

CursorAdapter 的几乎每个方法和事件都有一套 before 和 After 开头的“hook”事件(hook这个词中文没有很好的对应,勉强把它翻译成“挂钩”还不如不翻),这样你就可以自定义 CursorAdapter 的行为特性了。例如,你可以在 AfterCursorFill 中为 Cursor 建立索引。在 Before 系列事件中你可以返回一个 .F. 来防止触发被 hook 的事件发生(类似于数据库事件)。

示例

*****

这里是一个示例来自附带的示例文件 (CursorAdapterExample.prg),它用于从 SQL Server 自带的 Northwind 数据库的 Customers 表中取得巴西客户的某几个字段数据。产生的 Cursor 是可更新的,所以如果你对 Cursor 中的数据做了某些改动,然后再次运行程序,你会看到刚才所作的改动已经被保存在后台数据库中了。

local lcConnString, ;

loCursor as CursorAdapter, ;

laErrors[1] lcConnString = \'driver=SQL Server;server=(local);\' + ;

\'database=Northwind;uid=sa;pwd=;trusted_connection=no\'

* 把这里的密码改成你自己的数据库中密码

loCursor = createobject(\'CursorAdapter\')

with loCursor

.Alias = \'Customers\'

.DataSourceType = \'ODBC\'

.DataSource = sqlstringconnect(lcConnString)

.SelectCmd = "select CUSTOMERID, " + ;

"COMPANYNAME, CONTACTNAME from CUSTOMERS " + ;

"where COUNTRY = \'Brazil\'"

.KeyFieldList = \'CUSTOMERID\'

.Tables = \'CUSTOMERS\'

.UpdatableFieldList = \'CUSTOMERID, COMPANYNAME, \' + ;

\'CONTACTNAME\'

.UpdateNameList = ;

\'CUSTOMERID CUSTOMERS.CUSTOMERID, \' + ;

\'COMPANYNAME CUSTOMERS.COMPANYNAME, \' + ;

\'CONTACTNAME CUSTOMERS.CONTACTNAME\'

if .CursorFill()

browse

else

aerror(laErrors)

messagebox(laErrors[2])

endif

.CursorFill()

endwith

数据环境和表单的增强

********************

为了支持新的 CursorAdapter 类,对表单和数据环境类也做了一些增强。

首先,象我前面提到过的那样,DataEnvironment 类现在有了 DataSource 和 DataSourceType 属性。不过它自己并不使用这些属性,而是给那些在这个数据环境中的那些 UseDEDataSource 被设置成了 .T. 的 CursorAdapter 使用的。其次,现在你可以使用类设计器来可视化的建立 DataEnvironment 的子类了(哇!)。

而对于表单,你可以通过设置新的 DEClass 和 DEClassLibrary 属性来指定使用一个 DataEnvironment 的子类了。不过这么做一定要趁早,因为在这么干了以后,原来的数据环境中所有已经做好的东西(Cursor、代码等等)都会丢失,还好系统会先警告你。表单的一个很酷的新功能是它的 BindControls 属性——把这个属性设置为.F.就可以让表单在 INIT 的时候不对控件进行数据绑定,而只有当 BindControls 被设置为 .T. 的时候才会这样。这个功能好在哪里呢?你曾经多少次诅咒过这样的情况:参数必须被传递给表单的INIT事件,而INIT事件却要等到所有的控件已经初始化并已经绑定到它们的数据源了以后才会被触发?要是你想向该表单传递一个参数来告诉表单打开哪个表或者其它会影响 ControlSources 的事情的时候该怎么办?这个新的属性让这些事情变得象打个瞌睡那么容易。

优点

*****

有大量的理由支持我们使用 CursorAdapters 来代替远程视图、SPT、ADO 或者 XML: ×× 每一种机制都有一种不同的接口。对于远程视图,你用 USE 命令来打开它们。对于SPT,你要使用 SQLCONNECT() 和 SQLEXEC() 来建立一个 Cursor。对于 ADO,你必须先建立 ADO 的 Connection 对象和 Recordset 对象(根据你取得数据方式的不同,也许还可能需要一个 Command 对象)的实例,并调用它们的 Open 方法。对于 XML,你首先必须从什么地方获得一个 XML 字符串(例如在 N 层应用中通过一个 COM 部件,或者在 SQL Server 中通过 SQLXML),然后使用 XMLTOCURSOR() 来把这个字符串转换成一个 VFP 的 Cursor。编写对后台数据源进行更新的代码也各不相同。所以,当你从一种机

制转换到另一种机制的时候,就必须要去学一种新的技术,还有你可能需要重写的大量已有的代码。

不管你使用哪种机制来取得数据,CursorAdapters 都使用同一个统一的接口。通过设置该对象的一些属性,然后调用它的 CursorFill 方法来取得数据,对这个 Cursor 操作时就像在操作一个普通的 VFP Cursor 一样,然后调用 TABLEUPDATE() (或者让VFP自动去处理它)来将更新提交到后台数据源。

×× 在实际开发的时候,你经常会需要从命令窗口中打开一个 Cursor 来浏览它的内容。对于远程视图,这么做是很简单的,但是对于 SPT、ADO 和 XML,就可能要花上很多力气了。

而打开由一个 CursorAdapter 的子类产生的 Cursor 几乎就像打开一个远程视图那么容易:你只需要建立这个子类的实例,然后调用它的 CursorFill 方法就行了。你甚至可以直接在它的 INIT 方法中进行 CursorFill,这样只要一步就可以完成操作了。

×× 对于远程视图来说,升迁一个已有的应用程序会相对容易一些:你只要把数据环境中本地表或视图的东西换成同名的远程视图就行了。但是对于SPT、ADO 或 XML,你可能就必须要全部重写整个数据访问方案了。

而用 CursorAdapters 来升迁一个应用程序就会象用 远程视图来升迁一样轻松——只要简单的把数据环境中的 Cursor 对象替换成 CursorAdapters 对象就行了。

×× 在表单和报表设计器中使用远程视图来工作是很容易的。你可以给数据环境添加一个远程视图,然后就能利用到数据环境提供的可视化设计的优势了:拖放字段来自动建立控件、通过在属性窗口中的组合框中选择来轻松的将控件绑定到一个字段等等。SPT、ADO、XML 就不支持可视化设计方式了。

CursorAdapters 与远程视图一样能够享受到在数据环境中可视化设计的那些优点。

×× 用视图设计器可以很容易的建立远程视图。尽管过去它有着许多限制,尤其是在处理有两个以上的表相互连接的视图的时候,可现在,VFP 8 已经修正这些问题中的大多数,并且添加了许多新功能,例如双向编辑:你可以在 SQL 窗口中修改代码,然后就能看到这些改动被反映到视图设计器的可视化部分中了。而对于 SPT、ADO 和 XML,要做的工作就多的多,因为每样东西你都必须自己写代码:建立和关闭连接、要执行的 SQL Select 语句等等。

VFP 8 包含了一个 CursorAdapters 生成器,用了它,可以只需要很少的工作就可以设置好那些对于取得和更新数据来说相当重要的属性。它甚至还包含了一个 SelectCmd 生成器,这个生成器的可视化程度就像是视图设计器一样,它让你可以通过使用一个“mover”控件来选择应该从远程表中取得那些字段。

×× 将远程视图和ADO 记录集中的更新提交到后台数据库是相当简单的。假定视图的属性已经被设置正确了,那么你只需要调用 TABLEUPDATE() 就可以了。在 ADO 的情况下,则调用 RecordSet.Update() 或者 UpdateBatch()。对于 SPT 和 XML,你就必须手工的做大量工作来把更新提交到后台。

象我们前面看到的那样,用 CursorAdapter 来提交更新只需要设置几个属性,然后就可以全部交给 VFP 去做其它所有的工作,或者你也可以很方便的通过指定怎么删除、插入和更新来获得更大的灵活性。

×× 由于远程视图和 SPT 建立的结果集是 VFP 的 Cursor,所以你可以在VFP中的任何地方使用它们:表格、报表、用 Scan 来遍历等等。而另一方面的 ADO 和 XML ,在使用之前就必须先把它们转换成 Cursor,这会给你的应用程序增加额外的复杂性和处理它们的时间。

CursorAdapter 的结果集是一个 VFP Cursor,所以它有着与远程视图和SPT同样的优势。而

CA专题81_ca1981

更棒的是,即使数据源是 ADO 和 XML 你也能得到一个 VFP 的 Cursor,因为 CursorAdapter 会自动为你处理好转换的事情并为你形成一个 Cursor。

×× 由于一个远程视图的 SQL Select 语句是预先定义好的,所以你无法动态去修改它。尽管对于那些典型的数据输入表单来说这已经足够了,但是对于查询和报表来说则不然。可能你必须要建立好几个从同一个表中取得数据的视图,每一个会选择不同的字段、使用不同的 WHERE 子句结构等等。对于 SPT、ADO 或 XML 来说,这不是一个问题。

CursorAdapters 不会受这个问题的折磨——你可以很轻松的通过改动 SelectCmd 属性来改变取得什么数据以及怎么取得数据。

×× 你不能从一个远程视图中调用存储过程,所以远程视图需要直接访问后台的表。对于你的应用程序的数据库管理员来说,这可能是一个问题——某些数据库管理员认为,基于安全的或者什么其它原因,所有的数据访问应该只通过存储过程来进行。而且,由于存储过程是在后台预编译的,所以它执行起来通常要比 SQL Select 语句快得多。在 SPT、ADO 和 XML 的情况下,你可以根据需要来调用存储过程。

通过简单的设置 SelectCmd 属性,CursorAdapters 也可以使用存储过程。

×× 远程视图保存在一个数据库容器中,所以还有一套你必须维护和安装到客户系统上的文件。此外,当你打开一个视图的时候,VFP 会试图去锁定在 DBC 中的视图的记录,虽然这只需要很短的时间。在一个忙碌的系统中,当几个用户试图同时打开一个表单的时候,这可能会造成冲突。尽管也有一些变通的处理办法(把DBC拷贝到本地工作站上、或者使用在 VFP 7 以上版本中的 SET REPROCESS SYSTEM 来减少锁定的时间),这总是一件你要操心的事情。还有一个问题是:如果你使用一个 SELECT * 的视图来从一个指定的表取得数据、而那个表的结构又在后台被改动过了,那么这个视图就会变得无效而且必须要重建才能解决。对于 SPT、ADO 和 XML 来说,由于它们与 DBC 无关,因此它们都没有这些问题。

因为它们都不在 DBC 里面,所以 CursorAdapters 就也没这些问题了。

×× 由于远程视图和 SPT 是通过 ODBC 来工作的,因此它们只能用于直接数据连接的“客户—服务器”模式。而ADO和XML有着在一个 N-层应用程序中的多个层之间传递数据的机制可供选择。

由于 CursorAdapters 可以建立来自 ADO 或者 XML 数据的 VFP Cursor,因此它对于在一个 N-层应用程序中被用于用户界面层来说是理想的。

总结

××

我认为 CursorAdapters 是 VFP 8 中最重要、最令人兴奋的增强之一,因为它提供了一个对于远程数据源的统一而又容易使用的接口,此外,象我们将要在以后的文章中讲述的那样,它还允许我们建立可重用的数据类。下个月我们将探讨一下访问本地数据或者使用 ODBC、ADO和XML来访问远程数据的细节。再下个月,我们将探讨一下建立可重用数据类、以及怎样在报表中使用 CursorAdapters。

【译者注】

附带的示例文件是一个PRG,实在太简单了,我就直接把内容贴在这里了。

local lcConnString, ;

loCursor as CursorAdapter, ;

laErrors[1]

lcConnString = \'driver=SQL Server;server=(local);database=Northwind;\' + ;

\'uid=sa;pwd=;trusted_connection=no\'

* change password to appropriate value for your database

loCursor = createobject(\'CursorAdapter\')

with loCursor

.Alias = \'Customers\'

.DataSourceType = \'ODBC\'

.DataSource = sqlstringconnect(lcConnString)

.SelectCmd = "select CUSTOMERID, COMPANYNAME, CONTACTNAME " + ;

"from CUSTOMERS where COUNTRY = \'Brazil\'"

.KeyFieldList = \'CUSTOMERID\'

.Tables = \'CUSTOMERS\'

.UpdatableFieldList = \'CUSTOMERID, COMPANYNAME, CONTACTNAME\'

.UpdateNameList = \'CUSTOMERID CUSTOMERS.CUSTOMERID, \' + ;

\'COMPANYNAME CUSTOMERS.COMPANYNAME,

CUSTOMERS.CONTACTNAME\'

if .CursorFill()

browse

else

aerror(laErrors)

messagebox(laErrors[2])

endif .CursorFill()

endwith

CursorAdapter 起步 2

CursorAdapter 起步 之二:用 CursorAdapter 来取得和更新数据

在 VFP8 中新增的 CursorAdapter 基类提供一个统一、易用的数据接口。Doug Hennig 在这个月的文章中演示了怎样使用 CursorAdapter 来访问本地数据和 ODBC、ADO和XML这样的远程数据——讨论了使用各种数据源相应的特殊要求和实现途径。

正文:

如我在上一篇文章中所提到的那样,在VFP8中一个最重要的、也是最精彩的新功能是新的 CursorAdapter 基类。在那篇文章中,我们研究了一下 CursorAdapter 的属性、事件和方法,并讨论了它相对于远程视图、SQL PassThrough(SPT)、ADO和XML的优势。

在开始使用 CursorAdapter 之前,你需要根据要访问的是本地数据还是通过ODBC、ADO或者XML的远程数据源的不同,注意这个类所相应的不同的特殊要求。这个月的文章就讲述了使用各种数据源的细节。

使用本地数据源

×××××××

尽管我们很清楚 CursorAdapter 是试图用来标准化和简化对非VFP数据的访问方式的,不过你还是可以把它当作是 Cursor 的代替品用它来访问VFP数据:只要把它的 DataSourceType 属性设置成 "Native"。为什么要这么做呢?因为你的应用程序将来可能会需要升迁——那时候你就可以把 DataSourceType 属性设置成其它几个选项之一(当然可能还需要修改其它几个属性,例如设置连接信息等等),就能轻松的切换到另一种数据库引擎,CONTACTNAME

例如SQL Server。

当 DataSourceType 属性的设置为 "Native" 的时候,VFP会忽略它的 DataSource属性。SelectCmd属性必须是一个 SQL Select 语句(而不是一个 USE 命令或表达式),这就意味着你用 CursorAdapter 不是直接操作本地表而是操作一个类似于本地视图那样的东西。你还必须确保VFP能够找到出现在那个 Select 语句中的任何表,因此,如果这些表不在当前路径中,那么你就需要设置一下路径或者打开这些表所属的数据库。此外,就跟用视图一样,如果你想让这个 Cursor 是可更新的,你还必须设置好那些与更新相关的属性(KeyFieldList、Tables、UpdatableFieldlist和 UpdateNameList)。

下面的例子(文章附件 NativeExample.prg)会用 VFP 示例数据库中的 Customer 表建立一个可更新的 Cursor:

local loCursor as CursorAdapter, laErrors[1]

Open database (_samples + \'data\\testdata\')

with loCursor

.Alias = \'customercursor\'

.DataSourceType = \'Native\'

.SelectCmd = "Select CUST_ID, COMPANY, CONTACT FROM CUSTOMER " + ;

"WHERE COUNTRY = \'Brazil\'"

.KeyFieldList = \'CUST_ID\'

.Tables = \'CUSTOMER\'

.UpdatableFieldList = \'CUST_ID, COMPANY, CONTACT\'

.UpdateNamelist = \'CUST_ID CUSTOMER.CUST_ID, \'+ ;

\'COMPANY CUSTOMER.COMPANY, CONTACT CUSTOMER.CONTACT\'

if .CursorFill()

browse

tableupdate(1)

else

aerror(laErrors)

messagebox(laErrors[2])

endif .CursorFill()

endwith

close databases all

使用 ODBC

×××××

ODBC 是 DataSourceType 属性四种设置中最简单的一种。把 DataSource 设置为一个打开了的 ODBC 连接句柄、设置一下常用的属性、然后调用 CursorFill 来取得数据。如果你设好了 KeyFieldList、Tables、UpdatableFieldList和 UpdateNameList属性,VFP 会自动把你对数据的任何改动转换成相应的 UPDATE、INSERT、和 DELETE 语句来把改动提交到后台数据源。如果你想用的是一个存储过程,那么要相应的设置 *Cmd、*CmdDataSource和 *CmdDataSourceType属性(* 代表 “Delete”、“Insert”或“Update”)。

这里是附件 ODBCExample.prg 中的一个例子,它调用 Sql Server 自带的 NorthWind 数据库中的 CustOrderHist 存储过程来取得销售给某个客户的单位产品总数。

local lcConnString, loCursor as CursorAdapter, laErrors[1]

lcConnString = \'driver=SQL Server;server=(local);database=Northwind;uid=sa;pwd=;"+ ; "trusted_connection=no\'

** 把上面连接字符串中的密码改成你的SQL Server 登录的密码

loCursor = createobject(\'CursorAdapter\')

with loCursor

.Alias = \'Customerhistory\'

.DataSourceType = \'ODBC\'

.DataSource = SQLStringConnect(lcConnString)

.SelectCmd = "exec CustOrderhist \'ALFKI\'"

if .CursorFill()

browse

else

aerror(laErrors)

messagebox(laErrors[2])

endif .CursorFill()

endwith

使用 ADO

××××

与使用 ODBC 相比,使用 ADO要多一些需要操心的事情:

×× DataSource 必须被设置成一个 ADO RecordSet,而且这个 RecordSet 的 ActiveConnection 属性需要被设置成一个打开了的 ADO Connection 对象。

××如果你想要使用一个参数化查询(与下载全部数据相比,这可能是更常用的方式),你必须把一个 ADO Command 对象作为第四个参数传递给 CursorFill 方法,而且这个 Command 对象的 ActiveConnection 属性需要被设置成一个打开了的 ADO Connection 对象。VFP会为你照顾好填充 Command对象的参数化集合的事情(它通过分析 SelectCmd 来找出参数),不过参数所包含的值当然还是必须在有效取值范围内的。

××在数据环境中只有一个使用了 ADO 的 CursorAdapter 这样的情况是比较简单的:如果需要的话,你可以把 UseDEDataSource 属性设置成 .T.,然后根据你的需要把数据环境的 DataSource 和 DataSourceType 属性设置成 CursorAdapter。不过,如果数据环境中有多个 CursorAdapter 的话,这种办法就无效了。原因是 DataEnvironment.DataSource 所引用的 ADO RecordSet 只能包含一个 CursorAdapter 的数据;当你为第二个 CursorAdapter 调用 CursorFill 方法的时候,会出现“RecordSet is already open (RecordSet 记录集已经打开)”的错误。所以,如果你的数据环境中有超过一个的 CursorAdapter,你必须要把 UseDEDataSource 设置成 .F.,并自行管理每个 CursorAdapter 的 DataSource 和 DataSourceType 属性(或者你可以使用一个能够管理这种情况的 DataEnvironment 的子类)。

附件 ADOExample.prg 中的示例代码演示了怎样借助一个 ADO Command 对象来取得数据。这个示例还演示了使用 VFP8 中新的结构化错误处理的功能。对 ADO Connection 对象的 Open 方法的调用被封装在一个 TRY...CATCH...ENDTRY 语句中,以捕捉调用这个方法失败的时候将会出现的 COM 错误。

local loConn as ADODB.Connection, ;

loCommand as ADODB.Command, ;

loException as Exception, ;

loCursor as CursorAdapter, ;

lcCountry, ;

laErrors[1]

loConn = createobject(\'ADODB.Connection\')

with loConn

.ConnectionString = \'provider=SQLOLEDB.1;data source=(local);\' + ;

\'initial catalog=Northwind;uid=sa;pwd=dhennig;trusted_connection=no\'

&& 把上面连接字符串中的密码改成你的SQL Server 登录的密码

try

.Open()

catch to loException

messagebox(loException.Message)

cancel

endtry

endwith

loCommand = createobject(\'ADODB.Command\')

loCursor = createobject(\'CursorAdapter\')

with loCursor

.Alias = \'Customers\'

.DataSourceType = \'ADO\'

.DataSource = createobject(\'ADODB.RecordSet\')

.SelectCmd = \'select * from customers where country=?lcCountry\'

lcCountry = \'Brazil\'

.DataSource.ActiveConnection = loConn

loCommand.ActiveConnection = loConn

if .CursorFill(.F., .F., 0, loCommand)

browse

else

aerror(laErrors)

messagebox(laErrors[2])

endif .CursorFill(.F., .F., 0, loCommand)

endwith

使用 XML

××××

用 CursorAdapter 来操作 XML 需要一些特殊的设置。下面是这些问题:

×× DataSource 属性被忽略;

×× CursorSchema 属性必须被填充好——即使你给 CursorFill 传递的第一个参数是 .F. 也一样——否则将会出错。

×× SelectCmd 必须被设置成一个表达式,例如一个用户自定义函数(UDF)或者对象方法名,该表达式能够为 Cursor 返回 XML。

××对 Cursor 的改动会被转换成一个 DiffGram,它是“包含着被改动了的字段或者记录,在被改动之前、被改动之后的值”的XML,当需要更新的时候,它被放在 DiffGram 属性中。

××为了把数据更动回写到数据源中去,UpdateCmdDataSourceType属性必须被设置为“XML”,并且 UpdateCmd 必须被设置成一个能够处理提交更新任务的表达式(象前面一样,这个表达式也是象一个 UDF 或者对象的方法)。你可能会需要把“This.DiffGram”传递给那个 UDF,这样它就可以把更新提交给后台数据源。

CA专题81_ca1981

这个 Cursor 所使用的 XML源文件可能来自各种不同的地方。例如,你可以调用这样一个UDF:它能用 CursorToXML()来把一个VFP Cursor 转换成 XML,并返回结果: use CUSTOMERS

cursortoxml(\'customers\', \'lcXML\', 1, 8, 0, \'1\')

Return lcXML

UDF 可以调用一个 Web Service,这个 Web Service 则返回一个 XML 结果集。这里是一个例子,我建立了一个 Web Service 并注册在我自己的系统上,而智能感知则为我生成了下面的代码(具体的细节并不重要,它只是演示了一个 Web Service 的例子):

loWS = newobject("WSclient\', home() + \'ffc\\_webservices.vcx\')

loWS.cWSName = \'dataserver web service\'

loWS = loWS.SetupClient(\'http://localhost/' + ;

\'SQDataServer/dataserver.WSDL\', \'dataserver\', ;

\'dataserverSoapPort\')

lcXML = loWS.GetCustomers()

Return lcXML

它能够在一个 Web Server 上使用 SQLXML 3.0 去执行一个存储在一个临时文件中的 SQL Server 2000 查询(要了解关于 SQLXML 更多的信息,请访问 http://msdn.microsoft.com并查找 SQLXML)。下面的代码使用一个 MSXML2.XMLHTTP 对象通过 HTTP 从 Northwind数据库的 Customers表来取得所有的记录,稍后我们将做更进一步的解释。

local loXML as MSXML2.XMLHTTP

loXML = createobject(\'MSXML2.XMLHTTP\')

loXML.open(\'POST\', \'http://localhost/northwind/' + ;

\'template/getallcustomers.xml, .F.)

loXML.setRequestHeader(\'Content-type\', \'text/xml\')

loXML.send()

return loXML.responseText

处理更新的事情要更复杂一点。数据源必须或者能够接受并处理一个 DiffGram (比如 SQL Server 2000 的情况),或者你必须自己去弄清楚所有的改动、执行一系列的 SQL 语句(UPDATE、INSERT和 DELETE)去提交更新。

这里是个使用了带 XML 数据源的 CursorAdapter 的例子(XMLExample.prg)。要注意的是:SelectCMD和 UpdateCMD都是要调用 UDF 的。在 SelectCMD 的情况中,要返回数据的客户编号被传递给一个叫做 GetNEWustomers 的 UDF,这个我们稍后再提。在 UpdateCmd 的情况中,VFP把 DiffGram 属性传递给 SendNWXML,这个我们也稍后再提。 local loCustomers as CursorAdapter, ;

laErrors[1]

loCustomers = createobject(\'CursorAdapter\')

with loCustomers

.Alias = \'Customers\'

.CursorSchema = \'CUSTOMERID C(5), COMPANYNAME C(40), \' + ;

\'CONTACTNAME C(30), CONTACTTITLE C(30), ADDRESS C(60), \' + ;

\'CITY C(15), REGION C(15), POSTALCODE C(10), COUNTRY C(15), \' + ;

\'PHONE C(24), FAX C(24)\'

.DataSourceType = \'XML\'

.KeyFieldList = \'CUSTOMERID\'

.SelectCmd = \'GetNWCustomers([ALFKI])\'

.Tables = \'CUSTOMERS\'

.UpdatableFieldList = \'CUSTOMERID, COMPANYNAME, CONTACTNAME, \' + ;

\'CONTACTTITLE, ADDRESS, CITY, REGION, POSTALCODE, COUNTRY, PHONE, FAX\' .UpdateCmdDataSourceType = \'XML\'

.UpdateCmd = \'SendNWXML(This.DiffGram)\'

.UpdateNameList = \'CUSTOMERID CUSTOMERS.CUSTOMERID, \' + ;

\'COMPANYNAME CUSTOMERS.COMPANYNAME, \' + ;

\'CONTACTNAME CUSTOMERS.CONTACTNAME, \' + ;

\'CONTACTTITLE CUSTOMERS.CONTACTTITLE, \' + ;

\'ADDRESS CUSTOMERS.ADDRESS, \' + ;

\'CITY CUSTOMERS.CITY, \' + ;

\'REGION CUSTOMERS.REGION, \' + ;

\'POSTALCODE CUSTOMERS.POSTALCODE, \' + ;

\'COUNTRY CUSTOMERS.COUNTRY, \' + ;

\'PHONE CUSTOMERS.PHONE, \' + ;

\'FAX CUSTOMERS.FAX\'

if .CursorFill(.T.)

browse

else

aerror(laErrors)

messagebox(laErrors[2])

endif .CursorFill(.T.)

endwith

这里是 GetNWCustomers 的代码。它使用了一个 MSXML2.XMLHTTP 对象来访问一个位于一个Web Server 上的名叫 CustomersByID.xml 的 SQL Server 2000 XML 模板,并返回结果。要获取数据的 Customer ID 被作为一个参数传递给这段代码:

lparameters tcCustID

local loXML as MSXML2.XMLHTTP

loXML = createobject(\'MSXML2.XMLHTTP\')

loXML.open(\'POST\', "http://localhost/northwind/template/customersbyid.xml?";; + ;

"customerid=" + tcCustID, .F.)

loXML.setRequestHeader(\'Content-type\', \'text/xml\')

loXML.send()

return loXML.responseText

这段代码里引用的名为 CustomersByID.XML 的 XML 模板的内容如下:

SELECT *

FROM Customers

WHERE CustomerID = @customerid

FOR XML AUTO

把这个文件放在用于 Northwind 数据库的一个虚拟目录中(参见补充文档《设置 SQL Server 2000 XML 访问》以了解更多关于为 SQL Server 2000 设置 IIS 的内容、以及这篇文章所需要的特殊细节。)

SendNWXML 的内容看起来与 GetNWCustomers类似,除了它接收的参数是一个 DiffGram,然后它把这个 DiffGram 加载到一个 MSXML2.DOMDocumnet 对象中,并把这个对象传递给 Web Server,该 Web Server 会通过 SQLXML把这个对象传递给 SQL Server 2000 去处理。

lparameters tcDiffGram

local loDOM as MSXML2.DOMDocument, ;

loXML as MSXML2.XMLHTTP

loDOM = createobject(\'MSXML2.DOMDocument\')

loDOM.async = .F.

loDOM.loadXML(tcDiffGram)

loXML = createobject(\'MSXML2.XMLHTTP\')

loXML.open(\'POST\', \'http://localhost/northwind/', .F.)

loXML.setRequestHeader(\'Content-type\', \'text/xml\')

loXML.send(loDOM)

运行 XMLExample.prg 来看看它是怎么工作的。你将会在 Browse 窗口中看到一台记录(客户 ALFKI)。试着改动几个字段的值,然后关闭这个窗口,再运行 PRG 一遍。你会看到你的改动已经被写入到后台数据源中了。

总结

××

尽管 CursorAdapter 基类提供了一种对远程数据源的统一的结构,而不管你使用的是 ODBC、ADO还是XML——但是,根据你选择的数据访问机制的不同,对 CursorAdapter 的设置也有一些区别。这些区别取决于数据访问机制的本身。

下个月,我将通过建立一些可重用的数据类、并讨论怎样在报表中使用 CursorAdapter 来结束这个系列的专题。

补充文档:

《设置 SQL Server 2000 XML 访问》

为了能够在一个浏览器或者其它 HTTP 客户端用一个 URL来访问 SQL Server 2000,你需要做一些工作。首先,你需要从 MSDN 网站(http://msdn.microsoft.com——查询一下“SQLXML”,然后选择下载)去下载和安装 SQLXML 3.0。

接着,你需要设置一个 IIS 虚拟目录。步骤如下:从开始菜单|程序|SQLXML 3.0文件夹中单击“Configure IIS Support(设置 IIS 支持)”。展开你的服务器节点,选择要使用的 Web 站点,然后单击鼠标右键,选择“新建|虚拟目录”,在出现的对话框的“常规”页中输入虚拟目录的名称和它的物理路径。在这里,我们使用“Northwind”作为虚拟目录名、“NorthwindTemplates”作为物理路径。使用 Windows 资源管理器在你的系统上的什么地方建立这个物理目录,然后给它建一个名为“Template”的子目录(稍后我们将会用到这个子目录)。把附件中的两个模板文件 GetAllCustomers.xml 和 CustomersByID.xml 拷贝到这个子目录中。

在“安全”页中,输入访问 SQL Server 的相应的信息,例如用户名和密码或者你想采用的特定的验证机制。在“数据源”页上,选择 SQL Server,如果需要的话,还要选择要使用的数据库。在这里我们选择 Northwind 数据库。在“设置”页上选择希望的设置,至少要选上“允许模板查询”和“允许 Post”。

在“虚拟名称”页中,从类型组合框中选择“模板”,并输入一个虚拟名称(在这里我们使用“template”)和物理路径(它应该是虚拟目录的一个子目录,在这里就是 "Template"子目录),这是使用模板的需要。好,单击“确定”。

现在我们测试一下是否每样东西都设置正确了,我们将通过使用你拷贝到 Template 子目录中去得 GetAllCustomers.xml来访问 SQL Server。它的内容如下:

SELECT *

FROM Customers

FOR XML AUTO

为了测试的目的,打开你的浏览器,并输入这个URL:http://localhost/northwind/template/getallcustomers.xml,你就会在浏览器中看到XML形式的 Northwind Customers 表的内容了。

--

CursorAdapter 起步 3

CursorAdapter 起步 之 三:可重用数据类

VFP 的程序员们想要一个可重用的数据类已经很久了。尽管在过去的版本中也有许多解决这个问题的办法,不过总是有点美中不足。现在在 VFP 8里,我们有了真正的可重用数据类。这个月,Doug 为我们演示了怎样通过建立 CursorAdapter 和 DataEnvironment 的子类来建立可重用的数据类、以及怎样在表单和报表中使用它们。

正文

××

在过去的两期杂志中,我们讨论了在 VFP 8 中新增的 CursorAdapter 基础类。我个人的观点是,这是 VFP 8 中最重要的改动之一,因为它向我们提供了一个对象SQL Server这样的非VFP数据源的简单易用、统一的接口。此外,如你本月所能见到的那样,它们还形成了可重用数据类的基础。

在讲述可重用数据类之前,让我们先来看一下我建立的一些 CursorAdapter 和 DataEnvironment 的子类,我给它们增加了一些额外的功能,它们将成为我们的可重用数据类的起点。

SFCursorAdapter

***************

SFCursorAdapter (在附件 SFDataClasses.vcx 中) 是 CursorAdapter 的一个子类,它拥有一些额外增加的功能,如下:

※ 它可以自动处理参数化查询:你可以静态(一个常量)也可以动态(一个表达式,例如“=Thisform.txtName.value”,当 Cursor 被打开或者刷新的时候,这个表达式会被运算)的定义一个参数值。

※ 它可以在 Cursor 被打开以后自动在该 Cursor 上建立索引。

※ 对于 ADO,它还会执行一些特殊的工作,例如把 DataSource 属性设置为一个 ADO RecordSet,把这个 RecordSet 的 ActiveConnection 属性设置为一个 ADO Connection 对象,当用到一个参数化查询的时候,它还会建立一个 ADO Command 对象并把这个对象传递给 CursorFill 方法。

※ 它提供了简单的错误处理(cErrorMessage 属性里会有错误的信息)。

※ 它还有 CursorAdapter 中缺少的 Update 和 Release 方法。

这个类的 INIT 方法建立两个集合(使用新的 Collection 基础类,它是维护某些东西的集合用的),一个是为 SelectCmd 属性可能会用到的参数而准备的,另一个是用于在 Cursor 被打开以后应该自动建立的标记。它还会 SET MULTILOCK ON,因为这是 CursorAdapter Cursor 的需求。

This.oParameters = CreateObject(\'Collection\')

This.oTags = CreateObject(\'Collection\')

Set multilocks on

AddParameter 方法象 parameters 集合添加一个参数。给这个方法传递参数的名称(这个名称应该与该参数出现在 SelectCmd 属性中的那个名称相一致),根据需要也可以付上参数的值(如果你现在不给它传递参数的值,也可以以后再调用 Getparameter 方法来传递)。这段代码演示了一对 VFP 8 中的新功能:新的 empty 基础类,它没有任何属性、事件或者方法,因此是建立一个轻量级的对象的理想选择;还有 AddProperty() 函数,它的作用跟 AddProperty 方法类似,区别是它用于那些没有这个方法的对象。

lparameters tcName, tuvalue

local loParameter

loParameter = createobject(\'Empty\')

addproperty(loParmeter, \'Name\', tcName)

addproperty(loParmeter, \'value\', tuvalue)

This.oParameters.Add(loParameter, tcName)

使用 GetParmeter 方法来返回一个特殊的 parameter 对象——通常是用在需要设置用于参数的值的时候。

lparameters tcName

local loParameter

loParameter = This.oParameters.Item(tcName)

return loParameter

SetConnection 方法用于将 DataSource 属性设置为希望的连接。如果 DataSourceType 是 “ODBC”,就给这个方法传递一个连接句柄;如果是“ADO”,DataSource 必须是一个ADO Recordset 对象,而且该对象的 ActiveConnection 属性必须要设置为一个活动 ADO Connection 对象,所以,我们需要向 SetConnection 方法传递这个 ADO Connection 对象,

CA专题81_ca1981

SetConnection 会建立一个 RecordSet,并且把这个 RecordSet 的 ActiveConnection 设置为被传递的 ADO Connection 对象。

lparameters tuConnection

with this

do case

case .DataSourceType = \'ODBC\'

.DataSource = tuConnection

case .DataSourceType = \'ADO\'

.DataSource = Createobject(\'ADODB.RecordSet\')

.DataSource.ActiveConnection = tuConnection

endcase

endwith

为了建立 Cursor,我们调用 GetData 方法而不是 CursorFill 方法,因为 GetData 能够自动处理参数和错误。如果你想要建立一个不带数据的 Cursor,那么就给 GetData 方法传递一个 .T.。这个方法建立的第一样东西,是与定义在 parameters 集合中的参数们同名的私有变量(在这里调用了 GetParametervalue 方法,该方法会返回参数对象的值,如果该对象的值是一个以“=”开头的表达式,那么返回的将是运算该表达式之后所获得的值。)下一步,如果我们是在使用 ADO 并且已经有了一些参数,这段代码会建立一个 ADO Command 对象,并把该对象的 ActiveConnection 属性设置为 Connection 对象,然后把这个 Connection 对象传递给 CursorFill 方法——这是 CursorAdapter 处理 ADO 参数化查询的需要。如果我们不是在用 ADO 、或者没有任何参数,那么代码会简单的调用 CursorFill 来填充 Cursor。注意,如果给 GetData 方法传递了 .T.,并且 CursorSchema 已经被填写好了,那么就是告诉 GetData 方法去使用 CursorSchema(这也是我想让 CursorAdapter 基类拥有的功能)。现在如果 Cursor 被建立起来了,代码会调用 GreateTags 方法来为该 Cursor 建立想要的索引;如果 Cursor 没有被建好,那么它会调用 HandleError 方法来处理任何发生了的错误。

lparameters tlNoData

local loParameter, ;

lcName, ;

luvalue, ;

llUseSchema, ;

loCommand, ;

llReturn

with This

* tlNoData参数指定是否要向 Cursor 中填充数据,如果要填充的话,

* 我们就要把建立存储所有参数的变量的活在这里就做掉而不是放到一个其它的方法中去。 * 因为我们希望这些变量的有效范围是私有的。

if not tlNoData

for each loParameter in .oParameters

lcName = loParameter.Name

luvalue = .GetParametervalue(loParameter)

store luvalue to (lcName)

next loParameter

endif not tlNoData

* 如果我们正在使用 ADO,并且有了一些参数,那么就需要有一个处理这些参数的 Command对象

llUseSchema = not empty(.CursorSchema)

if \'?\' $ .SelectCmd and (.DataSourceType = \'ADO\' or (.UseDEDataSource and ;

.Parent.DataSourceType = \'ADO\'))

loCommand = createobject(\'ADODB.Command\')

loCommand.ActiveConnection = iif(.UseDEDataSource, ;

.Parent.DataSource.ActiveConnection, .DataSource.ActiveConnection)

llReturn = .CursorFill(llUseSchema, tlNoData, .nOptions, loCommand)

else

* 填充这个 cursor.

llReturn = .CursorFill(llUseSchema, tlNoData, .nOptions)

endif \'?\' $ .SelectCmd ...

* 如果 Cursor 建立成功,则为之定义所有的 Tag,否则则处理发生的错误。

if llReturn

.CreateTags()

else

.HandleError()

endif llReturn

endwith

return llReturn

--

还有一些方法这里我们就不说了,你可以自己去研究它们。HandleError 方法使用 Aerror() 来判断发生了什么错误,并把错误数组的第二个元素放到 cErrorMessage 属性中去。Requery 方法与 GetData 类似,不过它是用来刷新 Cursor 中的数据。调用这个方法而不是 CursorRefresh 方法的原因就象 GetData 一样:它能够处理参数和错误。Update 方法很简单:它就是调用 TableUpdate() 来提交当前数据源的更新,如果提交更新失败,则调用 HandleError 方法来处理错误。AddTag 用于在 Cursor 被建立后将你想要建立的索引的信息添加到 Tags 集合中,而 GetData 方法会调用的 CreateTags 方法则会在自己的 Index ON 语句中用到这个集合中的信息。

这里是使用这个类的一个例子,是从附件中的 TestCursorAdapter.prg 中拿来的。它从 SQL Server 自带的 Northwind 数据库的 Customers 表中取得数据。它的 SelectCmd 属性里是一个参数化查询的 Select 语句,向你演示了怎样用 AddParameter 方法来处理参数,以及怎样用 AddTag 方法来自动地为 Cursor 建立索引标识。

local loCursor as SFCursorAdapter of SFCursorAdapter, ;

loConnMgr as SFConnectionMgrODBC of SFRemote, ;

loParameter as Empty

lnHandle = sqlstringconnect(\'driver=SQL Server;server=(local);\' + ;

\'database=Northwind;uid=sa;pwd=;trusted_connection=no\')

&& change password to appropriate value for your database

loCursor = newobject(\'SFCursorAdapter\', \'SFDataClasses\')

with loCursor

.DataSourceType = \'ODBC\'

.Alias = \'Customers\'

.SelectCmd = \'select * from customers where country = ?pcountry\'

.SetConnection(lnHandle)

.AddParameter(\'pcountry\', \'Brazil\')

.AddTag(\'CustomerID\', \'CustomerID\')

.AddTag(\'Company\', \'upper(CompanyName)\')

.AddTag(\'Contact\', \'upper(ContactName)\')

if .GetData()

messagebox(\'Brazilian customers in CustomerID order\')

set order to CustomerID

go top

browse

messagebox(\'Brazilian customers in Contact order\')

set order to Contact

go top

browse

messagebox(\'Canadian customers\')

loParameter = .GetParameter(\'pcountry\')

loParameter.value = \'Canada\'

.Requery()

browse

else

messagebox(\'Could not get the data. The error message was:\' + ;

chr(13) + chr(13) + .cErrorMessage)

endif .GetData()

* Now try to do an invalid SELECT statement.

.SelectCmd = \'select * from customersx\'

browse

else

messagebox(\'Could not get the data. The error message was:\' + ;

chr(13) + chr(13) + .cErrorMessage)

endif .GetData()

endwith

sqldisconnect(lnHandle)

SFDataEnvironment

*****************

在附件 SFDataClasses.vcx 中的这个数据和环境类要比 SFCursorAdapter 简单的多。但它增加了一些非常有用的功能:

×× GetData 方法会调用所有在这个数据环境类里面的 SFCursorAdapter 成员类的 GetData 方法,这样你就不需要自己去一个个的调用它们。与此类似的是,Requery 方法和 Update 方法也会调用每个 SFCursorAdapter 成员类的 Requery 和 Update 方法。

×× 象 SFCursorAdapter 一样,SetConnection 方法会把 DataSource 设置为一个 ADO Recordset,并把这个 Recordset 的 ActiveConnection 属性设置为一个 ADO Connection 对象。不过,它还会调用所有 UseDEDataSource 属性被设置为 .F. 的 SFCursorAdapter 成员类的 SetConnection 方法。

×× 它提供了一些简单的错误处理(cErrorMessage 属性会被填入错误信息)

×× 它有一个 Release 方法。

现在我们看看这个类的一对方法。GetData 非常简单:如果这个数据环境类的任何成员对象拥有 GetData 方法,则调用该方法:

lparameters tlNoData

local loCursor, ;

llReturn

for each loCursor in This.Objects

if pemstatus(loCursor, \'GetData\', 5)

llReturn = loCursor.GetData(tlNoData)

if not llReturn

This.cErrorMessage = loCursor.cErrorMessage

exit

endif not llReturn

endif pemstatus(loCursor, \'GetData\', 5)

next loCursor

SetConnection 方法稍微复杂一点:如果它的任何成员对象有 SetConnection 方法、并且该成员对象的 UseDEDataSource 属性被设置为 .F.,则调用该成员对象的 SetConnection 方法;然后,如果有任何一个 CursorAdapter 对象的 UseDEDataSource 属性被设置为了 .T.,则使用类似于 SFCusrorAdapter 中的那样的代码来设置自己的 DataSource:

lparameters tuConnection

local llSetOurs, ;

loCursor, ;

llReturn

with This

* Call the SetConnection method of any CursorAdapter that isn\'t using our

* DataSource.

llSetOurs = .F.

for each loCursor in .Objects

do case

case upper(loCursor.BaseClass) <> \'CURSORADAPTER\'

case loCursor.UseDEDataSource

llSetOurs = .T.

case pemstatus(loCursor, \'SetConnection\', 5)

loCursor.SetConnection(tuConnection)

endcase

next loCursor

* If we found any CursorAdapters that are using our DataSource, we\'ll need to

* set our own DataSource.

if llSetOurs

do case

case .DataSourceType = \'ODBC\'

.DataSource = tuConnection

case .DataSourceType = \'ADO\'

.DataSource = createobject(\'ADODB.RecordSet\')

.DataSource.ActiveConnection = tuConnection

endcase

endif llSetOurs

endwith

TestDE.prg 做了一个演示,它使用 SFDataEnvironment 作为容器,该容器中有一对 SFCursorAdapter 类。因为这个例子用的是 ADO,所以每个 SFCursorAdapter 都需要它自己的 DataSource,因此它们的 UseDEDataSource 属性都被设置成了 .F.(默认设置)。注意:

CA专题81_ca1981

只要简单的调用一下 SFDataEnvironment 的 SetConnection 方法就能搞定为每个 CursorAdapter 设置好 DataSource 属性的事情。

local loConn as ADODB.Connection

loConn = createobject(\'ADODB.Connection\')

loConn.ConnectionString = \'provider=SQLOLEDB.1;data source=(local);\' + ;

\'database=Northwind;uid=sa;pwd=\'

&& change password to appropriate value for your database

loConn.Open()

set classlib to SFDataClasses

loDE = createobject(\'SFDataEnvironment\')

with loDE

.AddObject(\'CustomersCursor\', \'SFCursorAdapter\')

with .CustomersCursor

.Alias = \'Customers\'

.SelectCmd = \'select * from customers\'

.DataSourceType = \'ADO\'

endwith

.AddObject(\'OrdersCursor\', \'SFCursorAdapter\')

with .OrdersCursor

.Alias = \'Orders\'

.SelectCmd = \'select * from orders\'

.DataSourceType = \'ADO\'

endwith

.SetConnection(loConn)

if .GetData()

select Customers

browse nowait

select Orders

browse

else

messagebox(\'Could not get the data. The error message was:\' + ;

chr(13) + chr(13) + .cErrorMessage)

endif .GetData()

endwith

loConn.Close()

可重用数据类

************

现在我们已经有了可用的 CursorAdapter 和 DataEnvironment 的子类,让我们来谈谈可重用数据类的事情。

一件 VFP 程序员们已经向 Microsoft 要求了很久的事情是可重用数据类。例如,你可能有

一个表单和一个报表,它们使用的是完全相同的一套数据,然而你却不得不重复的去手动向数据环境中添加一个个表或者视图——因为数据环境是不可重用的。某些程序员(以及几乎所有的应用程序框架提供商)采用了通过代码来建立可重用数据环境(那时候数据环境是不能可视化的建立子类的)的方法,并且在表单上使用一个 “loader”对象来建立 DataEnvironment 子类的实例。不管怎么说,这种方法总不是那么正规,并且无法用于报表。

现在,在 VFP8 里,我们不仅拥有了建立“能够向任何需要数据的对象提供来自任何数据源的数据”的可重用数据类的能力,还有了建立“能够寄宿数据类的”数据环境类的能力。在我写这篇文章的时候,你还不能在报表中使用 CursorAdapter 或者 DataEnvironment 的子类,不过你可以编程的添加 CursorAdapter 子类(例如把这些代码写在 DataEnvironment 的 INIT 方法中)来利用可重用类的优点。

让我们为 Northwind 数据库的 Customers 和 Orders 表建立一些数据类。CustomersCursor (在 NorthwindDataClasses.vcx 中)是 SFCursorAdapter 的一个子类,其属性如表1:

表 1. CustomersCursor 的属性

属性 值

Alias Customers

CursorSchema CUSTOMERID C(5), COMPANYNAME C(40), CONTACTNAME C(30), CONTACTTITLE C(30), ADDRESS C(60),

CITY C(15), REGION C(15), POSTALCODE C(10), COUNTRY C(15), PHONE C(24), FAX C(24)

KeyFieldList CUSTOMERID

SelectCmd select * from customers

Tables CUSTOMERS

UpdatableFieldList CUSTOMERID, COMPANYNAME, CONTACTNAME, CONTACTTITLE, ADDRESS, CITY, REGION, POSTALCODE, COUNTRY, PHONE, FAX

UpdateNameList CUSTOMERID CUSTOMERS.CUSTOMERID, COMPANYNAME CUSTOMERS.COMPANYNAME, CONTACTNAME CUSTOMERS.CONTACTNAME, CONTACTTITLE CUSTOMERS.CONTACTTITLE, ADDRESS CUSTOMERS.ADDRESS, CITY CUSTOMERS.CITY, REGION CUSTOMERS.REGION, POSTALCODE CUSTOMERS.POSTALCODE, COUNTRY

CUSTOMERS.PHONE, FAX, CUSTOMERS.FAX CUSTOMERS.COUNTRY, PHONE

你不会以为我会是手动在属性窗口中输入所有这些属性的值吧?当然不是!我是用 CursorAdapter 的生成器来干的。这里的技巧是打开“Use connection settings in builder only(只使用在生成器中的连接设置)”,填入连接信息以获得一个活动连接,再填好 SelectCMD 以后,最后再用生成器来生成其它的属性设置。

现在,任何时候你需要 Northwind 的 Customers 表中的数据,只要简单的放一个 CustomersCursor 类就够了。当然,我们还没有定义任何连接信息,不过做到这样就已经很不错了,有了这个类就不需要担心怎么获得数据(ODBC、XML、ADO)、使用哪种数据引擎(比如 SQL Server、Access 以及 VFP 8中都有 Northwind 数据库)之类的事情了。

不过,要注意的是这个 Cursor 对付的是 Customers 表中所有的记录。可有时候,你又只想要一个客户的数据。那么,CustomerByIDCursor 是 CustomersCursor 的一个子类,它的 SelectCmd 已经被改成 “Select * from customers where customerid = ?pcustomerid”,还有下面增加的 INIT 方法的代码:

lparameters tcCustomerID

dodefault()

This.AddParmeter(\'pCustomerID\', tcCustomerID)

这段代码会建立一个叫做 pCustomerID 的参数(它跟在 SelectCmd 中指定的是同一个),并且被设置成传递进来的任何值。如果没有值被传递进来的话,那么使用 GetParameter 方法来为这个参数返回一个对象,并在调用 GetData 之前设置它的 value 属性。

OrdersCursor 类类似于 CustomersCursor,只是它返回的是 Orders 表中的所有数据,而 OrdersForCustomerCursor 是它的一个子类,用于返回一个指定客户的所有订单。

要测试一下的话,请运行 TestCustomersCursor.prg,它会从 SQL Server 版本的 Northwind 数据库中 Customers 表的一个客户,然后做到 Access 版本的 Northwind 数据库所做的同样的事情。这个示例演示了怎样不为类指定连接信息,这个类自己就能灵活的完成任务,因此,它的可重用性是很强的。

示例:表单

**********

现在我们已经有了一些可重用类,让我们来用用它们。首先,我们来建立 SFDataEnvironment 的一个子类 CustomersAndOrdersDataEnvironment (哈哈,名字可有够长的,D.H牌冰糖葫芦!),它包含着一个 CustomerByIDCursor 类和一个 OrdersForCustomerCursor 类。由于我们希望在打开表之前设置连接信息,因此把它的 AutoOpenTables 属性设置为了 .F.,而且把前面两个 CursorAdapter 的 UseDEDataSource 属性都设置为了 .T.。现在,这个数据环境类已经可以被用来在某个表单中显示关于一个指定客户的信息以及他的订单了。

让我们来建立这么一个表单。附件中的 CustomerOrders.scx 表单的 DEClass 和 DEClassLibrary 属性已经被设置为了CustomersAndOrdersDataEnvironment 和 NorthwindDataClasses.vcx,这样就用上了我们的可重用数据环境类。这个表单的 Load 方法里面的代码有点多,不过这是因为它要支持 ADO、ODBC、以及 XML 数据源,并且它还要建立自己的连接,所以大多数代码都是处理这些问题的。如果它只支持一种数据源的话,比如只用 ODBC,再比如由另一个对象来管理连接(实际的应用程序开发中常常就是这样的),代码就会简单多了:

with This.CustomersAndOrdersDataEnvironment

* 获得连接

lnHandle = oApp.oConnectionMgr.GetConnectionHandle()

.SetConnection(lnHandle)

* 指定从 CustomerID 文本框中取得 cursor 参数的值

loParameter = ;

.CustomerByIDCursor.GetParameter(\'pCustomerID\')

loParameter.value = \'=Thisform.txtCustomerID.value\'

loParameter = ;

.OrdersForCustomerCursor.GetParameter(\'pCustomerID\')

loParameter.value = \'=Thisform.txtCustomerID.value\'

* 建立一个空的 cursor,如果失败的话则显示错误信息

if not .GetData(.T.)

messagebox(.cErrorMessage)

return .F.

endif not .GetData(.T.)

endwith

这段代码用上了那两个 CursorAdapter 对象的 GetParameter 方法来把 pCustomerID 参数设置为表单上一个文本框中的值。注意在值里面用到的\'=\',它表示在你需要 value 属性的时候再去运算它的值,所以我们实际上有了一个动态的参数(这样就顺应了当用户在文本框中输入了新的值以后要将改动反应到参数中去的需要)。调用 GetData 方法是为了建立一个空的 Cursor,这样才能安顿那些数据绑定的控件。

txtCustomerID 文本框没有绑定什么数据。它的 Valid 方法先调用数据环境的 Requery 方法,然后再调用表单的 Refresh 方法。这样,当用户输入一个新的客户ID的时候,就能够 Requery 那个 Cursor,接着表单上其它控件也会被刷新。表单上的其它文本框被绑定到由 CustomersByIDCursor 对象建立的 Customers cursor 的字段中。那个 Grid 被绑定到由 OrdersForCustomerCursor 对象建立的 Orders Cursor。

运行这个表单,并输入一个 Customer ID 为“ALFKI”(见图1)。当你按下 Tab 键跳出这个文本框的时候,你会看到该客户的地址信息以及他的订单就出现了。试着改动一些这个客户的数据或者订单数据,然后关闭表单再打开,再输入一次“ALFKI”,你会看到你没做什么工作这些改动就都已经被写到后台数据库中了。

此主题相关图片如下:

图1、

酷吧,嗯?跟建立一个基于本地表或者视图的表单相比,并没多多少工作。更棒的是:试试把定义在 Load 方法中的 ccDATASOURCETYPE 常量改变为 “ADO”或者“XML”,然后这个表单无论是看起来还是实际工作起来都跟没改过之前一摸一样(如果你想用 XML,你需要象上个月的文章中所说的那样为 Northwind 数据库设置一个 SQLXML 虚拟目录,

并把本月附件中的 XML 模板文件拷贝到那个目录里)。

示例:报表

**********

我们来试试报表。这里最大的问题是:与表单不同,我们既不能告诉报表去使用一个数据环境子类,也不能拖放一个 CursorAdapter 子类到数据环境中去。所以我们不得不向报表放入一些代码以将 CursorAdapter 添加到数据环境。尽管从逻辑上来看应该把这些代码放到报表数据环境的 BeforeOpernTables 事件中去,不过事实上这样做却是行不通的,因为——由于某些我不能理解的原因—— BeforeOpenTables 事件只会在你预览报表的每一页的时候才会触发。所以,我们只好把代码放在 Init 方法里。因为演示的需要,报表 CustomerOrders.frx 跟表单 CustomerOrders.scx 一样,要比实际开发的情况下会用到的代码更复杂一些。如果没有这些演示的需求的话,实际上可以简化到下面这样:

with This

set safety off

* 获得连接

.DataSource = oApp.oConnectionMgr.GetConnectionHandle()

* 建立客户和订单的 CursorAdapter 对象

.NewObject(\'CustomersCursor\', \'CustomersCursor\', ;

\'NorthwindDataClasses\')

.CustomersCursor.AddTag(\'CustomerID\', \'CustomerID\')

.CustomersCursor.UseDEDataSource = .T.

.NewObject(\'OrdersCursor\', \'OrdersCursor\', ;

\'NorthwindDataClasses\')

.OrdersCursor.AddTag(\'CustomerID\', \'CustomerID\')

.OrdersCursor.UseDEDataSource = .T.

* 取得数据,如果失败,则显示错误信息

if not .CustomersCursor.GetData()

messagebox(.CustomersCursor.cErrorMessage)

return .F.

endif not .CustomersCursor.GetData()

if not .OrdersCursor.GetData()

messagebox(.OrdersCursor.cErrorMessage)

return .F.

endif not .OrdersCursor.GetData()

CA专题81_ca1981

* 从 Customers 设置一个与 Orders 的关系

set relation to CustomerID into Customers

endwith

这里的代码比表单示例的要多一些,这是因为我们不能使用自定义的数据环境类导致不得不自己手动编码来代替。

现在,我们怎样才能尽可能简单的就把那些字段放到报表上去呢?由于 CursorAdapter 对象是我们用代码在运行时才添加到数据环境中去的,在设计时就没办法享受到拖放字段到报表上的方便了。这里有个小技巧:建立一个会建立这些 Cursor 的 PRG文件,并让这些 Cursor 处于有效范围内(可以采用挂起 PRG 的运行或者把 CursorAdapter 对象声明成 Public 的办法),然后使用快速报表功能来把那些字段放到报表上,这样报表控件的大小也设置好了。

图2展示了当你预览报表的时候该报表的情况。如果结合表单一起使用的话,你可以试试改动表单数据环境中的 #DEFINE 语句来换用其它类型的数据源。

总结

*****

我们对新的 CursorAdapter 基础类的研究就到这里了。我个人对 CursorAdapter 的出现感到非常的兴奋,并计划给我的应用程序框架中的数据处理部件升升级以更充分的利用它的优点。

--

vfp9 CA的新方法----DelayedMemoFetch

vfp8的CA有一个FetchMemo属性

如果设置FetchMemo= .F.

那Memo字段的内容会不读取,但如果需要里面的内容就会变的非常麻烦

VFP9开始有了DelayedMemoFetch方法

可以做到,cursorFill()的时候,Memo里面全空

但,当光标移动到Memo字段的时候才自动读取当前条记录的Memo字段内容

注意是:当前条记录的Memo字段内容

这个方法能极大的提高读取带有Memo字段表的效率

操作办法如下:

1.FetchMemo = .F.

2.FetchMemoDataSourceType = ca.DataSourceType

3.FetchMemoDataSource = ca.DataSource

4.FetchMemoCmdList

这个是最关键的,也是最麻烦的

oCA.FetchMemoCmdList= "f1 <SELECT f1 FROM testCAMemoFetch WHERE f0=?EVALUATE(this.RefreshAlias +\'.f0\')>, f2 <SELECT f2 FROM testCAMemoFetch WHERE f0=?EVALUATE(this.RefreshAlias +\'.f0\')>"

f1,f2这里是Memo字段名简称

f0是关键字段名

this.RefreshAlias可以是this.Alias

翻译一下意思如下:select Memo字段名 From 后台表名 whete 关键字段名=?前台的Alias名.关键字段内容

注意:

DelayedMemoFetch是个内置保护方法

在程序里是不能直接调用

--

Visual FoxPro 9 C/S方面极富人性化的增强

自从VFP 8 开始,在C/S方面提供了一个CursorAdapter 类, CursorAdapter 是一个基于松散耦合思想设计的对象化的 Cursor 处理模型。对 CursorAdapter 类很多人对其褒贬不一,特别是一些老的Foxer认为做C/S系统用SPT就足够了,何必再增加一个类呢?但我可以这么说,从VFP9 开始,几个CursorAdapter新增加的功能,相信足以使那些纯使用SPT 的Foxer 心动不已了。

下面我先谈谈VFP9 在 CursorAdapter 部分的几个增加和增强。

1. 属性值可以超过255 个字符

用过CursorAdapter 类的人都知道,VFP8 时其几个属性 SelectCmd、CursorSchema、UpdateNameList、UpdatableFieldList的长度不能超过255个字符,这在VFP8时让人感觉是一件非常滑稽的事情,当后台表的字段数一多,连使用它自身生成器生成的字符串都要报错,不能保存,这点造成CursorAdapter使用起来极为不便,也是全球Foxer要求解决的呼声最多的地方,现在这个问题在VFP9 中终于得到了彻底解决。

2. 生成器生成的CursorSchema 不再是按照字母次序来排列了

当我们设计表单上控件时,只要在表单数据环境里放入CursorAdapter,设置 CursorAdapter 的CursorSchema 属性就会可视化的出现一个Cursor, 此时只要拖动相应字段到表单,即可完成一个个控件的设计,这也是CursorAdapter的优点之一,VFP8 时利用生成器生成的CursorSchema 是按照字母次序排列的,这点造成设计时非常的不方便,大家习惯的是自己设计表时的字段次序,现在VFP9 在这方面也做了非常人性化的修改,现在我们可以完全非常舒服的利用其本身的生成器来生成 CursorSchema 供我们设计表单使用。

3. NoData 和 UseCursorSchema 属性

VFP8 时当把CursorAdapter 设计时放到表单的数据环境里,使用CursorFill()里的这两个参数极为不便,现在好了,把这两个属性单独列了出来。

4. TimeStamp 时间戳字段

VFP8 的CursorAdapter 虽然 WhereType 可以等于 4 ,可是其实时间戳字段真正在更新时却过滤掉了,根本不起任何作用。现在VFP9 的CursorAdapter 增加了 TimestampFieldList属性,如果你的后台表里有时间戳的话,只要设置一下这个属性,然后设置WhereType = 4即可。

5. RecordRefresh()

VFP8时CursorAdapter只能用 CursorRefresh() 来刷新前台,可很多时候,我们可能只需要刷新其中一条或者几条记录的数据,可CursorRefresh(),如果前台记录有 1000 条,也要全部重新读一遍,读取完毕以后,记录指针却始终定位在第一条记录,这样既巨大的浪费了网络资源,同时很多情况下还要花费很大的精力重新定位记录指针。

现在 VFP9 增加了这个极富人性化的方法-----RecordRefresh(),能做到任意刷新此Cursor里的任意一条或者连续几条记录,而且当前记录指针保持不变,看到这里相信做过C/S程序的朋友们是不是有一种跃跃欲试的感觉?这个可以期盼已久的功能啊。

RecordRefresh()里有2个参数,RecordRefresh(nRecords,nRecordOffset)

1) nRecords 表示要刷新几条记录

2) nRecordOffset记录偏移量,指是当前记录开始加几条记录

例子1,比如当前记录号是第5条,我要刷新第7、8两条记录,

oCa.RecordRefresh(2,-2)

例子2, 只刷新当前记录,

oCa.RecordRefresh(1)

6. CursorAdapter 的 Auto-Refresh

VFP9提供了记录的Auto-Refresh,其作用、功能、效果和前面介绍的RecordRefresh() 基本相似,有异曲同功之妙用。

让我们来看看具体是怎么使用的吧:

InsertCmdRefreshFieldList、InsertCmdRefreshKeyFieldList、InsertCmdRefreshCmd

这三个新增的属性是针对新增记录时使用,一般我们只需要设置InsertCmdRefreshFieldList、InsertCmdRefreshKeyFieldList即可,从字面已经非常好理解需要设置的内容,InsertCmdRefreshKeyFieldList可以和CursorAdapter的KeyFieldList相同。

UpdateCmdRefreshFieldList、UpdateCmdRefreshKeyFieldList、UpdateCmdRefreshCmd

这三个新增的属性是针对修改记录时使用的,一般我们也只需设置UpdateCmdRefreshFieldList和UpdateCmdRefreshKeyFieldList即

InsertCmdRefreshKeyFieldList完全可以和CursorAdapter的KeyFieldList相同。 可。

让我们设置好这些属性以后看看效果吧,当TableUpdate()提交后台成功以后,记录就自动刷新了,而且当前的记录指针保持不变,这难道不正是我们想要的吗?

请注意,RecordRefresh()和Auto-Refresh 的区别,虽然RecordRefresh() 也能刷新多条指定的记录,可只能是连续的几条记录,而Auto-Refresh却只刷新已修改过的记录。RecordRefresh()刷新的记录可以自己来指定,可Auto-Refresh 刷新的记录却是 CursorAdapter 来控制的。

7. DelayedMemoFetch()

VFP8 的CursorAdapter 里有一个属性:FetchMemo,当设置FetchMemo = .F. 时,本表里的所有Memo 字段都不读取到前台,这样来大大提高了读取数据时的效率,特别是当Memo

字段里内容多的时候,可是当我们需要Memo字段里的内容时怎么办呢?这点是我们一直以来不管用远程视图、SPT还是用CursorAdapter做 C/S 程序时的痛苦矛盾之处,现在我们终于在VFP9的CursorAdapter 里找到了完美的解决办法。

先用文字来说明一下 VFP9 的CursorAdapter 的解决方法,当 CursorFill() 时,所有Memo字段的内容全部为空,以提高读取记录时的效率,但当光标移动到这条记录的这个字段时,自动从后台读取这条记录的当前Memo字段的内容到前台,填充进CursorAdapter里,以我实际操作下来的感觉,几乎根本感觉不到这个读取过程,而数据确确实实读到了前台。 整个设置过程如下:

1)oCa.FetchMemo = .F.

2)oCa.FetchMemoDataSourceType = oCa.DataSourceType

3)oCa.FetchMemoDataSource = oCa.DataSource

4)oCa.FetchMemoCmdList 这个是最关键的,也是最麻烦的:

oCA.FetchMemoCmdList= "f1 <SELECT f1 FROM testCAMemoFetch WHERE f0=?EVALUATE(this.RefreshAlias +\'.f0\')>, f2 <SELECT f2 FROM testCAMemoFetch WHERE f0=?EVALUATE(this.RefreshAlias +\'.f0\')>"

f1,f2这里是Memo字段名简称

f0一般是关键字段名

this.RefreshAlias可以是this.Alias

我翻译一下,就应该比较好理解了,意思如下:” Memo字段名 <select Memo字段名 From 后台表名 where 关键字段名=?前台的Alias名.关键字段内容>,?..”

只要设置好了以上属性,当前台记录移动到Memo字段时 CursorAdapter 会自动调用DelayedMemoFetch(),来读取Memo字段内容。

注意:DelayedMemoFetch是个内置保护方法,在程序里不能直接调用。

RecordRefrsh()、Auto-Refresh和DelayedMemoFetch() 此三项功能是 SPT 无法做到的,合理使用好此三项功能,能极大的提高整个 C/S 系统的效率,降低网络和服务器开销。但使用RecordRefrsh()和Auto-Refresh功能时有点需要特别注意:大家读到这里应该可以看出,其实此三项功能,都是依靠关键字来定位记录的,可当我们用自增量型字段做关键字时,当新增记录时,其值是更新成功以后才能得到,所以当在前台使用RecordRefrsh()和Auto-Refresh时会因无法定位记录而要出错或得不到正确结果。

以上7点是我认为是 VFP9 CursorAdapter 类最具人性化和效率化的方面的功能增强,下面再说说其他几个C/S 方面的功能增强。

1. RecordsFetched 和 FetchIsComplete

以前我们读取大批量记录的时候,如果想要做一个人性化的进度条,是一件非常不容易的事情,一般只能采取异步方式,先读取记录总数,然后用一个循环,

lnResult = SQLEXEC(lnHandle,“SELECT * FROM ?. WHERE ?”,“Temp”)

DO WHILE lnResult = 0

liResult = CURSORGETPROP("FetchSize")

此处写入进度条代码

ENDDO

这样做,效果是出来了,可是也有缺陷,异步其实变成了同步。现在 VFP9 在CursorGetProp() 里增加了两个参数,RecordsFetch 和 FetchIsComplete,意思和使用方法如下:

RecordsFetched 返回读取远程表过程中目前所传回来的记录数目

例如:lnResult = CURSORGETPROP("RecordsFetched")

FetchIsComplete 表示读取过程是否已经完成

如果已完成 = .T.

例如:llResult = CURSORGETPROP("FetchIsComplete")

有了这两个属性,要做一个进度条就轻而易举了,而且能实现异步功能不丧失的效果。 RecordsFetch 和 FetchIsComplete应该还有其他用处,留待我们一起来慢慢挖掘吧。

2. SQLIDLEDISCONNECT() 这是我认为 VFP9 中极其有意义的 C/S 功能增强。

尤其是对CursorAdapter,当然对SPT和远程视图也同样适用。

SQLIDLEDISCONNECT() 从字面上理解是暂时中断连接。刚开始,我始终未能理解其意思,可当亲手做了实验以后,就不得不惊叹其功能之强大了。

以前在VFP8下我曾仔细做过 CursorAdapter 的断线重连的测试,得出结论,CursorAdapter断线重连以后,当前数据可以向后台更新,但已经无法CursorRefresh()了,只能重新CursorFill()以后才行,但重新CursorFill()以后,前台的Cursor 等于是重新生成了,这对前台如果是用GRID来绑定 Cursor 时尤为不便。

现在终于盼到了----- SQLIDLEDISCONNECT(),当CursorFill()、

CursorRefresh()或者RecordRefresh()以后 SQLIDLEDISCONNECT(lnHandle),此时检查服务器,确实此句柄已经不存在了,和服务器 完全脱离了关系,为了保险起见,把网线拔了,过一段时间再插上,再对CursoraAdapter 进行数据更新,提交后台,然后在前台执行CursorRefresh()或者RecordRefresh(),这个时候检查服务器,连接句柄自动建立成功了,而且数据确实更新成功并重新刷新。

再用SPT 做了测试,同样得到了完美的结果。

综上所述,一旦执行了SQLIDLEDISCONNECT(),这个句柄就处于休眠状态,此时完全和服务器脱离了关系,一旦发生前台向后台请求任何的任务,此时 VFP 将无需任何条件、无需任何人工干预的自动唤醒此连接,且句柄号不变。

此项功能在用户数较多或者网络环境较差的情况下尤其有用,特别是在降低服务器的资源消耗方面有着非常大的作用。

以上是我在探索 VFP9 的 C/S 新功能过程中总结的几点心得,从以上几点不难看出微软的VFP 开发小组在 C/S 人性化使用方面所做的努力,其实在VFP9里所有新增或者增强的功能里处处都能体会到这点。由于时间关系,先拿出这些来和大家共享,下笔匆匆,可能其中有不少不够深入或者认识错误之处,请读此篇的狐友谅解指正,谨以此文抛砖引玉,希望更多的狐友一起加入到探索VFP9 新功能的行列中来。

________________________________________

VFP9的CursorAdapter的行级刷新和Memo字段级刷新,使得CursorAdapter从VFP9开始又迈进了大大的一步

.

--

Visual FoxPro 8.0的CursorAdapter类及其在远程数据访问中的意义

摘要: 本文从 Visual FoxPro 应用程序的观点深入剖析Visual FoxPro 8.0中新增的CursorAdapter类及其在远程数据访问中的意义。CursorAdapter对各种远程数据源提供了一种统一的面向对象的访问接口,开发人员借此可以轻松实现基于Native(本地数据)、ODBC、

CA专题81_ca1981

ADO、XML的数据访问。

关键字:CursorAdapter 远程数据访问 ADO 视图 Cursor COM

1、引言

就在“Visual FoxPro已过时,并即将被淘汰??”的一片喧嚣声中,Microsoft于今年6月正式发布了Visual FoxPro 8.0 。据称,这是自Visual FoxPro 3.0发布以来最精彩的一个版本。新增众多如:结构化异常处理、事件绑定、数据环境子类、XML Web services 、自动递增字段、控件延迟绑定、WindowsXP风格支持等等令人目不暇接的功能,着实让全球Foxer们兴奋不已,然而其中最值得令人称道的当数CursorAdapter类,笔者以为这是Visual FoxPro 8.0最抢眼的一个亮点。

长期以来,Visual FoxPro因为其先天的弱点如:表的脆弱性、安全性、数据库的容量、以及通用性等等,一直成为人们攻击的目标。因而越来越多的 VFP 程序员开始抛弃DBF表,转而采用如SQL Server、Oracle 等一些大型数据库来存储数据,而将VFP作为C/S结构中的前端开发工具或者作为基于COM的三层结构应用程序的中间层开发工具。然而,传统的方式通常是使用远程视图或SQL Pass Through 然后经过 ODBC 来访问远程数据。随着新的基于组件技术的数据访问规范OLE DB和扩展标记语言XML的出现,对VFP开发人员来说无疑产生了极大的吸引力。然而,在以前各版本的Visual FoxPro中,这些新技术都无法得以很好地利用。Microsoft当然也看到了这一点,于是在刚刚发布的Visaul FoxPro 8.0中,一个全新的为用户提供统一的数据访问接口、被称为CursorAdapter的基类,展现在了全球Foxer们面前。借助 CursorAdapter,在 Visual FoxPro 8.0 中访问远程数据要比过去的任何一个版本都简单的多:

&#8226; ODBC、ADO、XML的使用变得非常容易,即时你不熟悉这些技术。

&#8226; 不管你选择了哪种远程数据源机制,它都提供一种统一的访问接口。

&#8226; 从一种数据访问机制转换到另一种数据访问机制变得非常轻松。

2、CursorAdapter的设计理念

要彻底理解CursorAdapter,必须先弄清Microsoft设计CursorAdapter的真正意图。

众所周知,基于OLE DB的ADO数据访问技术,正日渐成为Windows平台主流的数据存取解决方案,VC、VB、Delphi这些当今流行的开发工具,都无一不支持ADO技术。在需要编写组件的场合, ADO更是一种理想的选择。然而很久以来,在Visual FoxPro中,我们似乎看不到ADO的影子。是不是Visual FoxPro不支持ADO呢?当然不是。ADO实际上是一组实现数据存取的COM对象,Visual FoxPro支持COM,当然也支持ADO。

然而,在Visual FoxPro 8.0出现之前,几乎很少看到有VFP程序员采用ADO来访问如SQL Server、Oracle 等一些大型数据库,其原因何在?原来,在Visual FoxPro中,ADO产生的RecordSet对象,不能像VFP中的表或视图(本地或远程)那样实现与控件的绑定,也不能作为一个整体的数据对象来处理,必须使用循环语句来逐条处理RecordSet中的记录,因而也就无法发挥Visual FoxPro强大的数据处理功能。

现在,CursorAdapter的出现彻底改变了这一切。可以这么说,CursorAdapter为我们提供了一种全新的远程数据访问解决方案,无论你是使用本地表(Native)、ODBC、ADO还是XML,CursorAdapter均提供了一个统一的数据访问接口,让你轻松实现远程数据的存取。

在详细剖析CursorAdapter的运作机制之前,让我们先来看一下传统的Visual FoxPro中的数据处理模型。

Visual FoxPro中,一切数据处理其实都是围绕着游标(Cursor)进行的。如:DBC中的视图就是一个Cursor、表单数据环境中的表也是Cursor,Select-SQL产生的查询结果还是Cursor(只读)。可以说,Visual FoxPro灵活、强大的数据处理功能无一不归功于Cursor的参与。 然而,对于ADO所产生的RecordSet,Visual FoxPro却显得英雄无用武之地。所以,面对

ADO,Visual FoxPro急于解决的问题是:要么推倒原有的整个VFP数据处理架构,重建一个对象化的Cursor以实现与对象化的RecordSet相容;要么通过某种方式,将ADO的RecordSet转化为VFP能处理的Cursor,而原有的以Cursor为中心的数据处理架构保持不变。最终结果是,Mirosoft选择了后者,事实上这也是一种最合理的方式。

再来看一下Visual FoxPro 8.0中的CursorAdapter类。CursorAdapter就是一个为实现上述思想而设计的对象化的数据处理模型。无论是本地数据(DBF),还是基于ADO、ODBC、XML的远程数据,都可以通过这个CursorAdapter产生一个能为VFP处理的Cursor,而对该Cursor的所有处理结果,又可以根据需要决定是否返回给数据源。需要注意的是:CursorAdapter本身并不是Cursor,而只是一个用于产生Cursor的对象化的数据处理模型。

与VFP中其它非可视化类一样,CursorAdapter也不提供可视化界面,即它不是以控件的形式出现在VFP的表单控件工具箱中,但这并不妨碍我们对它的使用。CursorAdapter提供了许多属性、事件与方法。如常用的属性有:Alias、DataSourceType、Datasource、SelectCmd、UpdatableFieldList、UpdateNameList等;方法有:CursorFill、CursorRefresh、AutoOpen等;事件有:AfterUpdate、BeforeUpdate、AfterCursorFill、BeforeCursorFill、AfterCursorRefresh等。在此不一一列举,读者可以查阅Visual FoxPro 8.0中相关的帮助文件。通过这些属性、事件、方法,开发人员可以自由方便地操纵CursorAdapter对象,实现对远程数据的存取。

3、CursorAdapter实例演示

接下来,让我们通过两个示例来看一下CursorAdapter如何实现对远程数据的存取以及它与直接使用ADO组件来处理远程数据有何不同。

[示例一]:直接使用ADO访问SQL-Server:

connstr="Persist Security Info=False;User ID=sa;Initial Catalog=cjgl;Data Source=HXM" oConnection = CreateObject("adodb.connection") &&建立连接对象

With oConnection

.Provider = "SQLOLEDB.1"

.ConnectionString = connstr

.Open

EndWith

oRecordSet = CreateObject("adodb.recordset") &&建立记录集对象

oRecordSet.Open("Select * From xs",oConnection)

Do While !oRecordSet.Eof &&通过循环语句列举姓名字段 ? oRecordSet.fields("xm").value

oRecordset.MoveNext

EndDo

[示例二]:使用ADO+ CursorAdapter访问SQL-Server:

connstr="Persist Security Info=False;User ID=sa;Initial Catalog=cjgl;Data Source=HXM" oConnection = CreateObject("adodb.connection") &&建立连接对象

With oConnection

.Provider = "SQLOLEDB.1"

.ConnectionString = connstr

.Open

EndWith

loCursor = Createobject(\'CursorAdapter\') &&建立CursorAdapter对象

With loCursor

.Alias = \'student\'

.DataSourceType = \'ADO\' &&指定数据源类型

.Datasource = Createobject(\'ADODB.RecordSet\')

.SelectCmd="select * FROM xs" &&指定用于产生Cursor的Select-SQL语句

.DataSource.ActiveConnection = oConnection

ENDWITH

loCursor.CursorFill() &&将后台数据重载到前台并产生出一个Cursor Browse

[注]:以上代码用到了一个非常简单的SQL-Server数据库XSCJ,其中包含一张XS表。 从上面代码可以看到,CursorAdapter本质上是基于ADO的RecordSet,通过RecordSet产生出一个可更新的Cursor(游标),使得我们可以用所有VFP传统语句来处理该Cursor,如可以用Browse来浏览该Cursor。

读者可能会说,CursorAdapter的作用无非就是将RecordSet转换为一个适合VFP处理的Cursor,用户完全可以自己写个类,将此转换代码封装其中,不照样实现CursorAdapter的功能吗?

实际上,事情并非完全如此。CursorAdapter除了产生出一个Cursor外,更重要的在于引入了相关的对象事件模型,如:BeforeInsert、AfterInsert、BeforeUpdate、AfterUpdate等, 从而使得编程人员可以利用这些事件,来控制对Cursor的各种操作。而这一点,正是普通意义上的视图所无法实现的。DBC中的视图虽然也可更新,但它不具有对象事件模型,因而开发人员无法去控制它,一旦执行TableUpadte,数据便立即更新,没有商量的余地。 下面代码演示了Update-SQL语句如何触发CursorAdapter 的AfterUpdate事件: Connstr="Persist Security Info=False;User ID=sa;Initial Catalog=cjgl;Data Source=HXM" oConnection = Createobject("adodb.connection")

With oConnection

.Provider = "SQLOLEDB.1"

.ConnectionString = Connstr

.Open

Endwith

loCursor =Createobject("myCurAdp") &&创建CursorAdapter对象 With loCursor

.Alias = \'student\'

.DataSourceType = \'ADO\'

.Datasource =Createobject(\'ADODB.RecordSet\')

.DataSource.CursorLocation = 3 && adUseClient

.DataSource.LockType = 3 && adLockOptimistic

.SelectCmd="select * FROM xs"

.UpdatableFieldList="xh,xm,xb,zydh,xidh"

.UpdateNameList="XH xs.XH, XM xs.XM, XB xs.XB, ZYDH xs.ZYDH, XIDH xs.XIDH" .KeyFieldList="xh"

.AllowUpdate=.T.

.SendUpdates=.T.

.Datasource.ActiveConnection = oConnection

Endwith

IF loCursor.CursorFill()

Update student Set xm="王一平" WHERE xb="男" &&触发AfterUpdate事件

ENDIF

**定义一个基于CursorAdapter的子类

Define Class myCurAdp As CursorAdapter

Procedure AfterUpdate &&定义AfterUpdate事件

Lparameters FldState,lForce,nUpdateType,cUpdateInsertCmd,cDeleteCmd,cResult

Wait Window "触发AfterUpdate事件!"

Endproc

Enddefine

当执行Update-SQL命令时,就会触发myCurAdp类的AfterUpdate事件,用户可以在此事件中做一些自己想做的事。

4、数据环境中的CursorAdapter

如果你对PRG文件中的OOP编程不是很熟悉,那也不要紧,Visual FoxPro 8.0重新设计了表单的数据环境,在新的数据环境中同样提供了CursorAdapter类,你甚至可以用可视化的方式来设置CursorAdapter的各项属性,设置完毕,就会在数据环境设计器中产生一个Cursor,然后像处理本地表一样处理这个Cursor,例如,你可以将其拖放到表单上实现与表单控件的绑定、用TableUpdate()来更新数据源。

不过,从Microsoft对Visual FoxPro的产品定位策略来看,Microsoft更倾向于将Visual FoxPro作为一个多层结构的中间层开发工具,并且将其融合到.NET框架中来。而多层结构的中间层实际就是一些COM组件。一方面,COM组件的编写必须基于OOP,并且在VFP中,支持私有工作期的Session类只能在PRG文件中定义;另一方面,进程内的COM组件不允许带有界面元素,因此从组件开发的角度来看,熟悉PRG中的OOP编程更显重要,这也是一个真正的程序设计高手所必须具备的基本功。

5、结束语

曾经风靡一时的FoxPro,在.NET、XML、Web Service大行其道的今天,并没有完全被淘汰,至少目前或者今后几年内不会。在保持快速、灵活、强大的数据处理能力的同时,新的Visaul FoxPro 7.0、8.0对.NET、XML、Web Service等新技术的强有力的支持,使其依然充满生机和活力。据今年6月在美国加利福尼亚举行的“Visual FoxPro DevCon 2003“会议透露,Visaul FoxPro的下一个版本已在开发中,代码为Europa(木卫二),其Beta版预计将于明年下半年发布。Microsoft承诺,对Visaul FoxPro 8.0的技术支持将延续到2010年。

本文标题:81道变态逻辑题-日本81道变态逻辑题,答出越多越变态31-40
本文地址: http://www.61k.com/1130963.html

61阅读| 精彩专题| 最新文章| 热门文章| 苏ICP备13036349号-1